summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-02-04 09:36:56 -0800
committerPaul Phillips <paulp@improving.org>2012-02-04 09:40:00 -0800
commit57f19c440a69714abf248ef7bbc5e94b96d89f2f (patch)
tree657c7d12463edbbc33725a10d28c50ff22556abd /src
parent269a9ef9b25cc90a8d05cff166f6461220b715b8 (diff)
downloadscala-57f19c440a69714abf248ef7bbc5e94b96d89f2f.tar.gz
scala-57f19c440a69714abf248ef7bbc5e94b96d89f2f.tar.bz2
scala-57f19c440a69714abf248ef7bbc5e94b96d89f2f.zip
ant and diff friendlier msil-disabling.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/MSILPlatform.scala123
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala4699
-rw-r--r--src/compiler/scala/tools/nsc/io/MsilFile.scala35
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala263
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala1691
-rw-r--r--src/compiler/scala/tools/nsc/util/MsilClassPath.scala323
6 files changed, 3570 insertions, 3564 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
index a86528d492..d5a02f9242 100644
--- a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala
@@ -1,65 +1,66 @@
-// /* NSC -- new Scala compiler
-// * Copyright 2005-2011 LAMP/EPFL
-// * @author Paul Phillips
-// */
-//
-// package scala.tools.nsc
-// package backend
-//
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package backend
+
// import ch.epfl.lamp.compiler.{ msil => msillib }
// import util.{ ClassPath, MsilClassPath }
// import msil.GenMSIL
// import io.{ AbstractFile, MsilFile }
-//
-// trait MSILPlatform extends Platform {
-// import global._
-// import definitions.{ ComparatorClass, BoxedNumberClass, getMember }
-//
-// type BinaryRepr = MsilFile
-//
-// if (settings.verbose.value)
-// inform("[AssemRefs = " + settings.assemrefs.value + "]")
-//
-// // phaseName = "msil"
-// object genMSIL extends {
-// val global: MSILPlatform.this.global.type = MSILPlatform.this.global
-// val runsAfter = List[String]("dce")
-// val runsRightAfter = None
-// } with GenMSIL
-//
-// lazy val classPath = MsilClassPath.fromSettings(settings)
-// def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]])
-// // See discussion in JavaPlatForm for why we need a cast here.
-//
-// def platformPhases = List(
-// genMSIL // generate .msil files
-// )
-//
-// lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_)
-// def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass
-//
-// def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin)
-//
-// /**
-// * Tells whether a class should be loaded and entered into the package
-// * scope. On .NET, this method returns `false` for all synthetic classes
-// * (anonymous classes, implementation classes, module classes), their
-// * symtab is encoded in the pickle of another class.
-// */
-// def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = {
-// if (cls.binary.isDefined) {
-// val typ = cls.binary.get.msilType
-// if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) {
-// val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)
-// assert(attrs.length == 1, attrs.length)
-// val a = attrs(0).asInstanceOf[msillib.Attribute]
-// // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle.
-// // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic.
-// a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR
-// } else true // always load non-scala types
-// } else true // always load source
-// }
-//
-// def needCompile(bin: MsilFile, src: AbstractFile) =
-// false // always use compiled file on .net
-// }
+
+trait MSILPlatform /*extends Platform {
+ import global._
+ import definitions.{ ComparatorClass, BoxedNumberClass, getMember }
+
+ type BinaryRepr = MsilFile
+
+ if (settings.verbose.value)
+ inform("[AssemRefs = " + settings.assemrefs.value + "]")
+
+ // phaseName = "msil"
+ object genMSIL extends {
+ val global: MSILPlatform.this.global.type = MSILPlatform.this.global
+ val runsAfter = List[String]("dce")
+ val runsRightAfter = None
+ } with GenMSIL
+
+ lazy val classPath = MsilClassPath.fromSettings(settings)
+ def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]])
+ // See discussion in JavaPlatForm for why we need a cast here.
+
+ def platformPhases = List(
+ genMSIL // generate .msil files
+ )
+
+ lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_)
+ def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass
+
+ def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin)
+
+ /**
+ * Tells whether a class should be loaded and entered into the package
+ * scope. On .NET, this method returns `false` for all synthetic classes
+ * (anonymous classes, implementation classes, module classes), their
+ * symtab is encoded in the pickle of another class.
+ */
+ def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = {
+ if (cls.binary.isDefined) {
+ val typ = cls.binary.get.msilType
+ if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) {
+ val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)
+ assert(attrs.length == 1, attrs.length)
+ val a = attrs(0).asInstanceOf[msillib.Attribute]
+ // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle.
+ // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic.
+ a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR
+ } else true // always load non-scala types
+ } else true // always load source
+ }
+
+ def needCompile(bin: MsilFile, src: AbstractFile) =
+ false // always use compiled file on .net
+}
+*/ \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index ab07f2e4fc..aba537f3bd 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -1,12 +1,12 @@
-// /* NSC -- new scala compiler
-// * Copyright 2005-2011 LAMP/EPFL
-// * @author Nikolay Mihaylov
-// */
-//
-//
-// package scala.tools.nsc
-// package backend.msil
-//
+/* NSC -- new scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Nikolay Mihaylov
+ */
+
+
+package scala.tools.nsc
+package backend.msil
+
// import java.io.{File, IOException}
// import java.nio.{ByteBuffer, ByteOrder}
// import scala.collection.{ mutable, immutable }
@@ -15,2343 +15,2344 @@
// import ch.epfl.lamp.compiler.msil.{Type => MsilType, _}
// import ch.epfl.lamp.compiler.msil.emit._
// import ch.epfl.lamp.compiler.msil.util.PECustomMod
-//
-// abstract class GenMSIL extends SubComponent {
-// import global._
-// import loaders.clrTypes
-// import clrTypes.{types, constructors, methods, fields}
-// import icodes._
-// import icodes.opcodes._
-//
-// val x = loaders
-//
-// /** Create a new phase */
-// override def newPhase(p: Phase) = new MsilPhase(p)
-//
-// val phaseName = "msil"
-// /** MSIL code generation phase
-// */
-// class MsilPhase(prev: Phase) extends GlobalPhase(prev) {
-// def name = phaseName
-// override def newFlags = phaseNewFlags
-//
-// override def erasedTypes = true
-//
-// override def run() {
-// if (settings.debug.value) inform("[running phase " + name + " on icode]")
-//
-// val codeGenerator = new BytecodeGenerator
-//
-// //classes is ICodes.classes, a HashMap[Symbol, IClass]
-// classes.values foreach codeGenerator.findEntryPoint
-// if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead
-// val entryclass = opt.showClass.get.toString
-// warning("Couldn't find entry class " + entryclass)
-// }
-//
-// codeGenerator.initAssembly
-//
-// val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output
-// classesSorted foreach codeGenerator.createTypeBuilder
-// classesSorted foreach codeGenerator.createClassMembers
-//
-// try {
-// classesSorted foreach codeGenerator.genClass
-// } finally {
-// codeGenerator.writeAssembly
-// }
-// }
-//
-// override def apply(unit: CompilationUnit) {
-// abort("MSIL works on icode classes, not on compilation units!")
-// }
-// }
-//
-// /**
-// * MSIL bytecode generator.
-// *
-// */
-// class BytecodeGenerator {
-//
-// val MODULE_INSTANCE_NAME = "MODULE$"
-//
-// import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT,
-// CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT,
-// DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING,
-// STRING_ARRAY => MSTRING_ARRAY,
-// SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR,
-// SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR}
-//
-// val EXCEPTION = clrTypes.getType("System.Exception")
-// val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE)
-//
-// val ICLONEABLE = clrTypes.getType("System.ICloneable")
-// val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes)
-//
-// val MMONITOR = clrTypes.getType("System.Threading.Monitor")
-// val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT))
-// val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT))
-//
-// val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder")
-// val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes)
-// val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString",
-// MsilType.EmptyTypes)
-//
-// val TYPE_FROM_HANDLE =
-// clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle")))
-//
-// val INT_PTR = clrTypes.getType("System.IntPtr")
-//
-// val JOBJECT = definitions.ObjectClass
-// val JSTRING = definitions.StringClass
-//
-// val SystemConvert = clrTypes.getType("System.Convert")
-//
-// val objParam = Array(MOBJECT)
-//
-// val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox
-// val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam)
-// val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam)
-// val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam)
-// val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam)
-// val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam)
-// val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam)
-// val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam)
-//
-// //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT")
-// val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT)
-//
-// // Scala attributes
-// // symtab.Definitions -> object (singleton..)
-// val SerializableAttr = definitions.SerializableAttr.tpe
-// val CloneableAttr = definitions.CloneableAttr.tpe
-// val TransientAtt = definitions.TransientAttr.tpe
-// // remoting: the architectures are too different, no mapping (no portable code
-// // possible)
-//
-// // java instance methods that are mapped to static methods in .net
-// // these will need to be called with OpCodes.Call (not Callvirt)
-// val dynToStatMapped = mutable.HashSet[Symbol]()
-//
-// initMappings()
-//
-// /** Create the mappings between java and .net classes and methods */
-// private def initMappings() {
-// mapType(definitions.AnyClass, MOBJECT)
-// mapType(definitions.AnyRefClass, MOBJECT)
-// //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$"))
-// //mapType(definitions.NothingClass, clrTypes.getType("scala.All$"))
-// // FIXME: for some reason the upper two lines map to null
-// mapType(definitions.NullClass, EXCEPTION)
-// mapType(definitions.NothingClass, EXCEPTION)
-//
-// mapType(definitions.BooleanClass, MBOOL)
-// mapType(definitions.ByteClass, MBYTE)
-// mapType(definitions.ShortClass, MSHORT)
-// mapType(definitions.CharClass, MCHAR)
-// mapType(definitions.IntClass, MINT)
-// mapType(definitions.LongClass, MLONG)
-// mapType(definitions.FloatClass, MFLOAT)
-// mapType(definitions.DoubleClass, MDOUBLE)
-// }
-//
-// var clasz: IClass = _
-// var method: IMethod = _
-//
-// var massembly: AssemblyBuilder = _
-// var mmodule: ModuleBuilder = _
-// var mcode: ILGenerator = _
-//
-// var assemName: String = _
-// var firstSourceName = ""
-// var outDir: File = _
-// var srcPath: File = _
-// var moduleName: String = _
-//
-// def initAssembly() {
-//
-// assemName = settings.assemname.value
-//
-// if (assemName == "") {
-// if (entryPoint != null) {
-// assemName = msilName(entryPoint.enclClass)
-// // remove the $ at the end (from module-name)
-// assemName = assemName.substring(0, assemName.length() - 1)
-// } else {
-// // assuming filename of first source file
-// assert(firstSourceName.endsWith(".scala"), firstSourceName)
-// assemName = firstSourceName.substring(0, firstSourceName.length() - 6)
-// }
-// } else {
-// if (assemName.endsWith(".msil"))
-// assemName = assemName.substring(0, assemName.length()-5)
-// if (assemName.endsWith(".il"))
-// assemName = assemName.substring(0, assemName.length()-3)
-// val f: File = new File(assemName)
-// assemName = f.getName()
-// }
-//
-// outDir = new File(settings.outdir.value)
-//
-// srcPath = new File(settings.sourcedir.value)
-//
-// val assemblyName = new AssemblyName()
-// assemblyName.Name = assemName
-// massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName)
-//
-// moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe")
-// // filename here: .dll or .exe (in both parameters), second: give absolute-path
-// mmodule = massembly.DefineDynamicModule(moduleName,
-// new File(outDir, moduleName).getAbsolutePath())
-// assert (mmodule != null)
-// }
-//
-//
-// /**
-// * Form of the custom Attribute parameter (Ecma-335.pdf)
-// * - p. 163 for CustomAttrib Form,
-// * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!)
-// * !! least significant byte first if values longer than one byte !!
-// *
-// * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00
-// * 2: FixedArgs (directly the data, get number and types from related constructor)
-// * 2.1: length of the array (unsigned int32, 4 bytes, least significant first)
-// * 2.2: the byte array data
-// * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000)
-// */
-// def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) {
-// def addMarker() {
-// val markerSymtab = new Array[Byte](4)
-// markerSymtab(0) = 1.toByte
-// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab)
-// }
-//
-// // both conditions are needed (why exactly..?)
-// if (tBuilder.Name.endsWith("$") || sym.isModuleClass) {
-// addMarker()
-// } else {
-// currentRun.symData.get(sym) match {
-// case Some(pickle) =>
-// var size = pickle.writeIndex
-// val symtab = new Array[Byte](size + 8)
-// symtab(0) = 1.toByte
-// for (i <- 2 until 6) {
-// symtab(i) = (size & 0xff).toByte
-// size = size >> 8
-// }
-// java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex)
-//
-// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab)
-//
-// currentRun.symData -= sym
-// currentRun.symData -= sym.companionSymbol
-//
-// case _ =>
-// addMarker()
-// }
-// }
-// }
-//
-// /**
-// * Mutates `member` adding CLR attributes (if any) based on sym.annotations.
-// * Please notice that CLR custom modifiers are a different beast (see customModifiers below)
-// * and thus shouldn't be added by this method.
-// */
-// def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) {
-// val attributes = annotations.map(_.atp.typeSymbol).collect {
-// case definitions.TransientAttr => null // TODO this is just an example
-// }
-// return // TODO: implement at some point
-// }
-//
-// /**
-// * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier.
-// * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo)
-// * and thus that marker (be it optional or required) becomes part of the signature of that location.
-// * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method).
-// */
-// def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = {
-// annotations.map(_.atp.typeSymbol).collect {
-// case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker)
-// } toArray
-// }
-//
-//
-//
-// /*
-// debuglog("creating annotations: " + annotations + " for member : " + member)
-// for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ;
-// if annot.isConstant)
-// //!typ.typeSymbol.isJavaDefined
-// {
-// // assert(consts.length <= 1,
-// // "too many constant arguments for annotations; "+consts.toString())
-//
-// // Problem / TODO having the symbol of the annotations type would be nicer
-// // (i hope that type.typeSymbol is the same as the one in types2create)
-// // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder)
-// // when this is solved, types2create will be the same as icodes.classes, thus superfluous
-// val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder]
-// // val annType: MsilType = getType(typ.typeSymbol)
-//
-// // Problem / TODO: i have no idea which constructor is used. This
-// // information should be available in AnnotationInfo.
-// annType.CreateType() // else, GetConstructors can't be used
-// val constr: ConstructorInfo = annType.GetConstructors()(0)
-// // prevent a second call of CreateType, only needed because there's no
-// // other way than GetConstructors()(0) to get the constructor, if there's
-// // no constructor symbol available.
-//
-// val args: Array[Byte] =
-// getAttributeArgs(
-// annArgs map (_.constant.get),
-// (for((n,v) <- nvPairs) yield (n, v.constant.get)))
-// member.SetCustomAttribute(constr, args)
-// }
-// } */
-//
-// /* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = {
-// val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough!
-// buf.order(ByteOrder.LITTLE_ENDIAN)
-// buf.putShort(1.toShort) // signature
-//
-// def emitSerString(str: String) = {
-// // this is wrong, it has to be the length of the UTF-8 byte array, which
-// // may be longer (see clr-book on page 302)
-// // val length: Int = str.length
-// val strBytes: Array[Byte] = try {
-// str.getBytes("UTF-8")
-// } catch {
-// case _: Error => abort("could not get byte-array for string: " + str)
-// }
-// val length: Int = strBytes.length //this length is stored big-endian
-// if (length < 128)
-// buf.put(length.toByte)
-// else if (length < (1<<14)) {
-// buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0'
-// buf.put((length | 0xff).toByte)
-// } else if (length < (1 << 29)) {
-// buf.put(((length >> 24) | 0xc0).toByte)
-// buf.put(((length >> 16) & 0xff).toByte)
-// buf.put(((length >> 8) & 0xff).toByte)
-// buf.put(((length ) & 0xff).toByte)
-// } else
-// abort("string too long for attribute parameter: " + length)
-// buf.put(strBytes)
-// }
-//
-// def emitConst(const: Constant): Unit = const.tag match {
-// case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte)
-// case ByteTag => buf.put(const.byteValue)
-// case ShortTag => buf.putShort(const.shortValue)
-// case CharTag => buf.putChar(const.charValue)
-// case IntTag => buf.putInt(const.intValue)
-// case LongTag => buf.putLong(const.longValue)
-// case FloatTag => buf.putFloat(const.floatValue)
-// case DoubleTag => buf.putDouble(const.doubleValue)
-// case StringTag =>
-// val str: String = const.stringValue
-// if (str == null) {
-// buf.put(0xff.toByte)
-// } else {
-// emitSerString(str)
-// }
-// case ArrayTag =>
-// val arr: Array[Constant] = const.arrayValue
-// if (arr == null) {
-// buf.putInt(0xffffffff)
-// } else {
-// buf.putInt(arr.length)
-// arr.foreach(emitConst)
-// }
-//
-// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ???
-//
-// case _ => abort("could not handle attribute argument: " + const)
-// }
-//
-// consts foreach emitConst
-// buf.putShort(nvPairs.length.toShort)
-// def emitNamedArg(nvPair: (Name, Constant)) {
-// // the named argument is a property of the attribute (it can't be a field, since
-// // all fields in scala are private)
-// buf.put(0x54.toByte)
-//
-// def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151
-// case BooleanTag => buf.put(0x02.toByte)
-// case ByteTag => buf.put(0x05.toByte)
-// case ShortTag => buf.put(0x06.toByte)
-// case CharTag => buf.put(0x07.toByte)
-// case IntTag => buf.put(0x08.toByte)
-// case LongTag => buf.put(0x0a.toByte)
-// case FloatTag => buf.put(0x0c.toByte)
-// case DoubleTag => buf.put(0x0d.toByte)
-// case StringTag => buf.put(0x0e.toByte)
-//
-// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ???
-//
-// // ArrayTag falls in here
-// case _ => abort("could not handle attribute argument: " + c)
-// }
-//
-// val cnst: Constant = nvPair._2
-// if (cnst.tag == ArrayTag) {
-// buf.put(0x1d.toByte)
-// emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0
-// } else if (cnst.tag == EnumTag) {
-// buf.put(0x55.toByte)
-// // TODO: put a SerString (don't know what exactly, names of the enums somehow..)
-// } else {
-// buf.put(0x51.toByte)
-// emitType(cnst)
-// }
-//
-// emitSerString(nvPair._1.toString)
-// emitConst(nvPair._2)
-// }
-//
-// val length = buf.position()
-// buf.array().slice(0, length)
-// } */
-//
-// def writeAssembly() {
-// if (entryPoint != null) {
-// assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass)
-// val mainMethod = methods(entryPoint)
-// val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY)
-// val globalMain = mmodule.DefineGlobalMethod(
-// "Main", MethodAttributes.Public | MethodAttributes.Static,
-// MVOID, stringArrayTypes)
-// globalMain.DefineParameter(0, ParameterAttributes.None, "args")
-// massembly.SetEntryPoint(globalMain)
-// val code = globalMain.GetILGenerator()
-// val moduleField = getModuleInstanceField(entryPoint.enclClass)
-// code.Emit(OpCodes.Ldsfld, moduleField)
-// code.Emit(OpCodes.Ldarg_0)
-// code.Emit(OpCodes.Callvirt, mainMethod)
-// code.Emit(OpCodes.Ret)
-// }
-// createTypes()
-// var outDirName: String = null
-// try {
-// if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar
-// outDirName = outDir.getPath()
-// massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */
-// } else {
-// outDirName = srcPath.getPath()
-// massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */
-// }
-// } catch {
-// case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage())
-// }
-// }
-//
-// private def createTypes() {
-// for (sym <- classes.keys) {
-// val iclass = classes(sym)
-// val tBuilder = types(sym).asInstanceOf[TypeBuilder]
-//
-// debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString)
-//
-// tBuilder.CreateType()
-// tBuilder.setSourceFilepath(iclass.cunit.source.file.path)
-// }
-// }
-//
-// private[GenMSIL] def ilasmFileName(iclass: IClass) : String = {
-// // method.sourceFile contains just the filename
-// iclass.cunit.source.file.toString.replace("\\", "\\\\")
-// }
-//
-// private[GenMSIL] def genClass(iclass: IClass) {
-// val sym = iclass.symbol
-// debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags))
-// clasz = iclass
-//
-// val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
-// if (isCloneable(sym)) {
-// // FIXME: why there's no nme.clone_ ?
-// // "Clone": if the code is non-portable, "Clone" is defined, not "clone"
-// // TODO: improve condition (should override AnyRef.clone)
-// if (iclass.methods.forall(m => {
-// !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") &&
-// m.symbol.tpe.paramTypes.length != 0)
-// })) {
-// debuglog("auto-generating cloneable method for " + sym)
-// val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual |
-// MethodAttributes.HideBySig).toShort
-// val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT,
-// MsilType.EmptyTypes)
-// val clCode = cloneMethod.GetILGenerator()
-// clCode.Emit(OpCodes.Ldarg_0)
-// clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE)
-// clCode.Emit(OpCodes.Ret)
-// }
-// }
-//
-// val line = sym.pos.line
-// tBuilder.setPosition(line, ilasmFileName(iclass))
-//
-// if (isTopLevelModule(sym)) {
-// if (sym.companionClass == NoSymbol)
-// generateMirrorClass(sym)
-// else
-// log("No mirror class for module with linked class: " +
-// sym.fullName)
-// }
-//
-// addSymtabAttribute(sym, tBuilder)
-// addAttributes(tBuilder, sym.annotations)
-//
-// if (iclass.symbol != definitions.ArrayClass)
-// iclass.methods foreach genMethod
-//
-// } //genClass
-//
-//
-// private def genMethod(m: IMethod) {
-// debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +
-// " owner: " + m.symbol.owner)
-// method = m
-// localBuilders.clear
-// computeLocalVarsIndex(m)
-//
-// if (m.symbol.isClassConstructor) {
-// mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator()
-// } else {
-// val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder]
-// if (!mBuilder.IsAbstract())
-// try {
-// mcode = mBuilder.GetILGenerator()
-// } catch {
-// case e: Exception =>
-// java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol)
-// java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner)
-// java.lang.System.out.println("mBuilder = " + mBuilder)
-// java.lang.System.out.println("mBuilder.DeclaringType = " +
-// TypeAttributes.toString(mBuilder.DeclaringType.Attributes) +
-// "::" + mBuilder.DeclaringType)
-// throw e
-// }
-// else
-// mcode = null
-// }
-//
-// if (mcode != null) {
-// for (local <- m.locals ; if !(m.params contains local)) {
-// debuglog("add local var: " + local + ", of kind " + local.kind)
-// val t: MsilType = msilType(local.kind)
-// val localBuilder = mcode.DeclareLocal(t)
-// localBuilder.SetLocalSymInfo(msilName(local.sym))
-// localBuilders(local) = localBuilder
-// }
-// genCode(m)
-// }
-//
-// }
-//
-// /** Special linearizer for methods with at least one exception handler. This
-// * linearizer brings all basic blocks in the right order so that nested
-// * try-catch and try-finally blocks can be emitted.
-// */
-// val msilLinearizer = new MSILLinearizer()
-//
-// val labels = mutable.HashMap[BasicBlock, Label]()
-//
-// /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize.
-// * this scheme relies on the fact that the entry block is emitted first. */
-// var dbFilenameSeen = false
-//
-// def genCode(m: IMethod) {
-//
-// def makeLabels(blocks: List[BasicBlock]) = {
-// debuglog("Making labels for: " + method)
-// for (bb <- blocks) labels(bb) = mcode.DefineLabel()
-// }
-//
-// labels.clear
-//
-// var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m)
-// else linearizer.linearize(m)
-//
-// if (!m.exh.isEmpty)
-// linearization = computeExceptionMaps(linearization, m)
-//
-// makeLabels(linearization)
-//
-// // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label)
-// // debug val blocksInL = linearization.sortBy(bb => bb.label)
-// // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP)
-// // debug if(!MButNotL.isEmpty) { }
-//
-// dbFilenameSeen = false
-// genBlocks(linearization)
-//
-// // RETURN inside exception blocks are replaced by Leave. The target of the
-// // leave is a `Ret` outside any exception block (generated here).
-// if (handlerReturnMethod == m) {
-// mcode.MarkLabel(handlerReturnLabel)
-// if (handlerReturnKind != UNIT)
-// mcode.Emit(OpCodes.Ldloc, handlerReturnLocal)
-// mcode.Emit(OpCodes.Ret)
-// }
-//
-// beginExBlock.clear()
-// beginCatchBlock.clear()
-// endExBlock.clear()
-// endFinallyLabels.clear()
-// }
-//
-// def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) {
-// blocks match {
-// case Nil => ()
-// case x :: Nil => genBlock(x, prev = previous, next = null)
-// case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x)
-// }
-// }
-//
-// // the try blocks starting at a certain BasicBlock
-// val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]()
-//
-// // the catch blocks starting / endling at a certain BasicBlock
-// val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]()
-// val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]()
-//
-// /** When emitting the code (genBlock), the number of currently active try / catch
-// * blocks. When seeing a `RETURN` inside a try / catch, we need to
-// * - store the result in a local (if it's not UNIT)
-// * - emit `Leave handlerReturnLabel` instead of the Return
-// * - emit code at the end: load the local and return its value
-// */
-// var currentHandlers = new mutable.Stack[ExceptionHandler]
-// // The IMethod the Local/Label/Kind below belong to
-// var handlerReturnMethod: IMethod = _
-// // Stores the result when returning inside an exception block
-// var handlerReturnLocal: LocalBuilder = _
-// // Label for a return instruction outside any exception block
-// var handlerReturnLabel: Label = _
-// // The result kind.
-// var handlerReturnKind: TypeKind = _
-// def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = {
-// if (handlerReturnMethod != method) {
-// handlerReturnMethod = method
-// if (kind != UNIT) {
-// handlerReturnLocal = mcode.DeclareLocal(msilType(kind))
-// handlerReturnLocal.SetLocalSymInfo("$handlerReturn")
-// }
-// handlerReturnLabel = mcode.DefineLabel()
-// handlerReturnKind = kind
-// }
-// (handlerReturnLocal, handlerReturnLabel)
-// }
-//
-// /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the
-// * Leave target has to be inside the finally (and it has to be the `endfinally` instruction).
-// * So for every finalizer, we have a label which marks the place of the `endfinally`,
-// * nested try/catch blocks will leave there.
-// */
-// val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]()
-//
-// /** Computes which blocks are the beginning / end of a try or catch block */
-// private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = {
-// val visitedBlocks = new mutable.HashSet[BasicBlock]()
-//
-// // handlers which have not been introduced so far
-// var openHandlers = m.exh
-//
-//
-// /** Example
-// * try {
-// * try {
-// * // *1*
-// * } catch {
-// * case h1 =>
-// * }
-// * } catch {
-// * case h2 =>
-// * case h3 =>
-// * try {
-// *
-// * } catch {
-// * case h4 => // *2*
-// * case h5 =>
-// * }
-// * }
-// */
-//
-// // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple
-// // catch statements). Example *1*: Stack(List(h2, h3), List(h1))
-// val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]()
-//
-// // Stack of nested catch blocks. The head of the list is the current catch block. The
-// // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5))
-// val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]()
-//
-// for (b <- blocks) {
-//
-// // are we past the current catch blocks?
-// def endHandlers(): List[ExceptionHandler] = {
-// var res: List[ExceptionHandler] = Nil
-// if (!currentCatchHandlers.isEmpty) {
-// val handler = currentCatchHandlers.top.head
-// if (!handler.blocks.contains(b)) {
-// // all blocks of the handler are either visited, or not part of the linearization (i.e. dead)
-// assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)),
-// "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+
-// b.fullString +"\nwhile in catch-part of\n"+ handler)
-//
-// val rest = currentCatchHandlers.pop.tail
-// if (rest.isEmpty) {
-// // all catch blocks of that exception handler are covered
-// res = handler :: endHandlers()
-// } else {
-// // there are more catch blocks for that try (handlers covering the same)
-// currentCatchHandlers.push(rest)
-// beginCatchBlock(b) = rest.head
-// }
-// }
-// }
-// res
-// }
-// val end = endHandlers()
-// if (!end.isEmpty) endExBlock(b) = end
-//
-// // are we past the current try block?
-// if (!currentTryHandlers.isEmpty) {
-// val handler = currentTryHandlers.top.head
-// if (!handler.covers(b)) {
-// // all of the covered blocks are visited, or not part of the linearization
-// assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)),
-// "Bad linearization of basic blocks inside try. Found non-covered block\n"+
-// b.fullString +"\nwhile in try-part of\n"+ handler)
-//
-// assert(handler.startBlock == b,
-// "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+
-// b.fullString +"\n"+ handler)
-//
-// val handlers = currentTryHandlers.pop
-// currentCatchHandlers.push(handlers)
-// beginCatchBlock(b) = handler
-// }
-// }
-//
-// // are there try blocks starting at b?
-// val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b))
-// openHandlers = stillOpen
-//
-// val newHandlersBySize = newHandlers.groupBy(_.covered.size)
-// // big handlers first, smaller ones are nested inside the try of the big one
-// // (checked by the assertions below)
-// val sizes = newHandlersBySize.keys.toList.sortWith(_ > _)
-//
-// val beginHandlers = new mutable.ListBuffer[ExceptionHandler]
-// for (s <- sizes) {
-// val sHandlers = newHandlersBySize(s)
-// for (h <- sHandlers) {
-// assert(h.covered == sHandlers.head.covered,
-// "bad nesting of exception handlers. same size, but not covering same blocks\n"+
-// h +"\n"+ sHandlers.head)
-// assert(h.resultKind == sHandlers.head.resultKind,
-// "bad nesting of exception handlers. same size, but the same resultKind\n"+
-// h +"\n"+ sHandlers.head)
-// }
-// for (bigger <- beginHandlers; h <- sHandlers) {
-// assert(h.covered.subsetOf(bigger.covered),
-// "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+
-// h +"\n"+ bigger)
-// assert(h.blocks.toSet.subsetOf(bigger.covered),
-// "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+
-// h +"\n"+ bigger)
-// }
-// beginHandlers += sHandlers.head
-// currentTryHandlers.push(sHandlers)
-// }
-// beginExBlock(b) = beginHandlers.toList
-// visitedBlocks += b
-// }
-//
-// // if there handlers left (i.e. handlers covering nothing, or a
-// // non-existent (dead) block), remove their catch-blocks.
-// val liveBlocks = if (openHandlers.isEmpty) blocks else {
-// blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b)))
-// }
-//
-// /** There might be open handlers, but no more blocks. happens when try/catch end
-// * with `throw` or `return`
-// * def foo() { try { .. throw } catch { _ => .. throw } }
-// *
-// * In this case we need some code after the catch block for the auto-generated
-// * `leave` instruction. So we're adding a (dead) `throw new Exception`.
-// */
-// val rest = currentCatchHandlers.map(handlers => {
-// assert(handlers.length == 1, handlers)
-// handlers.head
-// }).toList
-//
-// if (rest.isEmpty) {
-// liveBlocks
-// } else {
-// val b = m.code.newBlock
-// b.emit(Seq(
-// NEW(REFERENCE(definitions.ThrowableClass)),
-// DUP(REFERENCE(definitions.ObjectClass)),
-// CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)),
-// THROW(definitions.ThrowableClass)
-// ))
-// b.close
-// endExBlock(b) = rest
-// liveBlocks ::: List(b)
-// }
-// }
-//
-// /**
-// * @param block the BasicBlock to emit code for
-// * @param next the following BasicBlock, `null` if `block` is the last one
-// */
-// def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) {
-//
-// def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) {
-// debuglog(msg + " for " + local)
-// val isArg = local.arg
-// val i = local.index
-// if (isArg)
-// loadArg(mcode, loadAddr)(i)
-// else
-// loadLocal(i, local, mcode, loadAddr)
-// }
-//
-// def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) {
-// debuglog(msg + " with owner: " + field.owner +
-// " flags: " + Flags.flagsToString(field.owner.flags))
-// var fieldInfo = fields.get(field) match {
-// case Some(fInfo) => fInfo
-// case None =>
-// val fInfo = getType(field.owner).GetField(msilName(field))
-// fields(field) = fInfo
-// fInfo
-// }
-// if (fieldInfo.IsVolatile) {
-// mcode.Emit(OpCodes.Volatile)
-// }
-// if (!fieldInfo.IsLiteral) {
-// if (loadAddr) {
-// mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo)
-// } else {
-// mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo)
-// }
-// } else {
-// assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...")
-// // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack.
-// /* We perform `field inlining' as required by CLR.
-// * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available
-// * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type
-// * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case,
-// * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */
-// val value = fieldInfo.getValue()
-// if (value == null) {
-// mcode.Emit(OpCodes.Ldnull)
-// } else {
-// val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType
-// else fieldInfo.FieldType
-// if (typ == clrTypes.STRING) {
-// mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String])
-// } else if (typ == clrTypes.BOOLEAN) {
-// mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1
-// else OpCodes.Ldc_I4_0)
-// } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) {
-// loadI4(value.asInstanceOf[Byte], mcode)
-// } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) {
-// loadI4(value.asInstanceOf[Int], mcode)
-// } else if (typ == clrTypes.CHAR) {
-// loadI4(value.asInstanceOf[Char], mcode)
-// } else if (typ == clrTypes.INT || typ == clrTypes.UINT) {
-// loadI4(value.asInstanceOf[Int], mcode)
-// } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) {
-// mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long])
-// } else if (typ == clrTypes.FLOAT) {
-// mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float])
-// } else if (typ == clrTypes.DOUBLE) {
-// mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double])
-// } else {
-// /* TODO one more case is described in Partition II, 16.2: bytearray(...) */
-// abort("Unknown type for static literal field: " + fieldInfo)
-// }
-// }
-// }
-// }
-//
-// /** Creating objects works differently on .NET. On the JVM
-// * - NEW(type) => reference on Stack
-// * - DUP, load arguments, CALL_METHOD(constructor)
-// *
-// * On .NET, the NEW and DUP are ignored, but we emit a special method call
-// * - load arguments
-// * - NewObj(constructor) => reference on stack
-// *
-// * This variable tells whether the previous instruction was a NEW,
-// * we expect a DUP which is not emitted. */
-// var previousWasNEW = false
-//
-// var lastLineNr: Int = 0
-// var lastPos: Position = NoPosition
-//
-//
-// // EndExceptionBlock must happen before MarkLabel because it adds the
-// // Leave instruction. Otherwise, labels(block) points to the Leave
-// // (inside the catch) instead of the instruction afterwards.
-// for (handlers <- endExBlock.get(block); exh <- handlers) {
-// currentHandlers.pop()
-// for (l <- endFinallyLabels.get(exh))
-// mcode.MarkLabel(l)
-// mcode.EndExceptionBlock()
-// }
-//
-// mcode.MarkLabel(labels(block))
-// debuglog("Generating code for block: " + block)
-//
-// for (handler <- beginCatchBlock.get(block)) {
-// if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) {
-// currentHandlers.pop()
-// currentHandlers.push(handler)
-// }
-// if (handler.cls == NoSymbol) {
-// // `finally` blocks are represented the same as `catch`, but with no catch-type
-// mcode.BeginFinallyBlock()
-// } else {
-// val t = getType(handler.cls)
-// mcode.BeginCatchBlock(t)
-// }
-// }
-// for (handlers <- beginExBlock.get(block); exh <- handlers) {
-// currentHandlers.push(exh)
-// mcode.BeginExceptionBlock()
-// }
-//
-// for (instr <- block) {
-// try {
-// val currentLineNr = instr.pos.line
-// val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr);
-// if(!skip || !dbFilenameSeen) {
-// val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)};
-// if(instr.pos.isRange) {
-// val startLine = instr.pos.focusStart.line
-// val endLine = instr.pos.focusEnd.line
-// val startCol = instr.pos.focusStart.column
-// val endCol = instr.pos.focusEnd.column
-// mcode.setPosition(startLine, endLine, startCol, endCol, fileName)
-// } else {
-// mcode.setPosition(instr.pos.line, fileName)
-// }
-// lastLineNr = currentLineNr
-// lastPos = instr.pos
-// }
-// } catch { case _: UnsupportedOperationException => () }
-//
-// if (previousWasNEW)
-// assert(instr.isInstanceOf[DUP], block)
-//
-// instr match {
-// case THIS(clasz) =>
-// mcode.Emit(OpCodes.Ldarg_0)
-//
-// case CONSTANT(const) =>
-// const.tag match {
-// case UnitTag => ()
-// case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1
-// else OpCodes.Ldc_I4_0)
-// case ByteTag => loadI4(const.byteValue, mcode)
-// case ShortTag => loadI4(const.shortValue, mcode)
-// case CharTag => loadI4(const.charValue, mcode)
-// case IntTag => loadI4(const.intValue, mcode)
-// case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue)
-// case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue)
-// case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue)
-// case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue)
-// case NullTag => mcode.Emit(OpCodes.Ldnull)
-// case ClassTag =>
-// mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue))
-// mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE)
-// case _ => abort("Unknown constant value: " + const)
-// }
-//
-// case LOAD_ARRAY_ITEM(kind) =>
-// (kind: @unchecked) match {
-// case BOOL => mcode.Emit(OpCodes.Ldelem_I1)
-// case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte
-// case SHORT => mcode.Emit(OpCodes.Ldelem_I2)
-// case CHAR => mcode.Emit(OpCodes.Ldelem_U2)
-// case INT => mcode.Emit(OpCodes.Ldelem_I4)
-// case LONG => mcode.Emit(OpCodes.Ldelem_I8)
-// case FLOAT => mcode.Emit(OpCodes.Ldelem_R4)
-// case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8)
-// case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref)
-// case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref)
-//
-// // case UNIT is not possible: an Array[Unit] will be an
-// // Array[scala.runtime.BoxedUnit] (-> case REFERENCE)
-// }
-//
-// case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false)
-//
-// case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true)
-//
-// case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false)
-//
-// case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true)
-//
-// case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind))
-//
-// case CIL_NEWOBJ(msym) =>
-// assert(msym.isClassConstructor)
-// val constructorInfo: ConstructorInfo = getConstructor(msym)
-// mcode.Emit(OpCodes.Newobj, constructorInfo)
-//
-// case LOAD_MODULE(module) =>
-// debuglog("Generating LOAD_MODULE for: " + showsym(module))
-// mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module))
-//
-// case STORE_ARRAY_ITEM(kind) =>
-// (kind: @unchecked) match {
-// case BOOL => mcode.Emit(OpCodes.Stelem_I1)
-// case BYTE => mcode.Emit(OpCodes.Stelem_I1)
-// case SHORT => mcode.Emit(OpCodes.Stelem_I2)
-// case CHAR => mcode.Emit(OpCodes.Stelem_I2)
-// case INT => mcode.Emit(OpCodes.Stelem_I4)
-// case LONG => mcode.Emit(OpCodes.Stelem_I8)
-// case FLOAT => mcode.Emit(OpCodes.Stelem_R4)
-// case DOUBLE => mcode.Emit(OpCodes.Stelem_R8)
-// case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref)
-// case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method)
-//
-// // case UNIT not possible (see comment at LOAD_ARRAY_ITEM)
-// }
-//
-// case STORE_LOCAL(local) =>
-// val isArg = local.arg
-// val i = local.index
-// debuglog("store_local for " + local + ", index " + i)
-//
-// // there are some locals defined by the compiler that
-// // are isArg and are need to be stored.
-// if (isArg) {
-// if (i >= -128 && i <= 127)
-// mcode.Emit(OpCodes.Starg_S, i)
-// else
-// mcode.Emit(OpCodes.Starg, i)
-// } else {
-// i match {
-// case 0 => mcode.Emit(OpCodes.Stloc_0)
-// case 1 => mcode.Emit(OpCodes.Stloc_1)
-// case 2 => mcode.Emit(OpCodes.Stloc_2)
-// case 3 => mcode.Emit(OpCodes.Stloc_3)
-// case _ =>
-// if (i >= -128 && i <= 127)
-// mcode.Emit(OpCodes.Stloc_S, localBuilders(local))
-// else
-// mcode.Emit(OpCodes.Stloc, localBuilders(local))
-// }
-// }
-//
-// case STORE_THIS(_) =>
-// // this only works for impl classes because the self parameter comes first
-// // in the method signature. If that changes, this code has to be revisited.
-// mcode.Emit(OpCodes.Starg_S, 0)
-//
-// case STORE_FIELD(field, isStatic) =>
-// val fieldInfo = fields.get(field) match {
-// case Some(fInfo) => fInfo
-// case None =>
-// val fInfo = getType(field.owner).GetField(msilName(field))
-// fields(field) = fInfo
-// fInfo
-// }
-// mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo)
-//
-// case CALL_PRIMITIVE(primitive) =>
-// genPrimitive(primitive, instr.pos)
-//
-// case CALL_METHOD(msym, style) =>
-// if (msym.isClassConstructor) {
-// val constructorInfo: ConstructorInfo = getConstructor(msym)
-// (style: @unchecked) match {
-// // normal constructor calls are Static..
-// case Static(_) =>
-// if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner)
-// // we're generating a constructor (method: IMethod is a constructor), and we're
-// // calling another constructor of the same class.
-//
-// // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } }
-// // instead, we should instruct the CALL_METHOD with additional information, know whether it's
-// // an instance creation constructor call or not.
-// mcode.Emit(OpCodes.Call, constructorInfo)
-// else
-// mcode.Emit(OpCodes.Newobj, constructorInfo)
-// case SuperCall(_) =>
-// mcode.Emit(OpCodes.Call, constructorInfo)
-// if (isStaticModule(clasz.symbol) &&
-// notInitializedModules.contains(clasz.symbol) &&
-// method.symbol.isClassConstructor)
-// {
-// notInitializedModules -= clasz.symbol
-// mcode.Emit(OpCodes.Ldarg_0)
-// mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol))
-// }
-// }
-//
-// } else {
-//
-// var doEmit = true
-// getTypeOpt(msym.owner) match {
-// case Some(typ) if (typ.IsEnum) => {
-// def negBool() = {
-// mcode.Emit(OpCodes.Ldc_I4_0)
-// mcode.Emit(OpCodes.Ceq)
-// }
-// doEmit = false
-// val name = msym.name
-// if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) }
-// else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool }
-// else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) }
-// else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool }
-// else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) }
-// else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool }
-// else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) }
-// else if (name eq nme.AND) { mcode.Emit(OpCodes.And) }
-// else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) }
-// else
-// doEmit = true
-// }
-// case _ => ()
-// }
-//
-// // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType
-// val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) {
-// msym.tpe match {
-// case MethodType(params, resultType)
-// if (params.length == 1 && msym.name == nme.view_) =>
-// val paramType = params(0).tpe
-// val isDel = definitions.isCorrespondingDelegate(resultType, paramType)
-// (isDel, paramType, resultType)
-// case _ => (false, null, null)
-// }
-// }
-// if (doEmit && isDelegateView) {
-// doEmit = false
-// createDelegateCaller(paramType, resType)
-// }
-//
-// if (doEmit &&
-// (msym.name == nme.PLUS || msym.name == nme.MINUS)
-// && clrTypes.isDelegateType(msilType(msym.owner.tpe)))
-// {
-// doEmit = false
-// val methodInfo: MethodInfo = getMethod(msym)
-// // call it as a static method, even if the compiler (symbol) thinks it's virtual
-// mcode.Emit(OpCodes.Call, methodInfo)
-// mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe))
-// }
-//
-// if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) {
-// doEmit = false
-// val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym)
-// val delegateType: Type = msym.tpe match {
-// case MethodType(_, retType) => retType
-// case _ => abort("not a method type: " + msym.tpe)
-// }
-// val methodInfo: MethodInfo = getMethod(methodSym)
-// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR))
-// if (methodSym.isStatic) {
-// mcode.Emit(OpCodes.Ldftn, methodInfo)
-// } else {
-// mcode.Emit(OpCodes.Dup)
-// mcode.Emit(OpCodes.Ldvirtftn, methodInfo)
-// }
-// mcode.Emit(OpCodes.Newobj, delegCtor)
-// }
-//
-// if (doEmit) {
-// val methodInfo: MethodInfo = getMethod(msym)
-// (style: @unchecked) match {
-// case SuperCall(_) =>
-// mcode.Emit(OpCodes.Call, methodInfo)
-// case Dynamic =>
-// // methodInfo.DeclaringType is null for global methods
-// val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType)
-// val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual)
-// if (dynToStatMapped(msym)) {
-// mcode.Emit(OpCodes.Call, methodInfo)
-// } else if (isValuetypeVirtualMethod) {
-// mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType)
-// mcode.Emit(OpCodes.Callvirt, methodInfo)
-// } else if (isValuetypeMethod) {
-// // otherwise error "Callvirt on a value type method" ensues
-// mcode.Emit(OpCodes.Call, methodInfo)
-// } else {
-// mcode.Emit(OpCodes.Callvirt, methodInfo)
-// }
-// case Static(_) =>
-// if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) {
-// mcode.Emit(OpCodes.Callvirt, methodInfo)
-// } else mcode.Emit(OpCodes.Call, methodInfo)
-// }
-// }
-// }
-//
-// case BOX(boxType) =>
-// emitBox(mcode, boxType)
-//
-// case UNBOX(boxType) =>
-// emitUnbox(mcode, boxType)
-//
-// case CIL_UNBOX(boxType) =>
-// mcode.Emit(OpCodes.Unbox, msilType(boxType))
-//
-// case CIL_INITOBJ(valueType) =>
-// mcode.Emit(OpCodes.Initobj, msilType(valueType))
-//
-// case NEW(REFERENCE(cls)) =>
-// // the next instruction must be a DUP, see comment on `var previousWasNEW`
-// previousWasNEW = true
-//
-// // works also for arrays and reference-types
-// case CREATE_ARRAY(elem, dims) =>
-// // TODO: handle multi dimensional arrays
-// assert(dims == 1, "Can't handle multi dimensional arrays")
-// mcode.Emit(OpCodes.Newarr, msilType(elem))
-//
-// // works for arrays and reference-types
-// case IS_INSTANCE(tpe) =>
-// mcode.Emit(OpCodes.Isinst, msilType(tpe))
-// mcode.Emit(OpCodes.Ldnull)
-// mcode.Emit(OpCodes.Ceq)
-// mcode.Emit(OpCodes.Ldc_I4_0)
-// mcode.Emit(OpCodes.Ceq)
-//
-// // works for arrays and reference-types
-// // part from the scala reference: "S <: T does not imply
-// // Array[S] <: Array[T] in Scala. However, it is possible
-// // to cast an array of S to an array of T if such a cast
-// // is permitted in the host environment."
-// case CHECK_CAST(tpknd) =>
-// val tMSIL = msilType(tpknd)
-// mcode.Emit(OpCodes.Castclass, tMSIL)
-//
-// // no SWITCH is generated when there's
-// // - a default case ("case _ => ...") in the matching expr
-// // - OR is used ("case 1 | 2 => ...")
-// case SWITCH(tags, branches) =>
-// // tags is List[List[Int]]; a list of integers for every label.
-// // if the int on stack is 4, and 4 is in the second list => jump
-// // to second label
-// // branches is List[BasicBlock]
-// // the labels to jump to (the last one is the default one)
-//
-// val switchLocal = mcode.DeclareLocal(MINT)
-// // several switch variables will appear with the same name in the
-// // assembly code, but this makes no truble
-// switchLocal.SetLocalSymInfo("$switch_var")
-//
-// mcode.Emit(OpCodes.Stloc, switchLocal)
-// var i = 0
-// for (l <- tags) {
-// var targetLabel = labels(branches(i))
-// for (i <- l) {
-// mcode.Emit(OpCodes.Ldloc, switchLocal)
-// loadI4(i, mcode)
-// mcode.Emit(OpCodes.Beq, targetLabel)
-// }
-// i += 1
-// }
-// val defaultTarget = labels(branches(i))
-// if (next != branches(i))
-// mcode.Emit(OpCodes.Br, defaultTarget)
-//
-// case JUMP(whereto) =>
-// val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto)
-// if (leaveHandler) {
-// if (leaveFinally) {
-// if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get)
-// else mcode.Emit(OpCodes.Endfinally)
-// } else
-// mcode.Emit(OpCodes.Leave, labels(whereto))
-// } else if (next != whereto)
-// mcode.Emit(OpCodes.Br, labels(whereto))
-//
-// case CJUMP(success, failure, cond, kind) =>
-// // cond is TestOp (see Primitives.scala), and can take
-// // values EQ, NE, LT, GE LE, GT
-// // kind is TypeKind
-// val isFloat = kind == FLOAT || kind == DOUBLE
-// val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat)
-// emitCondBr(block, cond, success, failure, next, emit)
-//
-// case CZJUMP(success, failure, cond, kind) =>
-// emitCondBr(block, cond, success, failure, next, emitBrBool(_, _))
-//
-// case RETURN(kind) =>
-// if (currentHandlers.isEmpty)
-// mcode.Emit(OpCodes.Ret)
-// else {
-// val (local, label) = returnFromHandler(kind)
-// if (kind != UNIT)
-// mcode.Emit(OpCodes.Stloc, local)
-// mcode.Emit(OpCodes.Leave, label)
-// }
-//
-// case THROW(_) =>
-// mcode.Emit(OpCodes.Throw)
-//
-// case DROP(kind) =>
-// mcode.Emit(OpCodes.Pop)
-//
-// case DUP(kind) =>
-// // see comment on `var previousWasNEW`
-// if (!previousWasNEW)
-// mcode.Emit(OpCodes.Dup)
-// else
-// previousWasNEW = false
-//
-// case MONITOR_ENTER() =>
-// mcode.Emit(OpCodes.Call, MMONITOR_ENTER)
-//
-// case MONITOR_EXIT() =>
-// mcode.Emit(OpCodes.Call, MMONITOR_EXIT)
-//
-// case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) =>
-// ()
-// }
-//
-// } // end for (instr <- b) { .. }
-// } // end genBlock
-//
-// def genPrimitive(primitive: Primitive, pos: Position) {
-// primitive match {
-// case Negation(kind) =>
-// kind match {
-// // CHECK: is ist possible to get this for BOOL? in this case, verify.
-// case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE =>
-// mcode.Emit(OpCodes.Neg)
-//
-// case _ => abort("Impossible to negate a " + kind)
-// }
-//
-// case Arithmetic(op, kind) =>
-// op match {
-// case ADD => mcode.Emit(OpCodes.Add)
-// case SUB => mcode.Emit(OpCodes.Sub)
-// case MUL => mcode.Emit(OpCodes.Mul)
-// case DIV => mcode.Emit(OpCodes.Div)
-// case REM => mcode.Emit(OpCodes.Rem)
-// case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement)
-// case _ => abort("Unknown arithmetic primitive " + primitive )
-// }
-//
-// case Logical(op, kind) => op match {
-// case AND => mcode.Emit(OpCodes.And)
-// case OR => mcode.Emit(OpCodes.Or)
-// case XOR => mcode.Emit(OpCodes.Xor)
-// }
-//
-// case Shift(op, kind) => op match {
-// case LSL => mcode.Emit(OpCodes.Shl)
-// case ASR => mcode.Emit(OpCodes.Shr)
-// case LSR => mcode.Emit(OpCodes.Shr_Un)
-// }
-//
-// case Conversion(src, dst) =>
-// debuglog("Converting from: " + src + " to: " + dst)
-//
-// dst match {
-// case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte
-// case SHORT => mcode.Emit(OpCodes.Conv_I2)
-// case CHAR => mcode.Emit(OpCodes.Conv_U2)
-// case INT => mcode.Emit(OpCodes.Conv_I4)
-// case LONG => mcode.Emit(OpCodes.Conv_I8)
-// case FLOAT => mcode.Emit(OpCodes.Conv_R4)
-// case DOUBLE => mcode.Emit(OpCodes.Conv_R8)
-// case _ =>
-// Console.println("Illegal conversion at: " + clasz +
-// " at: " + pos.source + ":" + pos.line)
-// }
-//
-// case ArrayLength(_) =>
-// mcode.Emit(OpCodes.Ldlen)
-//
-// case StartConcat =>
-// mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR)
-//
-//
-// case StringConcat(el) =>
-// val elemType : MsilType = el match {
-// case REFERENCE(_) | ARRAY(_) => MOBJECT
-// case _ => msilType(el)
-// }
-//
-// val argTypes:Array[MsilType] = Array(elemType)
-// val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes )
-// mcode.Emit(OpCodes.Callvirt, stringBuilderAppend)
-//
-// case EndConcat =>
-// mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING)
-//
-// case _ =>
-// abort("Unimplemented primitive " + primitive)
-// }
-// } // end genPrimitive
-//
-//
-// ////////////////////// loading ///////////////////////
-//
-// def loadI4(value: Int, code: ILGenerator): Unit = value match {
-// case -1 => code.Emit(OpCodes.Ldc_I4_M1)
-// case 0 => code.Emit(OpCodes.Ldc_I4_0)
-// case 1 => code.Emit(OpCodes.Ldc_I4_1)
-// case 2 => code.Emit(OpCodes.Ldc_I4_2)
-// case 3 => code.Emit(OpCodes.Ldc_I4_3)
-// case 4 => code.Emit(OpCodes.Ldc_I4_4)
-// case 5 => code.Emit(OpCodes.Ldc_I4_5)
-// case 6 => code.Emit(OpCodes.Ldc_I4_6)
-// case 7 => code.Emit(OpCodes.Ldc_I4_7)
-// case 8 => code.Emit(OpCodes.Ldc_I4_8)
-// case _ =>
-// if (value >= -128 && value <= 127)
-// code.Emit(OpCodes.Ldc_I4_S, value)
-// else
-// code.Emit(OpCodes.Ldc_I4, value)
-// }
-//
-// def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) =
-// if (loadAddr) {
-// if (i >= -128 && i <= 127)
-// code.Emit(OpCodes.Ldarga_S, i)
-// else
-// code.Emit(OpCodes.Ldarga, i)
-// } else {
-// i match {
-// case 0 => code.Emit(OpCodes.Ldarg_0)
-// case 1 => code.Emit(OpCodes.Ldarg_1)
-// case 2 => code.Emit(OpCodes.Ldarg_2)
-// case 3 => code.Emit(OpCodes.Ldarg_3)
-// case _ =>
-// if (i >= -128 && i <= 127)
-// code.Emit(OpCodes.Ldarg_S, i)
-// else
-// code.Emit(OpCodes.Ldarg, i)
-// }
-// }
-//
-// def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) =
-// if (loadAddr) {
-// if (i >= -128 && i <= 127)
-// code.Emit(OpCodes.Ldloca_S, localBuilders(local))
-// else
-// code.Emit(OpCodes.Ldloca, localBuilders(local))
-// } else {
-// i match {
-// case 0 => code.Emit(OpCodes.Ldloc_0)
-// case 1 => code.Emit(OpCodes.Ldloc_1)
-// case 2 => code.Emit(OpCodes.Ldloc_2)
-// case 3 => code.Emit(OpCodes.Ldloc_3)
-// case _ =>
-// if (i >= -128 && i <= 127)
-// code.Emit(OpCodes.Ldloc_S, localBuilders(local))
-// else
-// code.Emit(OpCodes.Ldloc, localBuilders(local))
-// }
-// }
-//
-// ////////////////////// branches ///////////////////////
-//
-// /** Returns a Triple (Boolean, Boolean, Option[Label])
-// * - whether the jump leaves some exception block (try / catch / finally)
-// * - whether it leaves a finally handler (finally block, but not it's try / catch)
-// * - a label where to jump for leaving the finally handler
-// * . None to leave directly using `endfinally`
-// * . Some(label) to emit `leave label` (for try / catch inside a finally handler)
-// */
-// def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) =
-// if (currentHandlers.isEmpty) (false, false, None)
-// else {
-// val h = currentHandlers.head
-// val leaveHead = { h.covers(from) != h.covers(to) ||
-// h.blocks.contains(from) != h.blocks.contains(to) }
-// if (leaveHead) {
-// // we leave the innermost exception block.
-// // find out if we also leave som e `finally` handler
-// currentHandlers.find(e => {
-// e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to)
-// }) match {
-// case Some(finallyHandler) =>
-// if (h == finallyHandler) {
-// // the finally handler is the innermost, so we can emit `endfinally` directly
-// (true, true, None)
-// } else {
-// // we need to `Leave` to the `endfinally` of the next outer finally handler
-// val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel())
-// (true, true, Some(l))
-// }
-// case None =>
-// (true, false, None)
-// }
-// } else (false, false, None)
-// }
-//
-// def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock,
-// next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) {
-// val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success)
-// val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure)
-//
-// if (sLeaveHandler || fLeaveHandler) {
-// val sLabelOpt = if (sLeaveHandler) {
-// val leaveSLabel = mcode.DefineLabel()
-// emitBrFun(cond, leaveSLabel)
-// Some(leaveSLabel)
-// } else {
-// emitBrFun(cond, labels(success))
-// None
-// }
-//
-// if (fLeaveHandler) {
-// if (fLeaveFinally) {
-// if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get)
-// else mcode.Emit(OpCodes.Endfinally)
-// } else
-// mcode.Emit(OpCodes.Leave, labels(failure))
-// } else
-// mcode.Emit(OpCodes.Br, labels(failure))
-//
-// sLabelOpt.map(l => {
-// mcode.MarkLabel(l)
-// if (sLeaveFinally) {
-// if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get)
-// else mcode.Emit(OpCodes.Endfinally)
-// } else
-// mcode.Emit(OpCodes.Leave, labels(success))
-// })
-// } else {
-// if (next == success) {
-// emitBrFun(cond.negate, labels(failure))
-// } else {
-// emitBrFun(cond, labels(success))
-// if (next != failure) {
-// mcode.Emit(OpCodes.Br, labels(failure))
-// }
-// }
-// }
-// }
-//
-// def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) {
-// condition match {
-// case EQ => mcode.Emit(OpCodes.Beq, dest)
-// case NE => mcode.Emit(OpCodes.Bne_Un, dest)
-// case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest)
-// case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest)
-// case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest)
-// case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest)
-// }
-// }
-//
-// def emitBrBool(cond: TestOp, dest: Label) {
-// cond match {
-// // EQ -> Brfalse, NE -> Brtrue; this is because we come from
-// // a CZJUMP. If the value on the stack is 0 (e.g. a boolean
-// // method returned false), and we are in the case EQ, then
-// // we need to emit Brfalse (EQ Zero means false). vice versa
-// case EQ => mcode.Emit(OpCodes.Brfalse, dest)
-// case NE => mcode.Emit(OpCodes.Brtrue, dest)
-// }
-// }
-//
-// ////////////////////// local vars ///////////////////////
-//
-// /**
-// * Compute the indexes of each local variable of the given
-// * method.
-// */
-// def computeLocalVarsIndex(m: IMethod) {
-// var idx = if (m.symbol.isStaticMember) 0 else 1
-//
-// val params = m.params
-// for (l <- params) {
-// debuglog("Index value for parameter " + l + ": " + idx)
-// l.index = idx
-// idx += 1 // sizeOf(l.kind)
-// }
-//
-// val locvars = m.locals filterNot (params contains)
-// idx = 0
-//
-// for (l <- locvars) {
-// debuglog("Index value for local variable " + l + ": " + idx)
-// l.index = idx
-// idx += 1 // sizeOf(l.kind)
-// }
-//
-// }
-//
-// ////////////////////// Utilities ////////////////////////
-//
-// /** Return the a name of this symbol that can be used on the .NET
-// * platform. It removes spaces from names.
-// *
-// * Special handling: scala.All and scala.AllRef are 'erased' to
-// * scala.All$ and scala.AllRef$. This is needed because they are
-// * not real classes, and they mean 'abrupt termination upon evaluation
-// * of that expression' or 'null' respectively. This handling is
-// * done already in GenICode, but here we need to remove references
-// * from method signatures to these types, because such classes can
-// * not exist in the classpath: the type checker will be very confused.
-// */
-// def msilName(sym: Symbol): String = {
-// val suffix = sym.moduleSuffix
-// // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class)
-//
-// if (sym == definitions.NothingClass)
-// return "scala.runtime.Nothing$"
-// else if (sym == definitions.NullClass)
-// return "scala.runtime.Null$"
-//
-// (if (sym.isClass || (sym.isModule && !sym.isMethod)) {
-// if (sym.isNestedClass) sym.simpleName
-// else sym.fullName
-// } else
-// sym.simpleName.toString.trim()) + suffix
-// }
-//
-//
-// ////////////////////// flags ///////////////////////
-//
-// def msilTypeFlags(sym: Symbol): Int = {
-// var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass
-//
-// if(sym.isNestedClass) {
-// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic)
-// } else {
-// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public)
-// }
-// mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0)
-// mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class)
-// mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0)
-//
-// sym.annotations foreach { a => a match {
-// case AnnotationInfo(SerializableAttr, _, _) =>
-// // TODO: add the Serializable TypeAttribute also if the annotation
-// // System.SerializableAttribute is present (.net annotation, not scala)
-// // Best way to do it: compare with
-// // definitions.getClass("System.SerializableAttribute").tpe
-// // when frontend available
-// mf = mf | TypeAttributes.Serializable
-// case _ => ()
-// }}
-//
-// mf
-// // static: not possible (or?)
-// }
-//
-// def msilMethodFlags(sym: Symbol): Short = {
-// var mf: Int = MethodAttributes.HideBySig |
-// (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private
-// else MethodAttributes.Public)
-//
-// if (!sym.isClassConstructor) {
-// if (sym.isStaticMember)
-// mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ...
-// else {
-// mf = mf | MethodAttributes.Virtual
-// if (sym.isFinal && !getType(sym.owner).IsInterface)
-// mf = mf | MethodAttributes.Final
-// if (sym.isDeferred || getType(sym.owner).IsInterface)
-// mf = mf | MethodAttributes.Abstract
-// }
-// }
-//
-// 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
-// }
-//
-// def msilFieldFlags(sym: Symbol): Short = {
-// var mf: Int =
-// if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private
-// else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem
-// else FieldAttributes.Public
-//
-// if (sym hasFlag Flags.FINAL)
-// mf = mf | FieldAttributes.InitOnly
-//
-// if (sym.isStaticMember)
-// mf = mf | FieldAttributes.Static
-//
-// // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net
-// // TODO: add this annotation also if the class has the custom attribute
-// // System.NotSerializedAttribute
-// sym.annotations.foreach( a => a match {
-// case AnnotationInfo(TransientAtt, _, _) =>
-// mf = mf | FieldAttributes.NotSerialized
-// case _ => ()
-// })
-//
-// mf.toShort
-// }
-//
-// ////////////////////// builders, types ///////////////////////
-//
-// var entryPoint: Symbol = _
-//
-// val notInitializedModules = mutable.HashSet[Symbol]()
-//
-// // TODO: create fields also in def createType, and not in genClass,
-// // add a getField method (it only works as it is because fields never
-// // accessed from outside a class)
-//
-// val localBuilders = mutable.HashMap[Local, LocalBuilder]()
-//
-// private[GenMSIL] def findEntryPoint(cls: IClass) {
-//
-// def isEntryPoint(sym: Symbol):Boolean = {
-// if (isStaticModule(sym.owner) && msilName(sym) == "main")
-// if (sym.tpe.paramTypes.length == 1) {
-// toTypeKind(sym.tpe.paramTypes(0)) match {
-// case ARRAY(elem) =>
-// if (elem.toType.typeSymbol == definitions.StringClass) {
-// return true
-// }
-// case _ => ()
-// }
-// }
-// false
-// }
-//
-// if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead
-// val entryclass = opt.showClass.get.toString
-// val cfn = cls.symbol.fullName
-// if(cfn == entryclass) {
-// for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol }
-// if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) }
-// }
-// }
-//
-// if (firstSourceName == "")
-// if (cls.symbol.sourceFile != null) // is null for nested classes
-// firstSourceName = cls.symbol.sourceFile.name
-// }
-//
-// // #####################################################################
-// // get and create types
-//
-// private def msilType(t: TypeKind): MsilType = (t: @unchecked) match {
-// case UNIT => MVOID
-// case BOOL => MBOOL
-// case BYTE => MBYTE
-// case SHORT => MSHORT
-// case CHAR => MCHAR
-// case INT => MINT
-// case LONG => MLONG
-// case FLOAT => MFLOAT
-// case DOUBLE => MDOUBLE
-// case REFERENCE(cls) => getType(cls)
-// case ARRAY(elem) =>
-// msilType(elem) match {
-// // For type builders, cannot call "clrTypes.mkArrayType" because this looks up
-// // the type "tp" in the assembly (not in the HashMap "types" of the backend).
-// // This can fail for nested types because the builders are not complete yet.
-// case tb: TypeBuilder => tb.MakeArrayType()
-// case tp: MsilType => clrTypes.mkArrayType(tp)
-// }
-// }
-//
-// private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe))
-//
-// private def msilParamTypes(sym: Symbol): Array[MsilType] = {
-// sym.tpe.paramTypes.map(msilType).toArray
-// }
-//
-// def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym)))
-//
-// /**
-// * Get an MSIL type from a symbol. First look in the clrTypes.types map, then
-// * lookup the name using clrTypes.getType
-// */
-// def getTypeOpt(sym: Symbol): Option[MsilType] = {
-// val tmp = types.get(sym)
-// tmp match {
-// case typ @ Some(_) => typ
-// case None =>
-// def typeString(sym: Symbol): String = {
-// val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName
-// else sym.fullName
-// if (sym.isModuleClass && !sym.isTrait) s + "$" else s
-// }
-// val name = typeString(sym)
-// val typ = clrTypes.getType(name)
-// if (typ == null)
-// None
-// else {
-// types(sym) = typ
-// Some(typ)
-// }
-// }
-// }
-//
-// def mapType(sym: Symbol, mType: MsilType) {
-// assert(mType != null, showsym(sym))
-// types(sym) = mType
-// }
-//
-// def createTypeBuilder(iclass: IClass) {
-// /**
-// * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise
-// * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)).
-// */
-// def msilTypeFromSym(sym: Symbol): MsilType = {
-// types.get(sym).getOrElse {
-// classes.get(sym) match {
-// case Some(iclass) =>
-// msilTypeBuilderFromSym(sym)
-// case None =>
-// getType(sym)
-// }
-// }
-// }
-//
-// def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = {
-// if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){
-// val iclass = classes(sym)
-// assert(iclass != null)
-// createTypeBuilder(iclass)
-// }
-// types(sym).asInstanceOf[TypeBuilder]
-// }
-//
-// val sym = iclass.symbol
-// if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])
-// return
-//
-// def isInterface(s: Symbol) = s.isTrait && !s.isImplClass
-// val parents: List[Type] =
-// if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe)
-// else sym.info.parents.distinct
-//
-// val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol)
-// debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType)
-//
-// val interfaces: Array[MsilType] =
-// parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray
-// if (parents.length > 1) {
-// if (settings.debug.value) {
-// log("interfaces:")
-// for (i <- 0.until(interfaces.length)) {
-// log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i))
-// }
-// }
-// }
-//
-// val tBuilder = if (sym.isNestedClass) {
-// val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder]
-// ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces)
-// } else {
-// mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces)
-// }
-// mapType(sym, tBuilder)
-// } // createTypeBuilder
-//
-// def createClassMembers(iclass: IClass) {
-// try {
-// createClassMembers0(iclass)
-// }
-// catch {
-// case e: Throwable =>
-// java.lang.System.err.println(showsym(iclass.symbol))
-// java.lang.System.err.println("with methods = " + iclass.methods)
-// throw e
-// }
-// }
-//
-// def createClassMembers0(iclass: IClass) {
-//
-// val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder]
-//
-// for (ifield <- iclass.fields) {
-// val sym = ifield.symbol
-// debuglog("Adding field: " + sym.fullName)
-//
-// var attributes = msilFieldFlags(sym)
-// val fieldTypeWithCustomMods =
-// new PECustomMod(msilType(sym.tpe),
-// customModifiers(sym.annotations))
-// val fBuilder = mtype.DefineField(msilName(sym),
-// fieldTypeWithCustomMods,
-// attributes)
-// fields(sym) = fBuilder
-// 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.lastBlock
-// val lastBlock = m.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
-// debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " +
-// sym.owner.fullName + "::" + sym.name)
-//
-// val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder]
-// assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType)
-// var paramTypes = msilParamTypes(sym)
-// val attr = msilMethodFlags(sym)
-//
-// if (m.symbol.isClassConstructor) {
-// val constr =
-// ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes)
-// for (i <- 0.until(paramTypes.length)) {
-// constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym))
-// }
-// mapConstructor(sym, constr)
-// addAttributes(constr, sym.annotations)
-// } else {
-// var resType = msilType(m.returnType)
-// val method =
-// ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes)
-// for (i <- 0.until(paramTypes.length)) {
-// method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym))
-// }
-// if (!methods.contains(sym))
-// mapMethod(sym, method)
-// addAttributes(method, sym.annotations)
-// debuglog("\t created MethodBuilder " + method)
-// }
-// }
-// } // method builders created for non-array iclass
-//
-// if (isStaticModule(iclass.symbol)) {
-// addModuleInstanceField(iclass.symbol)
-// notInitializedModules += iclass.symbol
-// if (iclass.lookupStaticCtor.isEmpty) {
-// addStaticInit(iclass.symbol)
-// }
-// }
-//
-// } // createClassMembers0
-//
-// private def isTopLevelModule(sym: Symbol): Boolean =
-// atPhase (currentRun.refchecksPhase) {
-// sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass
-// }
-//
-// // if the module is lifted it does not need to be initialized in
-// // its static constructor, and the MODULE$ field is not required.
-// // the outer class will care about it.
-// private def isStaticModule(sym: Symbol): Boolean = {
-// // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added
-// // 'sym.isStatic'. -> no longer compatible without skipping flatten!
-// sym.isModuleClass && sym.isStatic && !sym.isImplClass
-// }
-//
-// private def isCloneable(sym: Symbol): Boolean = {
-// !sym.annotations.forall( a => a match {
-// case AnnotationInfo(CloneableAttr, _, _) => false
-// case _ => true
-// })
-// }
-//
-// private def addModuleInstanceField(sym: Symbol) {
-// debuglog("Adding Module-Instance Field for " + showsym(sym))
-// val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
-// val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME,
-// tBuilder,
-// (FieldAttributes.Public |
-// //FieldAttributes.InitOnly |
-// FieldAttributes.Static).toShort)
-// fields(sym) = fb
-// }
-//
-//
-// // the symbol may be a object-symbol (module-symbol), or a module-class-symbol
-// private def getModuleInstanceField(sym: Symbol): FieldInfo = {
-// assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym))
-//
-// // when called by LOAD_MODULE, the corresponding type maybe doesn't
-// // exist yet -> make a getType
-// val moduleClassSym = if (sym.isModule) sym.moduleClass else sym
-//
-// // TODO: get module field for modules not defined in the
-// // source currently compiling (e.g. Console)
-//
-// fields get moduleClassSym match {
-// case Some(sym) => sym
-// case None =>
-// //val mclass = types(moduleClassSym)
-// 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
-// mfield
-// }
-//
-// //fields(moduleClassSym)
-// }
-//
-// def nestingAwareFullClassname(csym: Symbol) : String = {
-// val suffix = csym.moduleSuffix
-// val res = if (csym.isNestedClass)
-// nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName
-// else
-// csym.fullName
-// res + suffix
-// }
-//
-// /** 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
-// * in the MODULE$ field right after the super call.
-// */
-// private def addStaticInit(sym: Symbol) {
-// val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
-//
-// val staticInit = tBuilder.DefineConstructor(
-// (MethodAttributes.Static | MethodAttributes.Public).toShort,
-// CallingConventions.Standard,
-// MsilType.EmptyTypes)
-//
-// val sicode = staticInit.GetILGenerator()
-//
-// val instanceConstructor = constructors(sym.primaryConstructor)
-//
-// // there are no constructor parameters. assuming the constructor takes no parameter
-// // is fine: we call (in the static constructor) the constructor of the module class,
-// // which takes no arguments - an object definition cannot take constructor arguments.
-// sicode.Emit(OpCodes.Newobj, instanceConstructor)
-// // the stsfld is done in the instance constructor, just after the super call.
-// sicode.Emit(OpCodes.Pop)
-//
-// sicode.Emit(OpCodes.Ret)
-// }
-//
-// private def generateMirrorClass(sym: Symbol) {
-// val tBuilder = getType(sym)
-// assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym)
-// debuglog("Dumping mirror class for object: " + sym)
-// val moduleName = msilName(sym)
-// val mirrorName = moduleName.substring(0, moduleName.length() - 1)
-// val mirrorTypeBuilder = mmodule.DefineType(mirrorName,
-// TypeAttributes.Class |
-// TypeAttributes.Public |
-// TypeAttributes.Sealed,
-// MOBJECT,
-// MsilType.EmptyTypes)
-//
-// val iclass = classes(sym)
-//
-// for (m <- sym.tpe.nonPrivateMembers
-// if m.owner != definitions.ObjectClass && !m.isProtected &&
-// m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase &&
-// !m.isDeferred)
-// {
-// debuglog(" Mirroring method: " + m)
-// val paramTypes = msilParamTypes(m)
-// val paramNames: Array[String] = new Array[String](paramTypes.length)
-// for (i <- 0 until paramTypes.length)
-// paramNames(i) = "x_" + i
-//
-// // CHECK: verify if getMethodName is better than msilName
-// val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m),
-// (MethodAttributes.Public |
-// MethodAttributes.Static).toShort,
-// msilType(m.tpe.resultType),
-// paramTypes)
-//
-// var i = 0
-// while (i < paramTypes.length) {
-// mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i))
-// i += 1
-// }
-//
-// val mirrorCode = mirrorMethod.GetILGenerator()
-// mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym))
-// val mInfo = getMethod(m)
-// for (paramidx <- 0.until(paramTypes.length)) {
-// val mInfoParams = mInfo.GetParameters
-// val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef
-// loadArg(mirrorCode, loadAddr)(paramidx)
-// }
-//
-// mirrorCode.Emit(OpCodes.Callvirt, getMethod(m))
-// mirrorCode.Emit(OpCodes.Ret)
-// }
-//
-// addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder)
-//
-// mirrorTypeBuilder.CreateType()
-// mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path)
-// }
-//
-//
-// // #####################################################################
-// // delegate callers
-//
-// var delegateCallers: TypeBuilder = _
-// var nbDelegateCallers: Int = 0
-//
-// private def initDelegateCallers() = {
-// delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public |
-// TypeAttributes.Sealed)
-// }
-//
-// private def createDelegateCaller(functionType: Type, delegateType: Type) = {
-// if (delegateCallers == null)
-// initDelegateCallers()
-// // create a field an store the function-object
-// val mFunctionType: MsilType = msilType(functionType)
-// val anonfunField: FieldBuilder = delegateCallers.DefineField(
-// "$anonfunField$$" + nbDelegateCallers, mFunctionType,
-// (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort)
-// mcode.Emit(OpCodes.Stsfld, anonfunField)
-//
-//
-// // create the static caller method and the delegate object
-// val (params, returnType) = delegateType.member(nme.apply).tpe match {
-// case MethodType(delParams, delReturn) => (delParams, delReturn)
-// case _ => abort("not a delegate type: " + delegateType)
-// }
-// val caller: MethodBuilder = delegateCallers.DefineMethod(
-// "$delegateCaller$$" + nbDelegateCallers,
-// (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort,
-// msilType(returnType), (params map (_.tpe)).map(msilType).toArray)
-// for (i <- 0 until params.length)
-// caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol
-// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR))
-// mcode.Emit(OpCodes.Ldnull)
-// mcode.Emit(OpCodes.Ldftn, caller)
-// mcode.Emit(OpCodes.Newobj, delegCtor)
-//
-//
-// // create the static caller method body
-// val functionApply: MethodInfo = getMethod(functionType.member(nme.apply))
-// val dcode: ILGenerator = caller.GetILGenerator()
-// dcode.Emit(OpCodes.Ldsfld, anonfunField)
-// for (i <- 0 until params.length) {
-// loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i)
-// emitBox(dcode, toTypeKind(params(i).tpe))
-// }
-// dcode.Emit(OpCodes.Callvirt, functionApply)
-// emitUnbox(dcode, toTypeKind(returnType))
-// dcode.Emit(OpCodes.Ret)
-//
-// nbDelegateCallers = nbDelegateCallers + 1
-//
-// } //def createDelegateCaller
-//
-// def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match {
-// // doesn't make sense, unit as parameter..
-// case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit)
-// case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE =>
-// code.Emit(OpCodes.Box, msilType(boxType))
-// case REFERENCE(cls) if clrTypes.isValueType(cls) =>
-// code.Emit(OpCodes.Box, (msilType(boxType)))
-// case REFERENCE(_) | ARRAY(_) =>
-// warning("Tried to BOX a non-valuetype.")
-// ()
-// }
-//
-// def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match {
-// case UNIT => code.Emit(OpCodes.Pop)
-// /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods)
-// behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods
-// (case null: that's easy, case boxed: track changes to unboxBlaBla)
-// (2) See also: asInstanceOf to cast from Any to number,
-// tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */
-// case BOOL => code.Emit(OpCodes.Call, toBool)
-// case BYTE => code.Emit(OpCodes.Call, toSByte)
-// case SHORT => code.Emit(OpCodes.Call, toShort)
-// case CHAR => code.Emit(OpCodes.Call, toChar)
-// case INT => code.Emit(OpCodes.Call, toInt)
-// case LONG => code.Emit(OpCodes.Call, toLong)
-// case FLOAT => code.Emit(OpCodes.Call, toFloat)
-// case DOUBLE => code.Emit(OpCodes.Call, toDouble)
-// case REFERENCE(cls) if clrTypes.isValueType(cls) =>
-// code.Emit(OpCodes.Unbox, msilType(boxType))
-// code.Emit(OpCodes.Ldobj, msilType(boxType))
-// case REFERENCE(_) | ARRAY(_) =>
-// warning("Tried to UNBOX a non-valuetype.")
-// ()
-// }
-//
-// // #####################################################################
-// // get and create methods / constructors
-//
-// def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match {
-// case Some(constr) => constr
-// case None =>
-// val mClass = getType(sym.owner)
-// val constr = mClass.GetConstructor(msilParamTypes(sym))
-// if (constr eq null) {
-// java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name)
-// java.lang.System.out.println("scope = " + sym.owner.tpe.decls)
-// abort(sym.fullName)
-// }
-// else {
-// mapConstructor(sym, constr)
-// constr
-// }
-// }
-//
-// def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = {
-// constructors(sym) = cInfo
-// }
-//
-// private def getMethod(sym: Symbol): MethodInfo = {
-//
-// methods.get(sym) match {
-// case Some(method) => method
-// case None =>
-// val mClass = getType(sym.owner)
-// try {
-// val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym),
-// msilType(sym.tpe.resultType))
-// if (method eq null) {
-// java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym))
-// java.lang.System.out.println("scope = " + sym.owner.tpe.decls)
-// abort(sym.fullName)
-// }
-// else {
-// mapMethod(sym, method)
-// method
-// }
-// }
-// catch {
-// case e: Exception =>
-// Console.println("While looking up " + mClass + "::" + sym.nameString)
-// Console.println("\t" + showsym(sym))
-// throw e
-// }
-// }
-// }
-//
-// /*
-// * add a mapping between sym and mInfo
-// */
-// private def mapMethod(sym: Symbol, mInfo: MethodInfo) {
-// assert (mInfo != null, mInfo)
-// methods(sym) = mInfo
-// }
-//
-// /*
-// * add mapping between sym and method with newName, paramTypes of newClass
-// */
-// private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) {
-// val methodInfo = newClass.GetMethod(newName, paramTypes)
-// assert(methodInfo != null, "Can't find mapping for " + sym + " -> " +
-// newName + "(" + paramTypes + ")")
-// mapMethod(sym, methodInfo)
-// if (methodInfo.IsStatic)
-// dynToStatMapped += sym
-// }
-//
-// /*
-// * add mapping between method with name and paramTypes of clazz to
-// * method with newName and newParamTypes of newClass (used for instance
-// * for "wait")
-// */
-// private def mapMethod(
-// clazz: Symbol, name: Name, paramTypes: Array[Type],
-// newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) {
-// val methodSym = lookupMethod(clazz, name, paramTypes)
-// assert(methodSym != null, "cannot find method " + name + "(" +
-// paramTypes + ")" + " in class " + clazz)
-// mapMethod(methodSym, newClass, newName, newParamTypes)
-// }
-//
-// /*
-// * add mapping for member with name and paramTypes to member
-// * newName of newClass (same parameters)
-// */
-// private def mapMethod(
-// clazz: Symbol, name: Name, paramTypes: Array[Type],
-// newClass: MsilType, newName: String) {
-// mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType)
-// }
-//
-// /*
-// * add mapping for all methods with name of clazz to the corresponding
-// * method (same parameters) with newName of newClass
-// */
-// private def mapMethod(
-// clazz: Symbol, name: Name,
-// newClass: MsilType, newName: String) {
-// val memberSym: Symbol = clazz.tpe.member(name)
-// memberSym.tpe match {
-// // alternatives: List[Symbol]
-// case OverloadedType(_, alternatives) =>
-// alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s)))
-//
-// // paramTypes: List[Type], resType: Type
-// case MethodType(params, resType) =>
-// mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym))
-//
-// case _ =>
-// abort("member not found: " + clazz + ", " + name)
-// }
-// }
-//
-//
-// /*
-// * find the method in clazz with name and paramTypes
-// */
-// private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = {
-// val memberSym = clazz.tpe.member(name)
-// memberSym.tpe match {
-// case OverloadedType(_, alternatives) =>
-// alternatives.find(s => {
-// var i: Int = 0
-// var typesOK: Boolean = true
-// if (paramTypes.length == s.tpe.paramTypes.length) {
-// while(i < paramTypes.length) {
-// if (paramTypes(i) != s.tpe.paramTypes(i))
-// typesOK = false
-// i += 1
-// }
-// } else {
-// typesOK = false
-// }
-// typesOK
-// }) match {
-// case Some(sym) => sym
-// case None => abort("member of " + clazz + ", " + name + "(" +
-// paramTypes + ") not found")
-// }
-//
-// case MethodType(_, _) => memberSym
-//
-// case _ => abort("member not found: " + name + " of " + clazz)
-// }
-// }
-//
-// private def showsym(sym: Symbol): String = (sym.toString +
-// "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym +
-// "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner
-// )
-//
-// } // class BytecodeGenerator
-//
-// } // class GenMSIL
+
+abstract class GenMSIL /*extends SubComponent {
+ import global._
+ import loaders.clrTypes
+ import clrTypes.{types, constructors, methods, fields}
+ import icodes._
+ import icodes.opcodes._
+
+ val x = loaders
+
+ /** Create a new phase */
+ override def newPhase(p: Phase) = new MsilPhase(p)
+
+ val phaseName = "msil"
+ /** MSIL code generation phase
+ */
+ class MsilPhase(prev: Phase) extends GlobalPhase(prev) {
+ def name = phaseName
+ override def newFlags = phaseNewFlags
+
+ override def erasedTypes = true
+
+ override def run() {
+ if (settings.debug.value) inform("[running phase " + name + " on icode]")
+
+ val codeGenerator = new BytecodeGenerator
+
+ //classes is ICodes.classes, a HashMap[Symbol, IClass]
+ classes.values foreach codeGenerator.findEntryPoint
+ if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead
+ val entryclass = opt.showClass.get.toString
+ warning("Couldn't find entry class " + entryclass)
+ }
+
+ codeGenerator.initAssembly
+
+ val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output
+ classesSorted foreach codeGenerator.createTypeBuilder
+ classesSorted foreach codeGenerator.createClassMembers
+
+ try {
+ classesSorted foreach codeGenerator.genClass
+ } finally {
+ codeGenerator.writeAssembly
+ }
+ }
+
+ override def apply(unit: CompilationUnit) {
+ abort("MSIL works on icode classes, not on compilation units!")
+ }
+ }
+
+ /**
+ * MSIL bytecode generator.
+ *
+ */
+ class BytecodeGenerator {
+
+ val MODULE_INSTANCE_NAME = "MODULE$"
+
+ import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT,
+ CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT,
+ DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING,
+ STRING_ARRAY => MSTRING_ARRAY,
+ SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR,
+ SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR}
+
+ val EXCEPTION = clrTypes.getType("System.Exception")
+ val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE)
+
+ val ICLONEABLE = clrTypes.getType("System.ICloneable")
+ val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes)
+
+ val MMONITOR = clrTypes.getType("System.Threading.Monitor")
+ val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT))
+ val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT))
+
+ val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder")
+ val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes)
+ val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString",
+ MsilType.EmptyTypes)
+
+ val TYPE_FROM_HANDLE =
+ clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle")))
+
+ val INT_PTR = clrTypes.getType("System.IntPtr")
+
+ val JOBJECT = definitions.ObjectClass
+ val JSTRING = definitions.StringClass
+
+ val SystemConvert = clrTypes.getType("System.Convert")
+
+ val objParam = Array(MOBJECT)
+
+ val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox
+ val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam)
+ val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam)
+ val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam)
+ val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam)
+ val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam)
+ val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam)
+ val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam)
+
+ //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT")
+ val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT)
+
+ // Scala attributes
+ // symtab.Definitions -> object (singleton..)
+ val SerializableAttr = definitions.SerializableAttr.tpe
+ val CloneableAttr = definitions.CloneableAttr.tpe
+ val TransientAtt = definitions.TransientAttr.tpe
+ // remoting: the architectures are too different, no mapping (no portable code
+ // possible)
+
+ // java instance methods that are mapped to static methods in .net
+ // these will need to be called with OpCodes.Call (not Callvirt)
+ val dynToStatMapped = mutable.HashSet[Symbol]()
+
+ initMappings()
+
+ /** Create the mappings between java and .net classes and methods */
+ private def initMappings() {
+ mapType(definitions.AnyClass, MOBJECT)
+ mapType(definitions.AnyRefClass, MOBJECT)
+ //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$"))
+ //mapType(definitions.NothingClass, clrTypes.getType("scala.All$"))
+ // FIXME: for some reason the upper two lines map to null
+ mapType(definitions.NullClass, EXCEPTION)
+ mapType(definitions.NothingClass, EXCEPTION)
+
+ mapType(definitions.BooleanClass, MBOOL)
+ mapType(definitions.ByteClass, MBYTE)
+ mapType(definitions.ShortClass, MSHORT)
+ mapType(definitions.CharClass, MCHAR)
+ mapType(definitions.IntClass, MINT)
+ mapType(definitions.LongClass, MLONG)
+ mapType(definitions.FloatClass, MFLOAT)
+ mapType(definitions.DoubleClass, MDOUBLE)
+ }
+
+ var clasz: IClass = _
+ var method: IMethod = _
+
+ var massembly: AssemblyBuilder = _
+ var mmodule: ModuleBuilder = _
+ var mcode: ILGenerator = _
+
+ var assemName: String = _
+ var firstSourceName = ""
+ var outDir: File = _
+ var srcPath: File = _
+ var moduleName: String = _
+
+ def initAssembly() {
+
+ assemName = settings.assemname.value
+
+ if (assemName == "") {
+ if (entryPoint != null) {
+ assemName = msilName(entryPoint.enclClass)
+ // remove the $ at the end (from module-name)
+ assemName = assemName.substring(0, assemName.length() - 1)
+ } else {
+ // assuming filename of first source file
+ assert(firstSourceName.endsWith(".scala"), firstSourceName)
+ assemName = firstSourceName.substring(0, firstSourceName.length() - 6)
+ }
+ } else {
+ if (assemName.endsWith(".msil"))
+ assemName = assemName.substring(0, assemName.length()-5)
+ if (assemName.endsWith(".il"))
+ assemName = assemName.substring(0, assemName.length()-3)
+ val f: File = new File(assemName)
+ assemName = f.getName()
+ }
+
+ outDir = new File(settings.outdir.value)
+
+ srcPath = new File(settings.sourcedir.value)
+
+ val assemblyName = new AssemblyName()
+ assemblyName.Name = assemName
+ massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName)
+
+ moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe")
+ // filename here: .dll or .exe (in both parameters), second: give absolute-path
+ mmodule = massembly.DefineDynamicModule(moduleName,
+ new File(outDir, moduleName).getAbsolutePath())
+ assert (mmodule != null)
+ }
+
+
+ /**
+ * Form of the custom Attribute parameter (Ecma-335.pdf)
+ * - p. 163 for CustomAttrib Form,
+ * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!)
+ * !! least significant byte first if values longer than one byte !!
+ *
+ * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00
+ * 2: FixedArgs (directly the data, get number and types from related constructor)
+ * 2.1: length of the array (unsigned int32, 4 bytes, least significant first)
+ * 2.2: the byte array data
+ * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000)
+ */
+ def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) {
+ def addMarker() {
+ val markerSymtab = new Array[Byte](4)
+ markerSymtab(0) = 1.toByte
+ tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab)
+ }
+
+ // both conditions are needed (why exactly..?)
+ if (tBuilder.Name.endsWith("$") || sym.isModuleClass) {
+ addMarker()
+ } else {
+ currentRun.symData.get(sym) match {
+ case Some(pickle) =>
+ var size = pickle.writeIndex
+ val symtab = new Array[Byte](size + 8)
+ symtab(0) = 1.toByte
+ for (i <- 2 until 6) {
+ symtab(i) = (size & 0xff).toByte
+ size = size >> 8
+ }
+ java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex)
+
+ tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab)
+
+ currentRun.symData -= sym
+ currentRun.symData -= sym.companionSymbol
+
+ case _ =>
+ addMarker()
+ }
+ }
+ }
+
+ /**
+ * Mutates `member` adding CLR attributes (if any) based on sym.annotations.
+ * Please notice that CLR custom modifiers are a different beast (see customModifiers below)
+ * and thus shouldn't be added by this method.
+ */
+ def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) {
+ val attributes = annotations.map(_.atp.typeSymbol).collect {
+ case definitions.TransientAttr => null // TODO this is just an example
+ }
+ return // TODO: implement at some point
+ }
+
+ /**
+ * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier.
+ * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo)
+ * and thus that marker (be it optional or required) becomes part of the signature of that location.
+ * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method).
+ */
+ def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = {
+ annotations.map(_.atp.typeSymbol).collect {
+ case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker)
+ } toArray
+ }
+
+
+
+ /*
+ debuglog("creating annotations: " + annotations + " for member : " + member)
+ for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ;
+ if annot.isConstant)
+ //!typ.typeSymbol.isJavaDefined
+ {
+// assert(consts.length <= 1,
+// "too many constant arguments for annotations; "+consts.toString())
+
+ // Problem / TODO having the symbol of the annotations type would be nicer
+ // (i hope that type.typeSymbol is the same as the one in types2create)
+ // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder)
+ // when this is solved, types2create will be the same as icodes.classes, thus superfluous
+ val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder]
+// val annType: MsilType = getType(typ.typeSymbol)
+
+ // Problem / TODO: i have no idea which constructor is used. This
+ // information should be available in AnnotationInfo.
+ annType.CreateType() // else, GetConstructors can't be used
+ val constr: ConstructorInfo = annType.GetConstructors()(0)
+ // prevent a second call of CreateType, only needed because there's no
+ // other way than GetConstructors()(0) to get the constructor, if there's
+ // no constructor symbol available.
+
+ val args: Array[Byte] =
+ getAttributeArgs(
+ annArgs map (_.constant.get),
+ (for((n,v) <- nvPairs) yield (n, v.constant.get)))
+ member.SetCustomAttribute(constr, args)
+ }
+ } */
+
+/* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = {
+ val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough!
+ buf.order(ByteOrder.LITTLE_ENDIAN)
+ buf.putShort(1.toShort) // signature
+
+ def emitSerString(str: String) = {
+ // this is wrong, it has to be the length of the UTF-8 byte array, which
+ // may be longer (see clr-book on page 302)
+// val length: Int = str.length
+ val strBytes: Array[Byte] = try {
+ str.getBytes("UTF-8")
+ } catch {
+ case _: Error => abort("could not get byte-array for string: " + str)
+ }
+ val length: Int = strBytes.length //this length is stored big-endian
+ if (length < 128)
+ buf.put(length.toByte)
+ else if (length < (1<<14)) {
+ buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0'
+ buf.put((length | 0xff).toByte)
+ } else if (length < (1 << 29)) {
+ buf.put(((length >> 24) | 0xc0).toByte)
+ buf.put(((length >> 16) & 0xff).toByte)
+ buf.put(((length >> 8) & 0xff).toByte)
+ buf.put(((length ) & 0xff).toByte)
+ } else
+ abort("string too long for attribute parameter: " + length)
+ buf.put(strBytes)
+ }
+
+ def emitConst(const: Constant): Unit = const.tag match {
+ case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte)
+ case ByteTag => buf.put(const.byteValue)
+ case ShortTag => buf.putShort(const.shortValue)
+ case CharTag => buf.putChar(const.charValue)
+ case IntTag => buf.putInt(const.intValue)
+ case LongTag => buf.putLong(const.longValue)
+ case FloatTag => buf.putFloat(const.floatValue)
+ case DoubleTag => buf.putDouble(const.doubleValue)
+ case StringTag =>
+ val str: String = const.stringValue
+ if (str == null) {
+ buf.put(0xff.toByte)
+ } else {
+ emitSerString(str)
+ }
+ case ArrayTag =>
+ val arr: Array[Constant] = const.arrayValue
+ if (arr == null) {
+ buf.putInt(0xffffffff)
+ } else {
+ buf.putInt(arr.length)
+ arr.foreach(emitConst)
+ }
+
+ // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ???
+
+ case _ => abort("could not handle attribute argument: " + const)
+ }
+
+ consts foreach emitConst
+ buf.putShort(nvPairs.length.toShort)
+ def emitNamedArg(nvPair: (Name, Constant)) {
+ // the named argument is a property of the attribute (it can't be a field, since
+ // all fields in scala are private)
+ buf.put(0x54.toByte)
+
+ def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151
+ case BooleanTag => buf.put(0x02.toByte)
+ case ByteTag => buf.put(0x05.toByte)
+ case ShortTag => buf.put(0x06.toByte)
+ case CharTag => buf.put(0x07.toByte)
+ case IntTag => buf.put(0x08.toByte)
+ case LongTag => buf.put(0x0a.toByte)
+ case FloatTag => buf.put(0x0c.toByte)
+ case DoubleTag => buf.put(0x0d.toByte)
+ case StringTag => buf.put(0x0e.toByte)
+
+ // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ???
+
+ // ArrayTag falls in here
+ case _ => abort("could not handle attribute argument: " + c)
+ }
+
+ val cnst: Constant = nvPair._2
+ if (cnst.tag == ArrayTag) {
+ buf.put(0x1d.toByte)
+ emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0
+ } else if (cnst.tag == EnumTag) {
+ buf.put(0x55.toByte)
+ // TODO: put a SerString (don't know what exactly, names of the enums somehow..)
+ } else {
+ buf.put(0x51.toByte)
+ emitType(cnst)
+ }
+
+ emitSerString(nvPair._1.toString)
+ emitConst(nvPair._2)
+ }
+
+ val length = buf.position()
+ buf.array().slice(0, length)
+ } */
+
+ def writeAssembly() {
+ if (entryPoint != null) {
+ assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass)
+ val mainMethod = methods(entryPoint)
+ val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY)
+ val globalMain = mmodule.DefineGlobalMethod(
+ "Main", MethodAttributes.Public | MethodAttributes.Static,
+ MVOID, stringArrayTypes)
+ globalMain.DefineParameter(0, ParameterAttributes.None, "args")
+ massembly.SetEntryPoint(globalMain)
+ val code = globalMain.GetILGenerator()
+ val moduleField = getModuleInstanceField(entryPoint.enclClass)
+ code.Emit(OpCodes.Ldsfld, moduleField)
+ code.Emit(OpCodes.Ldarg_0)
+ code.Emit(OpCodes.Callvirt, mainMethod)
+ code.Emit(OpCodes.Ret)
+ }
+ createTypes()
+ var outDirName: String = null
+ try {
+ if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar
+ outDirName = outDir.getPath()
+ massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */
+ } else {
+ outDirName = srcPath.getPath()
+ massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */
+ }
+ } catch {
+ case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage())
+ }
+ }
+
+ private def createTypes() {
+ for (sym <- classes.keys) {
+ val iclass = classes(sym)
+ val tBuilder = types(sym).asInstanceOf[TypeBuilder]
+
+ debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString)
+
+ tBuilder.CreateType()
+ tBuilder.setSourceFilepath(iclass.cunit.source.file.path)
+ }
+ }
+
+ private[GenMSIL] def ilasmFileName(iclass: IClass) : String = {
+ // method.sourceFile contains just the filename
+ iclass.cunit.source.file.toString.replace("\\", "\\\\")
+ }
+
+ private[GenMSIL] def genClass(iclass: IClass) {
+ val sym = iclass.symbol
+ debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags))
+ clasz = iclass
+
+ val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
+ if (isCloneable(sym)) {
+ // FIXME: why there's no nme.clone_ ?
+ // "Clone": if the code is non-portable, "Clone" is defined, not "clone"
+ // TODO: improve condition (should override AnyRef.clone)
+ if (iclass.methods.forall(m => {
+ !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") &&
+ m.symbol.tpe.paramTypes.length != 0)
+ })) {
+ debuglog("auto-generating cloneable method for " + sym)
+ val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual |
+ MethodAttributes.HideBySig).toShort
+ val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT,
+ MsilType.EmptyTypes)
+ val clCode = cloneMethod.GetILGenerator()
+ clCode.Emit(OpCodes.Ldarg_0)
+ clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE)
+ clCode.Emit(OpCodes.Ret)
+ }
+ }
+
+ val line = sym.pos.line
+ tBuilder.setPosition(line, ilasmFileName(iclass))
+
+ if (isTopLevelModule(sym)) {
+ if (sym.companionClass == NoSymbol)
+ generateMirrorClass(sym)
+ else
+ log("No mirror class for module with linked class: " +
+ sym.fullName)
+ }
+
+ addSymtabAttribute(sym, tBuilder)
+ addAttributes(tBuilder, sym.annotations)
+
+ if (iclass.symbol != definitions.ArrayClass)
+ iclass.methods foreach genMethod
+
+ } //genClass
+
+
+ private def genMethod(m: IMethod) {
+ debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +
+ " owner: " + m.symbol.owner)
+ method = m
+ localBuilders.clear
+ computeLocalVarsIndex(m)
+
+ if (m.symbol.isClassConstructor) {
+ mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator()
+ } else {
+ val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder]
+ if (!mBuilder.IsAbstract())
+ try {
+ mcode = mBuilder.GetILGenerator()
+ } catch {
+ case e: Exception =>
+ java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol)
+ java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner)
+ java.lang.System.out.println("mBuilder = " + mBuilder)
+ java.lang.System.out.println("mBuilder.DeclaringType = " +
+ TypeAttributes.toString(mBuilder.DeclaringType.Attributes) +
+ "::" + mBuilder.DeclaringType)
+ throw e
+ }
+ else
+ mcode = null
+ }
+
+ if (mcode != null) {
+ for (local <- m.locals ; if !(m.params contains local)) {
+ debuglog("add local var: " + local + ", of kind " + local.kind)
+ val t: MsilType = msilType(local.kind)
+ val localBuilder = mcode.DeclareLocal(t)
+ localBuilder.SetLocalSymInfo(msilName(local.sym))
+ localBuilders(local) = localBuilder
+ }
+ genCode(m)
+ }
+
+ }
+
+ /** Special linearizer for methods with at least one exception handler. This
+ * linearizer brings all basic blocks in the right order so that nested
+ * try-catch and try-finally blocks can be emitted.
+ */
+ val msilLinearizer = new MSILLinearizer()
+
+ val labels = mutable.HashMap[BasicBlock, Label]()
+
+ /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize.
+ * this scheme relies on the fact that the entry block is emitted first. */
+ var dbFilenameSeen = false
+
+ def genCode(m: IMethod) {
+
+ def makeLabels(blocks: List[BasicBlock]) = {
+ debuglog("Making labels for: " + method)
+ for (bb <- blocks) labels(bb) = mcode.DefineLabel()
+ }
+
+ labels.clear
+
+ var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m)
+ else linearizer.linearize(m)
+
+ if (!m.exh.isEmpty)
+ linearization = computeExceptionMaps(linearization, m)
+
+ makeLabels(linearization)
+
+ // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label)
+ // debug val blocksInL = linearization.sortBy(bb => bb.label)
+ // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP)
+ // debug if(!MButNotL.isEmpty) { }
+
+ dbFilenameSeen = false
+ genBlocks(linearization)
+
+ // RETURN inside exception blocks are replaced by Leave. The target of the
+ // leave is a `Ret` outside any exception block (generated here).
+ if (handlerReturnMethod == m) {
+ mcode.MarkLabel(handlerReturnLabel)
+ if (handlerReturnKind != UNIT)
+ mcode.Emit(OpCodes.Ldloc, handlerReturnLocal)
+ mcode.Emit(OpCodes.Ret)
+ }
+
+ beginExBlock.clear()
+ beginCatchBlock.clear()
+ endExBlock.clear()
+ endFinallyLabels.clear()
+ }
+
+ def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) {
+ blocks match {
+ case Nil => ()
+ case x :: Nil => genBlock(x, prev = previous, next = null)
+ case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x)
+ }
+ }
+
+ // the try blocks starting at a certain BasicBlock
+ val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]()
+
+ // the catch blocks starting / endling at a certain BasicBlock
+ val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]()
+ val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]()
+
+ /** When emitting the code (genBlock), the number of currently active try / catch
+ * blocks. When seeing a `RETURN` inside a try / catch, we need to
+ * - store the result in a local (if it's not UNIT)
+ * - emit `Leave handlerReturnLabel` instead of the Return
+ * - emit code at the end: load the local and return its value
+ */
+ var currentHandlers = new mutable.Stack[ExceptionHandler]
+ // The IMethod the Local/Label/Kind below belong to
+ var handlerReturnMethod: IMethod = _
+ // Stores the result when returning inside an exception block
+ var handlerReturnLocal: LocalBuilder = _
+ // Label for a return instruction outside any exception block
+ var handlerReturnLabel: Label = _
+ // The result kind.
+ var handlerReturnKind: TypeKind = _
+ def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = {
+ if (handlerReturnMethod != method) {
+ handlerReturnMethod = method
+ if (kind != UNIT) {
+ handlerReturnLocal = mcode.DeclareLocal(msilType(kind))
+ handlerReturnLocal.SetLocalSymInfo("$handlerReturn")
+ }
+ handlerReturnLabel = mcode.DefineLabel()
+ handlerReturnKind = kind
+ }
+ (handlerReturnLocal, handlerReturnLabel)
+ }
+
+ /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the
+ * Leave target has to be inside the finally (and it has to be the `endfinally` instruction).
+ * So for every finalizer, we have a label which marks the place of the `endfinally`,
+ * nested try/catch blocks will leave there.
+ */
+ val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]()
+
+ /** Computes which blocks are the beginning / end of a try or catch block */
+ private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = {
+ val visitedBlocks = new mutable.HashSet[BasicBlock]()
+
+ // handlers which have not been introduced so far
+ var openHandlers = m.exh
+
+
+ /** Example
+ * try {
+ * try {
+ * // *1*
+ * } catch {
+ * case h1 =>
+ * }
+ * } catch {
+ * case h2 =>
+ * case h3 =>
+ * try {
+ *
+ * } catch {
+ * case h4 => // *2*
+ * case h5 =>
+ * }
+ * }
+ */
+
+ // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple
+ // catch statements). Example *1*: Stack(List(h2, h3), List(h1))
+ val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]()
+
+ // Stack of nested catch blocks. The head of the list is the current catch block. The
+ // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5))
+ val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]()
+
+ for (b <- blocks) {
+
+ // are we past the current catch blocks?
+ def endHandlers(): List[ExceptionHandler] = {
+ var res: List[ExceptionHandler] = Nil
+ if (!currentCatchHandlers.isEmpty) {
+ val handler = currentCatchHandlers.top.head
+ if (!handler.blocks.contains(b)) {
+ // all blocks of the handler are either visited, or not part of the linearization (i.e. dead)
+ assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)),
+ "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+
+ b.fullString +"\nwhile in catch-part of\n"+ handler)
+
+ val rest = currentCatchHandlers.pop.tail
+ if (rest.isEmpty) {
+ // all catch blocks of that exception handler are covered
+ res = handler :: endHandlers()
+ } else {
+ // there are more catch blocks for that try (handlers covering the same)
+ currentCatchHandlers.push(rest)
+ beginCatchBlock(b) = rest.head
+ }
+ }
+ }
+ res
+ }
+ val end = endHandlers()
+ if (!end.isEmpty) endExBlock(b) = end
+
+ // are we past the current try block?
+ if (!currentTryHandlers.isEmpty) {
+ val handler = currentTryHandlers.top.head
+ if (!handler.covers(b)) {
+ // all of the covered blocks are visited, or not part of the linearization
+ assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)),
+ "Bad linearization of basic blocks inside try. Found non-covered block\n"+
+ b.fullString +"\nwhile in try-part of\n"+ handler)
+
+ assert(handler.startBlock == b,
+ "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+
+ b.fullString +"\n"+ handler)
+
+ val handlers = currentTryHandlers.pop
+ currentCatchHandlers.push(handlers)
+ beginCatchBlock(b) = handler
+ }
+ }
+
+ // are there try blocks starting at b?
+ val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b))
+ openHandlers = stillOpen
+
+ val newHandlersBySize = newHandlers.groupBy(_.covered.size)
+ // big handlers first, smaller ones are nested inside the try of the big one
+ // (checked by the assertions below)
+ val sizes = newHandlersBySize.keys.toList.sortWith(_ > _)
+
+ val beginHandlers = new mutable.ListBuffer[ExceptionHandler]
+ for (s <- sizes) {
+ val sHandlers = newHandlersBySize(s)
+ for (h <- sHandlers) {
+ assert(h.covered == sHandlers.head.covered,
+ "bad nesting of exception handlers. same size, but not covering same blocks\n"+
+ h +"\n"+ sHandlers.head)
+ assert(h.resultKind == sHandlers.head.resultKind,
+ "bad nesting of exception handlers. same size, but the same resultKind\n"+
+ h +"\n"+ sHandlers.head)
+ }
+ for (bigger <- beginHandlers; h <- sHandlers) {
+ assert(h.covered.subsetOf(bigger.covered),
+ "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+
+ h +"\n"+ bigger)
+ assert(h.blocks.toSet.subsetOf(bigger.covered),
+ "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+
+ h +"\n"+ bigger)
+ }
+ beginHandlers += sHandlers.head
+ currentTryHandlers.push(sHandlers)
+ }
+ beginExBlock(b) = beginHandlers.toList
+ visitedBlocks += b
+ }
+
+ // if there handlers left (i.e. handlers covering nothing, or a
+ // non-existent (dead) block), remove their catch-blocks.
+ val liveBlocks = if (openHandlers.isEmpty) blocks else {
+ blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b)))
+ }
+
+ /** There might be open handlers, but no more blocks. happens when try/catch end
+ * with `throw` or `return`
+ * def foo() { try { .. throw } catch { _ => .. throw } }
+ *
+ * In this case we need some code after the catch block for the auto-generated
+ * `leave` instruction. So we're adding a (dead) `throw new Exception`.
+ */
+ val rest = currentCatchHandlers.map(handlers => {
+ assert(handlers.length == 1, handlers)
+ handlers.head
+ }).toList
+
+ if (rest.isEmpty) {
+ liveBlocks
+ } else {
+ val b = m.code.newBlock
+ b.emit(Seq(
+ NEW(REFERENCE(definitions.ThrowableClass)),
+ DUP(REFERENCE(definitions.ObjectClass)),
+ CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)),
+ THROW(definitions.ThrowableClass)
+ ))
+ b.close
+ endExBlock(b) = rest
+ liveBlocks ::: List(b)
+ }
+ }
+
+ /**
+ * @param block the BasicBlock to emit code for
+ * @param next the following BasicBlock, `null` if `block` is the last one
+ */
+ def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) {
+
+ def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) {
+ debuglog(msg + " for " + local)
+ val isArg = local.arg
+ val i = local.index
+ if (isArg)
+ loadArg(mcode, loadAddr)(i)
+ else
+ loadLocal(i, local, mcode, loadAddr)
+ }
+
+ def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) {
+ debuglog(msg + " with owner: " + field.owner +
+ " flags: " + Flags.flagsToString(field.owner.flags))
+ var fieldInfo = fields.get(field) match {
+ case Some(fInfo) => fInfo
+ case None =>
+ val fInfo = getType(field.owner).GetField(msilName(field))
+ fields(field) = fInfo
+ fInfo
+ }
+ if (fieldInfo.IsVolatile) {
+ mcode.Emit(OpCodes.Volatile)
+ }
+ if (!fieldInfo.IsLiteral) {
+ if (loadAddr) {
+ mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo)
+ } else {
+ mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo)
+ }
+ } else {
+ assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...")
+ // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack.
+ /* We perform `field inlining' as required by CLR.
+ * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available
+ * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type
+ * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case,
+ * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */
+ val value = fieldInfo.getValue()
+ if (value == null) {
+ mcode.Emit(OpCodes.Ldnull)
+ } else {
+ val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType
+ else fieldInfo.FieldType
+ if (typ == clrTypes.STRING) {
+ mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String])
+ } else if (typ == clrTypes.BOOLEAN) {
+ mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1
+ else OpCodes.Ldc_I4_0)
+ } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) {
+ loadI4(value.asInstanceOf[Byte], mcode)
+ } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) {
+ loadI4(value.asInstanceOf[Int], mcode)
+ } else if (typ == clrTypes.CHAR) {
+ loadI4(value.asInstanceOf[Char], mcode)
+ } else if (typ == clrTypes.INT || typ == clrTypes.UINT) {
+ loadI4(value.asInstanceOf[Int], mcode)
+ } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) {
+ mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long])
+ } else if (typ == clrTypes.FLOAT) {
+ mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float])
+ } else if (typ == clrTypes.DOUBLE) {
+ mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double])
+ } else {
+ /* TODO one more case is described in Partition II, 16.2: bytearray(...) */
+ abort("Unknown type for static literal field: " + fieldInfo)
+ }
+ }
+ }
+ }
+
+ /** Creating objects works differently on .NET. On the JVM
+ * - NEW(type) => reference on Stack
+ * - DUP, load arguments, CALL_METHOD(constructor)
+ *
+ * On .NET, the NEW and DUP are ignored, but we emit a special method call
+ * - load arguments
+ * - NewObj(constructor) => reference on stack
+ *
+ * This variable tells whether the previous instruction was a NEW,
+ * we expect a DUP which is not emitted. */
+ var previousWasNEW = false
+
+ var lastLineNr: Int = 0
+ var lastPos: Position = NoPosition
+
+
+ // EndExceptionBlock must happen before MarkLabel because it adds the
+ // Leave instruction. Otherwise, labels(block) points to the Leave
+ // (inside the catch) instead of the instruction afterwards.
+ for (handlers <- endExBlock.get(block); exh <- handlers) {
+ currentHandlers.pop()
+ for (l <- endFinallyLabels.get(exh))
+ mcode.MarkLabel(l)
+ mcode.EndExceptionBlock()
+ }
+
+ mcode.MarkLabel(labels(block))
+ debuglog("Generating code for block: " + block)
+
+ for (handler <- beginCatchBlock.get(block)) {
+ if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) {
+ currentHandlers.pop()
+ currentHandlers.push(handler)
+ }
+ if (handler.cls == NoSymbol) {
+ // `finally` blocks are represented the same as `catch`, but with no catch-type
+ mcode.BeginFinallyBlock()
+ } else {
+ val t = getType(handler.cls)
+ mcode.BeginCatchBlock(t)
+ }
+ }
+ for (handlers <- beginExBlock.get(block); exh <- handlers) {
+ currentHandlers.push(exh)
+ mcode.BeginExceptionBlock()
+ }
+
+ for (instr <- block) {
+ try {
+ val currentLineNr = instr.pos.line
+ val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr);
+ if(!skip || !dbFilenameSeen) {
+ val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)};
+ if(instr.pos.isRange) {
+ val startLine = instr.pos.focusStart.line
+ val endLine = instr.pos.focusEnd.line
+ val startCol = instr.pos.focusStart.column
+ val endCol = instr.pos.focusEnd.column
+ mcode.setPosition(startLine, endLine, startCol, endCol, fileName)
+ } else {
+ mcode.setPosition(instr.pos.line, fileName)
+ }
+ lastLineNr = currentLineNr
+ lastPos = instr.pos
+ }
+ } catch { case _: UnsupportedOperationException => () }
+
+ if (previousWasNEW)
+ assert(instr.isInstanceOf[DUP], block)
+
+ instr match {
+ case THIS(clasz) =>
+ mcode.Emit(OpCodes.Ldarg_0)
+
+ case CONSTANT(const) =>
+ const.tag match {
+ case UnitTag => ()
+ case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1
+ else OpCodes.Ldc_I4_0)
+ case ByteTag => loadI4(const.byteValue, mcode)
+ case ShortTag => loadI4(const.shortValue, mcode)
+ case CharTag => loadI4(const.charValue, mcode)
+ case IntTag => loadI4(const.intValue, mcode)
+ case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue)
+ case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue)
+ case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue)
+ case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue)
+ case NullTag => mcode.Emit(OpCodes.Ldnull)
+ case ClassTag =>
+ mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue))
+ mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE)
+ case _ => abort("Unknown constant value: " + const)
+ }
+
+ case LOAD_ARRAY_ITEM(kind) =>
+ (kind: @unchecked) match {
+ case BOOL => mcode.Emit(OpCodes.Ldelem_I1)
+ case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte
+ case SHORT => mcode.Emit(OpCodes.Ldelem_I2)
+ case CHAR => mcode.Emit(OpCodes.Ldelem_U2)
+ case INT => mcode.Emit(OpCodes.Ldelem_I4)
+ case LONG => mcode.Emit(OpCodes.Ldelem_I8)
+ case FLOAT => mcode.Emit(OpCodes.Ldelem_R4)
+ case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8)
+ case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref)
+ case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref)
+
+ // case UNIT is not possible: an Array[Unit] will be an
+ // Array[scala.runtime.BoxedUnit] (-> case REFERENCE)
+ }
+
+ case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false)
+
+ case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true)
+
+ case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false)
+
+ case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true)
+
+ case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind))
+
+ case CIL_NEWOBJ(msym) =>
+ assert(msym.isClassConstructor)
+ val constructorInfo: ConstructorInfo = getConstructor(msym)
+ mcode.Emit(OpCodes.Newobj, constructorInfo)
+
+ case LOAD_MODULE(module) =>
+ debuglog("Generating LOAD_MODULE for: " + showsym(module))
+ mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module))
+
+ case STORE_ARRAY_ITEM(kind) =>
+ (kind: @unchecked) match {
+ case BOOL => mcode.Emit(OpCodes.Stelem_I1)
+ case BYTE => mcode.Emit(OpCodes.Stelem_I1)
+ case SHORT => mcode.Emit(OpCodes.Stelem_I2)
+ case CHAR => mcode.Emit(OpCodes.Stelem_I2)
+ case INT => mcode.Emit(OpCodes.Stelem_I4)
+ case LONG => mcode.Emit(OpCodes.Stelem_I8)
+ case FLOAT => mcode.Emit(OpCodes.Stelem_R4)
+ case DOUBLE => mcode.Emit(OpCodes.Stelem_R8)
+ case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref)
+ case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method)
+
+ // case UNIT not possible (see comment at LOAD_ARRAY_ITEM)
+ }
+
+ case STORE_LOCAL(local) =>
+ val isArg = local.arg
+ val i = local.index
+ debuglog("store_local for " + local + ", index " + i)
+
+ // there are some locals defined by the compiler that
+ // are isArg and are need to be stored.
+ if (isArg) {
+ if (i >= -128 && i <= 127)
+ mcode.Emit(OpCodes.Starg_S, i)
+ else
+ mcode.Emit(OpCodes.Starg, i)
+ } else {
+ i match {
+ case 0 => mcode.Emit(OpCodes.Stloc_0)
+ case 1 => mcode.Emit(OpCodes.Stloc_1)
+ case 2 => mcode.Emit(OpCodes.Stloc_2)
+ case 3 => mcode.Emit(OpCodes.Stloc_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ mcode.Emit(OpCodes.Stloc_S, localBuilders(local))
+ else
+ mcode.Emit(OpCodes.Stloc, localBuilders(local))
+ }
+ }
+
+ case STORE_THIS(_) =>
+ // this only works for impl classes because the self parameter comes first
+ // in the method signature. If that changes, this code has to be revisited.
+ mcode.Emit(OpCodes.Starg_S, 0)
+
+ case STORE_FIELD(field, isStatic) =>
+ val fieldInfo = fields.get(field) match {
+ case Some(fInfo) => fInfo
+ case None =>
+ val fInfo = getType(field.owner).GetField(msilName(field))
+ fields(field) = fInfo
+ fInfo
+ }
+ mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo)
+
+ case CALL_PRIMITIVE(primitive) =>
+ genPrimitive(primitive, instr.pos)
+
+ case CALL_METHOD(msym, style) =>
+ if (msym.isClassConstructor) {
+ val constructorInfo: ConstructorInfo = getConstructor(msym)
+ (style: @unchecked) match {
+ // normal constructor calls are Static..
+ case Static(_) =>
+ if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner)
+ // we're generating a constructor (method: IMethod is a constructor), and we're
+ // calling another constructor of the same class.
+
+ // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } }
+ // instead, we should instruct the CALL_METHOD with additional information, know whether it's
+ // an instance creation constructor call or not.
+ mcode.Emit(OpCodes.Call, constructorInfo)
+ else
+ mcode.Emit(OpCodes.Newobj, constructorInfo)
+ case SuperCall(_) =>
+ mcode.Emit(OpCodes.Call, constructorInfo)
+ if (isStaticModule(clasz.symbol) &&
+ notInitializedModules.contains(clasz.symbol) &&
+ method.symbol.isClassConstructor)
+ {
+ notInitializedModules -= clasz.symbol
+ mcode.Emit(OpCodes.Ldarg_0)
+ mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol))
+ }
+ }
+
+ } else {
+
+ var doEmit = true
+ getTypeOpt(msym.owner) match {
+ case Some(typ) if (typ.IsEnum) => {
+ def negBool() = {
+ mcode.Emit(OpCodes.Ldc_I4_0)
+ mcode.Emit(OpCodes.Ceq)
+ }
+ doEmit = false
+ val name = msym.name
+ if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) }
+ else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool }
+ else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) }
+ else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool }
+ else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) }
+ else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool }
+ else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) }
+ else if (name eq nme.AND) { mcode.Emit(OpCodes.And) }
+ else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) }
+ else
+ doEmit = true
+ }
+ case _ => ()
+ }
+
+ // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType
+ val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) {
+ msym.tpe match {
+ case MethodType(params, resultType)
+ if (params.length == 1 && msym.name == nme.view_) =>
+ val paramType = params(0).tpe
+ val isDel = definitions.isCorrespondingDelegate(resultType, paramType)
+ (isDel, paramType, resultType)
+ case _ => (false, null, null)
+ }
+ }
+ if (doEmit && isDelegateView) {
+ doEmit = false
+ createDelegateCaller(paramType, resType)
+ }
+
+ if (doEmit &&
+ (msym.name == nme.PLUS || msym.name == nme.MINUS)
+ && clrTypes.isDelegateType(msilType(msym.owner.tpe)))
+ {
+ doEmit = false
+ val methodInfo: MethodInfo = getMethod(msym)
+ // call it as a static method, even if the compiler (symbol) thinks it's virtual
+ mcode.Emit(OpCodes.Call, methodInfo)
+ mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe))
+ }
+
+ if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) {
+ doEmit = false
+ val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym)
+ val delegateType: Type = msym.tpe match {
+ case MethodType(_, retType) => retType
+ case _ => abort("not a method type: " + msym.tpe)
+ }
+ val methodInfo: MethodInfo = getMethod(methodSym)
+ val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR))
+ if (methodSym.isStatic) {
+ mcode.Emit(OpCodes.Ldftn, methodInfo)
+ } else {
+ mcode.Emit(OpCodes.Dup)
+ mcode.Emit(OpCodes.Ldvirtftn, methodInfo)
+ }
+ mcode.Emit(OpCodes.Newobj, delegCtor)
+ }
+
+ if (doEmit) {
+ val methodInfo: MethodInfo = getMethod(msym)
+ (style: @unchecked) match {
+ case SuperCall(_) =>
+ mcode.Emit(OpCodes.Call, methodInfo)
+ case Dynamic =>
+ // methodInfo.DeclaringType is null for global methods
+ val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType)
+ val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual)
+ if (dynToStatMapped(msym)) {
+ mcode.Emit(OpCodes.Call, methodInfo)
+ } else if (isValuetypeVirtualMethod) {
+ mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType)
+ mcode.Emit(OpCodes.Callvirt, methodInfo)
+ } else if (isValuetypeMethod) {
+ // otherwise error "Callvirt on a value type method" ensues
+ mcode.Emit(OpCodes.Call, methodInfo)
+ } else {
+ mcode.Emit(OpCodes.Callvirt, methodInfo)
+ }
+ case Static(_) =>
+ if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) {
+ mcode.Emit(OpCodes.Callvirt, methodInfo)
+ } else mcode.Emit(OpCodes.Call, methodInfo)
+ }
+ }
+ }
+
+ case BOX(boxType) =>
+ emitBox(mcode, boxType)
+
+ case UNBOX(boxType) =>
+ emitUnbox(mcode, boxType)
+
+ case CIL_UNBOX(boxType) =>
+ mcode.Emit(OpCodes.Unbox, msilType(boxType))
+
+ case CIL_INITOBJ(valueType) =>
+ mcode.Emit(OpCodes.Initobj, msilType(valueType))
+
+ case NEW(REFERENCE(cls)) =>
+ // the next instruction must be a DUP, see comment on `var previousWasNEW`
+ previousWasNEW = true
+
+ // works also for arrays and reference-types
+ case CREATE_ARRAY(elem, dims) =>
+ // TODO: handle multi dimensional arrays
+ assert(dims == 1, "Can't handle multi dimensional arrays")
+ mcode.Emit(OpCodes.Newarr, msilType(elem))
+
+ // works for arrays and reference-types
+ case IS_INSTANCE(tpe) =>
+ mcode.Emit(OpCodes.Isinst, msilType(tpe))
+ mcode.Emit(OpCodes.Ldnull)
+ mcode.Emit(OpCodes.Ceq)
+ mcode.Emit(OpCodes.Ldc_I4_0)
+ mcode.Emit(OpCodes.Ceq)
+
+ // works for arrays and reference-types
+ // part from the scala reference: "S <: T does not imply
+ // Array[S] <: Array[T] in Scala. However, it is possible
+ // to cast an array of S to an array of T if such a cast
+ // is permitted in the host environment."
+ case CHECK_CAST(tpknd) =>
+ val tMSIL = msilType(tpknd)
+ mcode.Emit(OpCodes.Castclass, tMSIL)
+
+ // no SWITCH is generated when there's
+ // - a default case ("case _ => ...") in the matching expr
+ // - OR is used ("case 1 | 2 => ...")
+ case SWITCH(tags, branches) =>
+ // tags is List[List[Int]]; a list of integers for every label.
+ // if the int on stack is 4, and 4 is in the second list => jump
+ // to second label
+ // branches is List[BasicBlock]
+ // the labels to jump to (the last one is the default one)
+
+ val switchLocal = mcode.DeclareLocal(MINT)
+ // several switch variables will appear with the same name in the
+ // assembly code, but this makes no truble
+ switchLocal.SetLocalSymInfo("$switch_var")
+
+ mcode.Emit(OpCodes.Stloc, switchLocal)
+ var i = 0
+ for (l <- tags) {
+ var targetLabel = labels(branches(i))
+ for (i <- l) {
+ mcode.Emit(OpCodes.Ldloc, switchLocal)
+ loadI4(i, mcode)
+ mcode.Emit(OpCodes.Beq, targetLabel)
+ }
+ i += 1
+ }
+ val defaultTarget = labels(branches(i))
+ if (next != branches(i))
+ mcode.Emit(OpCodes.Br, defaultTarget)
+
+ case JUMP(whereto) =>
+ val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto)
+ if (leaveHandler) {
+ if (leaveFinally) {
+ if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
+ mcode.Emit(OpCodes.Leave, labels(whereto))
+ } else if (next != whereto)
+ mcode.Emit(OpCodes.Br, labels(whereto))
+
+ case CJUMP(success, failure, cond, kind) =>
+ // cond is TestOp (see Primitives.scala), and can take
+ // values EQ, NE, LT, GE LE, GT
+ // kind is TypeKind
+ val isFloat = kind == FLOAT || kind == DOUBLE
+ val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat)
+ emitCondBr(block, cond, success, failure, next, emit)
+
+ case CZJUMP(success, failure, cond, kind) =>
+ emitCondBr(block, cond, success, failure, next, emitBrBool(_, _))
+
+ case RETURN(kind) =>
+ if (currentHandlers.isEmpty)
+ mcode.Emit(OpCodes.Ret)
+ else {
+ val (local, label) = returnFromHandler(kind)
+ if (kind != UNIT)
+ mcode.Emit(OpCodes.Stloc, local)
+ mcode.Emit(OpCodes.Leave, label)
+ }
+
+ case THROW(_) =>
+ mcode.Emit(OpCodes.Throw)
+
+ case DROP(kind) =>
+ mcode.Emit(OpCodes.Pop)
+
+ case DUP(kind) =>
+ // see comment on `var previousWasNEW`
+ if (!previousWasNEW)
+ mcode.Emit(OpCodes.Dup)
+ else
+ previousWasNEW = false
+
+ case MONITOR_ENTER() =>
+ mcode.Emit(OpCodes.Call, MMONITOR_ENTER)
+
+ case MONITOR_EXIT() =>
+ mcode.Emit(OpCodes.Call, MMONITOR_EXIT)
+
+ case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) =>
+ ()
+ }
+
+ } // end for (instr <- b) { .. }
+ } // end genBlock
+
+ def genPrimitive(primitive: Primitive, pos: Position) {
+ primitive match {
+ case Negation(kind) =>
+ kind match {
+ // CHECK: is ist possible to get this for BOOL? in this case, verify.
+ case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE =>
+ mcode.Emit(OpCodes.Neg)
+
+ case _ => abort("Impossible to negate a " + kind)
+ }
+
+ case Arithmetic(op, kind) =>
+ op match {
+ case ADD => mcode.Emit(OpCodes.Add)
+ case SUB => mcode.Emit(OpCodes.Sub)
+ case MUL => mcode.Emit(OpCodes.Mul)
+ case DIV => mcode.Emit(OpCodes.Div)
+ case REM => mcode.Emit(OpCodes.Rem)
+ case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement)
+ case _ => abort("Unknown arithmetic primitive " + primitive )
+ }
+
+ case Logical(op, kind) => op match {
+ case AND => mcode.Emit(OpCodes.And)
+ case OR => mcode.Emit(OpCodes.Or)
+ case XOR => mcode.Emit(OpCodes.Xor)
+ }
+
+ case Shift(op, kind) => op match {
+ case LSL => mcode.Emit(OpCodes.Shl)
+ case ASR => mcode.Emit(OpCodes.Shr)
+ case LSR => mcode.Emit(OpCodes.Shr_Un)
+ }
+
+ case Conversion(src, dst) =>
+ debuglog("Converting from: " + src + " to: " + dst)
+
+ dst match {
+ case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte
+ case SHORT => mcode.Emit(OpCodes.Conv_I2)
+ case CHAR => mcode.Emit(OpCodes.Conv_U2)
+ case INT => mcode.Emit(OpCodes.Conv_I4)
+ case LONG => mcode.Emit(OpCodes.Conv_I8)
+ case FLOAT => mcode.Emit(OpCodes.Conv_R4)
+ case DOUBLE => mcode.Emit(OpCodes.Conv_R8)
+ case _ =>
+ Console.println("Illegal conversion at: " + clasz +
+ " at: " + pos.source + ":" + pos.line)
+ }
+
+ case ArrayLength(_) =>
+ mcode.Emit(OpCodes.Ldlen)
+
+ case StartConcat =>
+ mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR)
+
+
+ case StringConcat(el) =>
+ val elemType : MsilType = el match {
+ case REFERENCE(_) | ARRAY(_) => MOBJECT
+ case _ => msilType(el)
+ }
+
+ val argTypes:Array[MsilType] = Array(elemType)
+ val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes )
+ mcode.Emit(OpCodes.Callvirt, stringBuilderAppend)
+
+ case EndConcat =>
+ mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING)
+
+ case _ =>
+ abort("Unimplemented primitive " + primitive)
+ }
+ } // end genPrimitive
+
+
+ ////////////////////// loading ///////////////////////
+
+ def loadI4(value: Int, code: ILGenerator): Unit = value match {
+ case -1 => code.Emit(OpCodes.Ldc_I4_M1)
+ case 0 => code.Emit(OpCodes.Ldc_I4_0)
+ case 1 => code.Emit(OpCodes.Ldc_I4_1)
+ case 2 => code.Emit(OpCodes.Ldc_I4_2)
+ case 3 => code.Emit(OpCodes.Ldc_I4_3)
+ case 4 => code.Emit(OpCodes.Ldc_I4_4)
+ case 5 => code.Emit(OpCodes.Ldc_I4_5)
+ case 6 => code.Emit(OpCodes.Ldc_I4_6)
+ case 7 => code.Emit(OpCodes.Ldc_I4_7)
+ case 8 => code.Emit(OpCodes.Ldc_I4_8)
+ case _ =>
+ if (value >= -128 && value <= 127)
+ code.Emit(OpCodes.Ldc_I4_S, value)
+ else
+ code.Emit(OpCodes.Ldc_I4, value)
+ }
+
+ def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) =
+ if (loadAddr) {
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldarga_S, i)
+ else
+ code.Emit(OpCodes.Ldarga, i)
+ } else {
+ i match {
+ case 0 => code.Emit(OpCodes.Ldarg_0)
+ case 1 => code.Emit(OpCodes.Ldarg_1)
+ case 2 => code.Emit(OpCodes.Ldarg_2)
+ case 3 => code.Emit(OpCodes.Ldarg_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldarg_S, i)
+ else
+ code.Emit(OpCodes.Ldarg, i)
+ }
+ }
+
+ def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) =
+ if (loadAddr) {
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldloca_S, localBuilders(local))
+ else
+ code.Emit(OpCodes.Ldloca, localBuilders(local))
+ } else {
+ i match {
+ case 0 => code.Emit(OpCodes.Ldloc_0)
+ case 1 => code.Emit(OpCodes.Ldloc_1)
+ case 2 => code.Emit(OpCodes.Ldloc_2)
+ case 3 => code.Emit(OpCodes.Ldloc_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldloc_S, localBuilders(local))
+ else
+ code.Emit(OpCodes.Ldloc, localBuilders(local))
+ }
+ }
+
+ ////////////////////// branches ///////////////////////
+
+ /** Returns a Triple (Boolean, Boolean, Option[Label])
+ * - whether the jump leaves some exception block (try / catch / finally)
+ * - whether it leaves a finally handler (finally block, but not it's try / catch)
+ * - a label where to jump for leaving the finally handler
+ * . None to leave directly using `endfinally`
+ * . Some(label) to emit `leave label` (for try / catch inside a finally handler)
+ */
+ def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) =
+ if (currentHandlers.isEmpty) (false, false, None)
+ else {
+ val h = currentHandlers.head
+ val leaveHead = { h.covers(from) != h.covers(to) ||
+ h.blocks.contains(from) != h.blocks.contains(to) }
+ if (leaveHead) {
+ // we leave the innermost exception block.
+ // find out if we also leave som e `finally` handler
+ currentHandlers.find(e => {
+ e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to)
+ }) match {
+ case Some(finallyHandler) =>
+ if (h == finallyHandler) {
+ // the finally handler is the innermost, so we can emit `endfinally` directly
+ (true, true, None)
+ } else {
+ // we need to `Leave` to the `endfinally` of the next outer finally handler
+ val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel())
+ (true, true, Some(l))
+ }
+ case None =>
+ (true, false, None)
+ }
+ } else (false, false, None)
+ }
+
+ def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock,
+ next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) {
+ val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success)
+ val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure)
+
+ if (sLeaveHandler || fLeaveHandler) {
+ val sLabelOpt = if (sLeaveHandler) {
+ val leaveSLabel = mcode.DefineLabel()
+ emitBrFun(cond, leaveSLabel)
+ Some(leaveSLabel)
+ } else {
+ emitBrFun(cond, labels(success))
+ None
+ }
+
+ if (fLeaveHandler) {
+ if (fLeaveFinally) {
+ if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
+ mcode.Emit(OpCodes.Leave, labels(failure))
+ } else
+ mcode.Emit(OpCodes.Br, labels(failure))
+
+ sLabelOpt.map(l => {
+ mcode.MarkLabel(l)
+ if (sLeaveFinally) {
+ if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
+ mcode.Emit(OpCodes.Leave, labels(success))
+ })
+ } else {
+ if (next == success) {
+ emitBrFun(cond.negate, labels(failure))
+ } else {
+ emitBrFun(cond, labels(success))
+ if (next != failure) {
+ mcode.Emit(OpCodes.Br, labels(failure))
+ }
+ }
+ }
+ }
+
+ def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) {
+ condition match {
+ case EQ => mcode.Emit(OpCodes.Beq, dest)
+ case NE => mcode.Emit(OpCodes.Bne_Un, dest)
+ case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest)
+ case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest)
+ case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest)
+ case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest)
+ }
+ }
+
+ def emitBrBool(cond: TestOp, dest: Label) {
+ cond match {
+ // EQ -> Brfalse, NE -> Brtrue; this is because we come from
+ // a CZJUMP. If the value on the stack is 0 (e.g. a boolean
+ // method returned false), and we are in the case EQ, then
+ // we need to emit Brfalse (EQ Zero means false). vice versa
+ case EQ => mcode.Emit(OpCodes.Brfalse, dest)
+ case NE => mcode.Emit(OpCodes.Brtrue, dest)
+ }
+ }
+
+ ////////////////////// local vars ///////////////////////
+
+ /**
+ * Compute the indexes of each local variable of the given
+ * method.
+ */
+ def computeLocalVarsIndex(m: IMethod) {
+ var idx = if (m.symbol.isStaticMember) 0 else 1
+
+ val params = m.params
+ for (l <- params) {
+ debuglog("Index value for parameter " + l + ": " + idx)
+ l.index = idx
+ idx += 1 // sizeOf(l.kind)
+ }
+
+ val locvars = m.locals filterNot (params contains)
+ idx = 0
+
+ for (l <- locvars) {
+ debuglog("Index value for local variable " + l + ": " + idx)
+ l.index = idx
+ idx += 1 // sizeOf(l.kind)
+ }
+
+ }
+
+ ////////////////////// Utilities ////////////////////////
+
+ /** Return the a name of this symbol that can be used on the .NET
+ * platform. It removes spaces from names.
+ *
+ * Special handling: scala.All and scala.AllRef are 'erased' to
+ * scala.All$ and scala.AllRef$. This is needed because they are
+ * not real classes, and they mean 'abrupt termination upon evaluation
+ * of that expression' or 'null' respectively. This handling is
+ * done already in GenICode, but here we need to remove references
+ * from method signatures to these types, because such classes can
+ * not exist in the classpath: the type checker will be very confused.
+ */
+ def msilName(sym: Symbol): String = {
+ val suffix = sym.moduleSuffix
+ // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class)
+
+ if (sym == definitions.NothingClass)
+ return "scala.runtime.Nothing$"
+ else if (sym == definitions.NullClass)
+ return "scala.runtime.Null$"
+
+ (if (sym.isClass || (sym.isModule && !sym.isMethod)) {
+ if (sym.isNestedClass) sym.simpleName
+ else sym.fullName
+ } else
+ sym.simpleName.toString.trim()) + suffix
+ }
+
+
+ ////////////////////// flags ///////////////////////
+
+ def msilTypeFlags(sym: Symbol): Int = {
+ var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass
+
+ if(sym.isNestedClass) {
+ mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic)
+ } else {
+ mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public)
+ }
+ mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0)
+ mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class)
+ mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0)
+
+ sym.annotations foreach { a => a match {
+ case AnnotationInfo(SerializableAttr, _, _) =>
+ // TODO: add the Serializable TypeAttribute also if the annotation
+ // System.SerializableAttribute is present (.net annotation, not scala)
+ // Best way to do it: compare with
+ // definitions.getClass("System.SerializableAttribute").tpe
+ // when frontend available
+ mf = mf | TypeAttributes.Serializable
+ case _ => ()
+ }}
+
+ mf
+ // static: not possible (or?)
+ }
+
+ def msilMethodFlags(sym: Symbol): Short = {
+ var mf: Int = MethodAttributes.HideBySig |
+ (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private
+ else MethodAttributes.Public)
+
+ if (!sym.isClassConstructor) {
+ if (sym.isStaticMember)
+ mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ...
+ else {
+ mf = mf | MethodAttributes.Virtual
+ if (sym.isFinal && !getType(sym.owner).IsInterface)
+ mf = mf | MethodAttributes.Final
+ if (sym.isDeferred || getType(sym.owner).IsInterface)
+ mf = mf | MethodAttributes.Abstract
+ }
+ }
+
+ 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
+ }
+
+ def msilFieldFlags(sym: Symbol): Short = {
+ var mf: Int =
+ if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private
+ else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem
+ else FieldAttributes.Public
+
+ if (sym hasFlag Flags.FINAL)
+ mf = mf | FieldAttributes.InitOnly
+
+ if (sym.isStaticMember)
+ mf = mf | FieldAttributes.Static
+
+ // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net
+ // TODO: add this annotation also if the class has the custom attribute
+ // System.NotSerializedAttribute
+ sym.annotations.foreach( a => a match {
+ case AnnotationInfo(TransientAtt, _, _) =>
+ mf = mf | FieldAttributes.NotSerialized
+ case _ => ()
+ })
+
+ mf.toShort
+ }
+
+ ////////////////////// builders, types ///////////////////////
+
+ var entryPoint: Symbol = _
+
+ val notInitializedModules = mutable.HashSet[Symbol]()
+
+ // TODO: create fields also in def createType, and not in genClass,
+ // add a getField method (it only works as it is because fields never
+ // accessed from outside a class)
+
+ val localBuilders = mutable.HashMap[Local, LocalBuilder]()
+
+ private[GenMSIL] def findEntryPoint(cls: IClass) {
+
+ def isEntryPoint(sym: Symbol):Boolean = {
+ if (isStaticModule(sym.owner) && msilName(sym) == "main")
+ if (sym.tpe.paramTypes.length == 1) {
+ toTypeKind(sym.tpe.paramTypes(0)) match {
+ case ARRAY(elem) =>
+ if (elem.toType.typeSymbol == definitions.StringClass) {
+ return true
+ }
+ case _ => ()
+ }
+ }
+ false
+ }
+
+ if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead
+ val entryclass = opt.showClass.get.toString
+ val cfn = cls.symbol.fullName
+ if(cfn == entryclass) {
+ for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol }
+ if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) }
+ }
+ }
+
+ if (firstSourceName == "")
+ if (cls.symbol.sourceFile != null) // is null for nested classes
+ firstSourceName = cls.symbol.sourceFile.name
+ }
+
+ // #####################################################################
+ // get and create types
+
+ private def msilType(t: TypeKind): MsilType = (t: @unchecked) match {
+ case UNIT => MVOID
+ case BOOL => MBOOL
+ case BYTE => MBYTE
+ case SHORT => MSHORT
+ case CHAR => MCHAR
+ case INT => MINT
+ case LONG => MLONG
+ case FLOAT => MFLOAT
+ case DOUBLE => MDOUBLE
+ case REFERENCE(cls) => getType(cls)
+ case ARRAY(elem) =>
+ msilType(elem) match {
+ // For type builders, cannot call "clrTypes.mkArrayType" because this looks up
+ // the type "tp" in the assembly (not in the HashMap "types" of the backend).
+ // This can fail for nested types because the builders are not complete yet.
+ case tb: TypeBuilder => tb.MakeArrayType()
+ case tp: MsilType => clrTypes.mkArrayType(tp)
+ }
+ }
+
+ private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe))
+
+ private def msilParamTypes(sym: Symbol): Array[MsilType] = {
+ sym.tpe.paramTypes.map(msilType).toArray
+ }
+
+ def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym)))
+
+ /**
+ * Get an MSIL type from a symbol. First look in the clrTypes.types map, then
+ * lookup the name using clrTypes.getType
+ */
+ def getTypeOpt(sym: Symbol): Option[MsilType] = {
+ val tmp = types.get(sym)
+ tmp match {
+ case typ @ Some(_) => typ
+ case None =>
+ def typeString(sym: Symbol): String = {
+ val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName
+ else sym.fullName
+ if (sym.isModuleClass && !sym.isTrait) s + "$" else s
+ }
+ val name = typeString(sym)
+ val typ = clrTypes.getType(name)
+ if (typ == null)
+ None
+ else {
+ types(sym) = typ
+ Some(typ)
+ }
+ }
+ }
+
+ def mapType(sym: Symbol, mType: MsilType) {
+ assert(mType != null, showsym(sym))
+ types(sym) = mType
+ }
+
+ def createTypeBuilder(iclass: IClass) {
+ /**
+ * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise
+ * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)).
+ */
+ def msilTypeFromSym(sym: Symbol): MsilType = {
+ types.get(sym).getOrElse {
+ classes.get(sym) match {
+ case Some(iclass) =>
+ msilTypeBuilderFromSym(sym)
+ case None =>
+ getType(sym)
+ }
+ }
+ }
+
+ def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = {
+ if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){
+ val iclass = classes(sym)
+ assert(iclass != null)
+ createTypeBuilder(iclass)
+ }
+ types(sym).asInstanceOf[TypeBuilder]
+ }
+
+ val sym = iclass.symbol
+ if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])
+ return
+
+ def isInterface(s: Symbol) = s.isTrait && !s.isImplClass
+ val parents: List[Type] =
+ if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe)
+ else sym.info.parents.distinct
+
+ val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol)
+ debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType)
+
+ val interfaces: Array[MsilType] =
+ parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray
+ if (parents.length > 1) {
+ if (settings.debug.value) {
+ log("interfaces:")
+ for (i <- 0.until(interfaces.length)) {
+ log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i))
+ }
+ }
+ }
+
+ val tBuilder = if (sym.isNestedClass) {
+ val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder]
+ ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces)
+ } else {
+ mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces)
+ }
+ mapType(sym, tBuilder)
+ } // createTypeBuilder
+
+ def createClassMembers(iclass: IClass) {
+ try {
+ createClassMembers0(iclass)
+ }
+ catch {
+ case e: Throwable =>
+ java.lang.System.err.println(showsym(iclass.symbol))
+ java.lang.System.err.println("with methods = " + iclass.methods)
+ throw e
+ }
+ }
+
+ def createClassMembers0(iclass: IClass) {
+
+ val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder]
+
+ for (ifield <- iclass.fields) {
+ val sym = ifield.symbol
+ debuglog("Adding field: " + sym.fullName)
+
+ var attributes = msilFieldFlags(sym)
+ val fieldTypeWithCustomMods =
+ new PECustomMod(msilType(sym.tpe),
+ customModifiers(sym.annotations))
+ val fBuilder = mtype.DefineField(msilName(sym),
+ fieldTypeWithCustomMods,
+ attributes)
+ fields(sym) = fBuilder
+ 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.lastBlock
+ val lastBlock = m.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
+ debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " +
+ sym.owner.fullName + "::" + sym.name)
+
+ val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder]
+ assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType)
+ var paramTypes = msilParamTypes(sym)
+ val attr = msilMethodFlags(sym)
+
+ if (m.symbol.isClassConstructor) {
+ val constr =
+ ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes)
+ for (i <- 0.until(paramTypes.length)) {
+ constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym))
+ }
+ mapConstructor(sym, constr)
+ addAttributes(constr, sym.annotations)
+ } else {
+ var resType = msilType(m.returnType)
+ val method =
+ ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes)
+ for (i <- 0.until(paramTypes.length)) {
+ method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym))
+ }
+ if (!methods.contains(sym))
+ mapMethod(sym, method)
+ addAttributes(method, sym.annotations)
+ debuglog("\t created MethodBuilder " + method)
+ }
+ }
+ } // method builders created for non-array iclass
+
+ if (isStaticModule(iclass.symbol)) {
+ addModuleInstanceField(iclass.symbol)
+ notInitializedModules += iclass.symbol
+ if (iclass.lookupStaticCtor.isEmpty) {
+ addStaticInit(iclass.symbol)
+ }
+ }
+
+ } // createClassMembers0
+
+ private def isTopLevelModule(sym: Symbol): Boolean =
+ atPhase (currentRun.refchecksPhase) {
+ sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass
+ }
+
+ // if the module is lifted it does not need to be initialized in
+ // its static constructor, and the MODULE$ field is not required.
+ // the outer class will care about it.
+ private def isStaticModule(sym: Symbol): Boolean = {
+ // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added
+ // 'sym.isStatic'. -> no longer compatible without skipping flatten!
+ sym.isModuleClass && sym.isStatic && !sym.isImplClass
+ }
+
+ private def isCloneable(sym: Symbol): Boolean = {
+ !sym.annotations.forall( a => a match {
+ case AnnotationInfo(CloneableAttr, _, _) => false
+ case _ => true
+ })
+ }
+
+ private def addModuleInstanceField(sym: Symbol) {
+ debuglog("Adding Module-Instance Field for " + showsym(sym))
+ val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
+ val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME,
+ tBuilder,
+ (FieldAttributes.Public |
+ //FieldAttributes.InitOnly |
+ FieldAttributes.Static).toShort)
+ fields(sym) = fb
+ }
+
+
+ // the symbol may be a object-symbol (module-symbol), or a module-class-symbol
+ private def getModuleInstanceField(sym: Symbol): FieldInfo = {
+ assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym))
+
+ // when called by LOAD_MODULE, the corresponding type maybe doesn't
+ // exist yet -> make a getType
+ val moduleClassSym = if (sym.isModule) sym.moduleClass else sym
+
+ // TODO: get module field for modules not defined in the
+ // source currently compiling (e.g. Console)
+
+ fields get moduleClassSym match {
+ case Some(sym) => sym
+ case None =>
+ //val mclass = types(moduleClassSym)
+ 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
+ mfield
+ }
+
+ //fields(moduleClassSym)
+ }
+
+ def nestingAwareFullClassname(csym: Symbol) : String = {
+ val suffix = csym.moduleSuffix
+ val res = if (csym.isNestedClass)
+ nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName
+ else
+ csym.fullName
+ res + suffix
+ }
+
+ /** 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
+ * in the MODULE$ field right after the super call.
+ */
+ private def addStaticInit(sym: Symbol) {
+ val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
+
+ val staticInit = tBuilder.DefineConstructor(
+ (MethodAttributes.Static | MethodAttributes.Public).toShort,
+ CallingConventions.Standard,
+ MsilType.EmptyTypes)
+
+ val sicode = staticInit.GetILGenerator()
+
+ val instanceConstructor = constructors(sym.primaryConstructor)
+
+ // there are no constructor parameters. assuming the constructor takes no parameter
+ // is fine: we call (in the static constructor) the constructor of the module class,
+ // which takes no arguments - an object definition cannot take constructor arguments.
+ sicode.Emit(OpCodes.Newobj, instanceConstructor)
+ // the stsfld is done in the instance constructor, just after the super call.
+ sicode.Emit(OpCodes.Pop)
+
+ sicode.Emit(OpCodes.Ret)
+ }
+
+ private def generateMirrorClass(sym: Symbol) {
+ val tBuilder = getType(sym)
+ assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym)
+ debuglog("Dumping mirror class for object: " + sym)
+ val moduleName = msilName(sym)
+ val mirrorName = moduleName.substring(0, moduleName.length() - 1)
+ val mirrorTypeBuilder = mmodule.DefineType(mirrorName,
+ TypeAttributes.Class |
+ TypeAttributes.Public |
+ TypeAttributes.Sealed,
+ MOBJECT,
+ MsilType.EmptyTypes)
+
+ val iclass = classes(sym)
+
+ for (m <- sym.tpe.nonPrivateMembers
+ if m.owner != definitions.ObjectClass && !m.isProtected &&
+ m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase &&
+ !m.isDeferred)
+ {
+ debuglog(" Mirroring method: " + m)
+ val paramTypes = msilParamTypes(m)
+ val paramNames: Array[String] = new Array[String](paramTypes.length)
+ for (i <- 0 until paramTypes.length)
+ paramNames(i) = "x_" + i
+
+ // CHECK: verify if getMethodName is better than msilName
+ val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m),
+ (MethodAttributes.Public |
+ MethodAttributes.Static).toShort,
+ msilType(m.tpe.resultType),
+ paramTypes)
+
+ var i = 0
+ while (i < paramTypes.length) {
+ mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i))
+ i += 1
+ }
+
+ val mirrorCode = mirrorMethod.GetILGenerator()
+ mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym))
+ val mInfo = getMethod(m)
+ for (paramidx <- 0.until(paramTypes.length)) {
+ val mInfoParams = mInfo.GetParameters
+ val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef
+ loadArg(mirrorCode, loadAddr)(paramidx)
+ }
+
+ mirrorCode.Emit(OpCodes.Callvirt, getMethod(m))
+ mirrorCode.Emit(OpCodes.Ret)
+ }
+
+ addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder)
+
+ mirrorTypeBuilder.CreateType()
+ mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path)
+ }
+
+
+ // #####################################################################
+ // delegate callers
+
+ var delegateCallers: TypeBuilder = _
+ var nbDelegateCallers: Int = 0
+
+ private def initDelegateCallers() = {
+ delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public |
+ TypeAttributes.Sealed)
+ }
+
+ private def createDelegateCaller(functionType: Type, delegateType: Type) = {
+ if (delegateCallers == null)
+ initDelegateCallers()
+ // create a field an store the function-object
+ val mFunctionType: MsilType = msilType(functionType)
+ val anonfunField: FieldBuilder = delegateCallers.DefineField(
+ "$anonfunField$$" + nbDelegateCallers, mFunctionType,
+ (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort)
+ mcode.Emit(OpCodes.Stsfld, anonfunField)
+
+
+ // create the static caller method and the delegate object
+ val (params, returnType) = delegateType.member(nme.apply).tpe match {
+ case MethodType(delParams, delReturn) => (delParams, delReturn)
+ case _ => abort("not a delegate type: " + delegateType)
+ }
+ val caller: MethodBuilder = delegateCallers.DefineMethod(
+ "$delegateCaller$$" + nbDelegateCallers,
+ (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort,
+ msilType(returnType), (params map (_.tpe)).map(msilType).toArray)
+ for (i <- 0 until params.length)
+ caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol
+ val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR))
+ mcode.Emit(OpCodes.Ldnull)
+ mcode.Emit(OpCodes.Ldftn, caller)
+ mcode.Emit(OpCodes.Newobj, delegCtor)
+
+
+ // create the static caller method body
+ val functionApply: MethodInfo = getMethod(functionType.member(nme.apply))
+ val dcode: ILGenerator = caller.GetILGenerator()
+ dcode.Emit(OpCodes.Ldsfld, anonfunField)
+ for (i <- 0 until params.length) {
+ loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i)
+ emitBox(dcode, toTypeKind(params(i).tpe))
+ }
+ dcode.Emit(OpCodes.Callvirt, functionApply)
+ emitUnbox(dcode, toTypeKind(returnType))
+ dcode.Emit(OpCodes.Ret)
+
+ nbDelegateCallers = nbDelegateCallers + 1
+
+ } //def createDelegateCaller
+
+ def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match {
+ // doesn't make sense, unit as parameter..
+ case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit)
+ case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE =>
+ code.Emit(OpCodes.Box, msilType(boxType))
+ case REFERENCE(cls) if clrTypes.isValueType(cls) =>
+ code.Emit(OpCodes.Box, (msilType(boxType)))
+ case REFERENCE(_) | ARRAY(_) =>
+ warning("Tried to BOX a non-valuetype.")
+ ()
+ }
+
+ def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match {
+ case UNIT => code.Emit(OpCodes.Pop)
+ /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods)
+ behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods
+ (case null: that's easy, case boxed: track changes to unboxBlaBla)
+ (2) See also: asInstanceOf to cast from Any to number,
+ tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */
+ case BOOL => code.Emit(OpCodes.Call, toBool)
+ case BYTE => code.Emit(OpCodes.Call, toSByte)
+ case SHORT => code.Emit(OpCodes.Call, toShort)
+ case CHAR => code.Emit(OpCodes.Call, toChar)
+ case INT => code.Emit(OpCodes.Call, toInt)
+ case LONG => code.Emit(OpCodes.Call, toLong)
+ case FLOAT => code.Emit(OpCodes.Call, toFloat)
+ case DOUBLE => code.Emit(OpCodes.Call, toDouble)
+ case REFERENCE(cls) if clrTypes.isValueType(cls) =>
+ code.Emit(OpCodes.Unbox, msilType(boxType))
+ code.Emit(OpCodes.Ldobj, msilType(boxType))
+ case REFERENCE(_) | ARRAY(_) =>
+ warning("Tried to UNBOX a non-valuetype.")
+ ()
+ }
+
+ // #####################################################################
+ // get and create methods / constructors
+
+ def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match {
+ case Some(constr) => constr
+ case None =>
+ val mClass = getType(sym.owner)
+ val constr = mClass.GetConstructor(msilParamTypes(sym))
+ if (constr eq null) {
+ java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name)
+ java.lang.System.out.println("scope = " + sym.owner.tpe.decls)
+ abort(sym.fullName)
+ }
+ else {
+ mapConstructor(sym, constr)
+ constr
+ }
+ }
+
+ def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = {
+ constructors(sym) = cInfo
+ }
+
+ private def getMethod(sym: Symbol): MethodInfo = {
+
+ methods.get(sym) match {
+ case Some(method) => method
+ case None =>
+ val mClass = getType(sym.owner)
+ try {
+ val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym),
+ msilType(sym.tpe.resultType))
+ if (method eq null) {
+ java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym))
+ java.lang.System.out.println("scope = " + sym.owner.tpe.decls)
+ abort(sym.fullName)
+ }
+ else {
+ mapMethod(sym, method)
+ method
+ }
+ }
+ catch {
+ case e: Exception =>
+ Console.println("While looking up " + mClass + "::" + sym.nameString)
+ Console.println("\t" + showsym(sym))
+ throw e
+ }
+ }
+ }
+
+ /*
+ * add a mapping between sym and mInfo
+ */
+ private def mapMethod(sym: Symbol, mInfo: MethodInfo) {
+ assert (mInfo != null, mInfo)
+ methods(sym) = mInfo
+ }
+
+ /*
+ * add mapping between sym and method with newName, paramTypes of newClass
+ */
+ private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) {
+ val methodInfo = newClass.GetMethod(newName, paramTypes)
+ assert(methodInfo != null, "Can't find mapping for " + sym + " -> " +
+ newName + "(" + paramTypes + ")")
+ mapMethod(sym, methodInfo)
+ if (methodInfo.IsStatic)
+ dynToStatMapped += sym
+ }
+
+ /*
+ * add mapping between method with name and paramTypes of clazz to
+ * method with newName and newParamTypes of newClass (used for instance
+ * for "wait")
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name, paramTypes: Array[Type],
+ newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) {
+ val methodSym = lookupMethod(clazz, name, paramTypes)
+ assert(methodSym != null, "cannot find method " + name + "(" +
+ paramTypes + ")" + " in class " + clazz)
+ mapMethod(methodSym, newClass, newName, newParamTypes)
+ }
+
+ /*
+ * add mapping for member with name and paramTypes to member
+ * newName of newClass (same parameters)
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name, paramTypes: Array[Type],
+ newClass: MsilType, newName: String) {
+ mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType)
+ }
+
+ /*
+ * add mapping for all methods with name of clazz to the corresponding
+ * method (same parameters) with newName of newClass
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name,
+ newClass: MsilType, newName: String) {
+ val memberSym: Symbol = clazz.tpe.member(name)
+ memberSym.tpe match {
+ // alternatives: List[Symbol]
+ case OverloadedType(_, alternatives) =>
+ alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s)))
+
+ // paramTypes: List[Type], resType: Type
+ case MethodType(params, resType) =>
+ mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym))
+
+ case _ =>
+ abort("member not found: " + clazz + ", " + name)
+ }
+ }
+
+
+ /*
+ * find the method in clazz with name and paramTypes
+ */
+ private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = {
+ val memberSym = clazz.tpe.member(name)
+ memberSym.tpe match {
+ case OverloadedType(_, alternatives) =>
+ alternatives.find(s => {
+ var i: Int = 0
+ var typesOK: Boolean = true
+ if (paramTypes.length == s.tpe.paramTypes.length) {
+ while(i < paramTypes.length) {
+ if (paramTypes(i) != s.tpe.paramTypes(i))
+ typesOK = false
+ i += 1
+ }
+ } else {
+ typesOK = false
+ }
+ typesOK
+ }) match {
+ case Some(sym) => sym
+ case None => abort("member of " + clazz + ", " + name + "(" +
+ paramTypes + ") not found")
+ }
+
+ case MethodType(_, _) => memberSym
+
+ case _ => abort("member not found: " + name + " of " + clazz)
+ }
+ }
+
+ private def showsym(sym: Symbol): String = (sym.toString +
+ "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym +
+ "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner
+ )
+
+ } // class BytecodeGenerator
+
+} // class GenMSIL
+*/ \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala
index 2982812fdd..aeaa1b759b 100644
--- a/src/compiler/scala/tools/nsc/io/MsilFile.scala
+++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala
@@ -1,18 +1,19 @@
-// /* NSC -- new Scala compiler
-// * Copyright 2005-2011 LAMP/EPFL
-// * @author Paul Phillips
-// */
-//
-// package scala.tools.nsc
-// package io
-//
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
// import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ }
-//
-// /** This class wraps an MsilType. It exists only so
-// * ClassPath can treat all of JVM/MSIL/bin/src files
-// * uniformly, as AbstractFiles.
-// */
-// class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) {
-// }
-//
-// object NoMsilFile extends MsilFile(null) { }
+
+/** This class wraps an MsilType. It exists only so
+ * ClassPath can treat all of JVM/MSIL/bin/src files
+ * uniformly, as AbstractFiles.
+ */
+class MsilFile /* (val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) {
+}
+
+object NoMsilFile extends MsilFile(null) { }
+*/ \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala
index 4346cb6f8d..469f7ce3ab 100644
--- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala
+++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala
@@ -1,137 +1,138 @@
-// /* NSC -- new scala compiler
-// * Copyright 2004-2011 LAMP/EPFL
-// */
-//
-//
-// package scala.tools.nsc
-// package symtab
-// package clr
-//
+/* NSC -- new scala compiler
+ * Copyright 2004-2011 LAMP/EPFL
+ */
+
+
+package scala.tools.nsc
+package symtab
+package clr
+
// import java.io.File
// import java.util.{Comparator, StringTokenizer}
// import scala.util.Sorting
// import ch.epfl.lamp.compiler.msil._
// import scala.collection.{ mutable, immutable }
// import scala.tools.nsc.util.{Position, NoPosition}
-//
-// /**
-// * Collects all types from all reference assemblies.
-// */
-// abstract class CLRTypes {
-//
-// val global: Global
-// import global.Symbol
-// import global.definitions
-//
-// //##########################################################################
-//
-// var BYTE: Type = _
-// var UBYTE: Type = _
-// var SHORT: Type = _
-// var USHORT: Type = _
-// var CHAR: Type = _
-// var INT: Type = _
-// var UINT: Type = _
-// var LONG: Type = _
-// var ULONG: Type = _
-// var FLOAT: Type = _
-// var DOUBLE: Type = _
-// var BOOLEAN: Type = _
-// var VOID: Type = _
-// var ENUM: Type = _
-// var DELEGATE: Type = _
-//
-// var OBJECT: Type = _
-// var STRING: Type = _
-// var STRING_ARRAY: Type = _
-//
-// var VALUE_TYPE: Type = _
-//
-// var SCALA_SYMTAB_ATTR: Type = _
-// var SYMTAB_CONSTR: ConstructorInfo = _
-// var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _
-//
-// var DELEGATE_COMBINE: MethodInfo = _
-// var DELEGATE_REMOVE: MethodInfo = _
-//
-// val types: mutable.Map[Symbol,Type] = new mutable.HashMap
-// val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap
-// val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap
-// val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap
-// val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap
-// val addressOfViews = new mutable.HashSet[Symbol]
-// val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap
-//
-// def isAddressOf(msym : Symbol) = addressOfViews.contains(msym)
-//
-// def isNonEnumValuetype(cls: Symbol) = {
-// val msilTOpt = types.get(cls)
-// val res = msilTOpt.isDefined && {
-// val msilT = msilTOpt.get
-// msilT.IsValueType && !msilT.IsEnum
-// }
-// res
-// }
-//
-// def isValueType(cls: Symbol): Boolean = {
-// val opt = types.get(cls)
-// opt.isDefined && opt.get.IsValueType
-// }
-//
-// def init() = try { // initialize
-// // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling
-// // Assembly.LoadFrom("mscorlib.dll"), so this type should be found
-// Type.initMSCORLIB(getTypeSafe("System.String").Assembly)
-//
-// BYTE = getTypeSafe("System.SByte")
-// UBYTE = getTypeSafe("System.Byte")
-// CHAR = getTypeSafe("System.Char")
-// SHORT = getTypeSafe("System.Int16")
-// USHORT = getTypeSafe("System.UInt16")
-// INT = getTypeSafe("System.Int32")
-// UINT = getTypeSafe("System.UInt32")
-// LONG = getTypeSafe("System.Int64")
-// ULONG = getTypeSafe("System.UInt64")
-// FLOAT = getTypeSafe("System.Single")
-// DOUBLE = getTypeSafe("System.Double")
-// BOOLEAN = getTypeSafe("System.Boolean")
-// VOID = getTypeSafe("System.Void")
-// ENUM = getTypeSafe("System.Enum")
-// DELEGATE = getTypeSafe("System.MulticastDelegate")
-//
-// OBJECT = getTypeSafe("System.Object")
-// STRING = getTypeSafe("System.String")
-// STRING_ARRAY = getTypeSafe("System.String[]")
-// VALUE_TYPE = getTypeSafe("System.ValueType")
-//
-// SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute")
-// val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]"))
-// SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray)
-// SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes)
-//
-// val delegate: Type = getTypeSafe("System.Delegate")
-// val dargs: Array[Type] = Array(delegate, delegate)
-// DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs)
-// DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs)
-// }
-// catch {
-// case e: RuntimeException =>
-// Console.println(e.getMessage)
-// throw e
-// }
-//
-// //##########################################################################
-// // type mapping and lookup
-//
-// def getType(name: String): Type = Type.GetType(name)
-//
-// def getTypeSafe(name: String): Type = {
-// val t = Type.GetType(name)
-// assert(t != null, name)
-// t
-// }
-//
-// def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]")
-//
-// def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE }
-// } // CLRTypes
+
+/**
+ * Collects all types from all reference assemblies.
+ */
+abstract class CLRTypes /*{
+
+ val global: Global
+ import global.Symbol
+ import global.definitions
+
+ //##########################################################################
+
+ var BYTE: Type = _
+ var UBYTE: Type = _
+ var SHORT: Type = _
+ var USHORT: Type = _
+ var CHAR: Type = _
+ var INT: Type = _
+ var UINT: Type = _
+ var LONG: Type = _
+ var ULONG: Type = _
+ var FLOAT: Type = _
+ var DOUBLE: Type = _
+ var BOOLEAN: Type = _
+ var VOID: Type = _
+ var ENUM: Type = _
+ var DELEGATE: Type = _
+
+ var OBJECT: Type = _
+ var STRING: Type = _
+ var STRING_ARRAY: Type = _
+
+ var VALUE_TYPE: Type = _
+
+ var SCALA_SYMTAB_ATTR: Type = _
+ var SYMTAB_CONSTR: ConstructorInfo = _
+ var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _
+
+ var DELEGATE_COMBINE: MethodInfo = _
+ var DELEGATE_REMOVE: MethodInfo = _
+
+ val types: mutable.Map[Symbol,Type] = new mutable.HashMap
+ val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap
+ val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap
+ val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap
+ val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap
+ val addressOfViews = new mutable.HashSet[Symbol]
+ val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap
+
+ def isAddressOf(msym : Symbol) = addressOfViews.contains(msym)
+
+ def isNonEnumValuetype(cls: Symbol) = {
+ val msilTOpt = types.get(cls)
+ val res = msilTOpt.isDefined && {
+ val msilT = msilTOpt.get
+ msilT.IsValueType && !msilT.IsEnum
+ }
+ res
+ }
+
+ def isValueType(cls: Symbol): Boolean = {
+ val opt = types.get(cls)
+ opt.isDefined && opt.get.IsValueType
+ }
+
+ def init() = try { // initialize
+ // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling
+ // Assembly.LoadFrom("mscorlib.dll"), so this type should be found
+ Type.initMSCORLIB(getTypeSafe("System.String").Assembly)
+
+ BYTE = getTypeSafe("System.SByte")
+ UBYTE = getTypeSafe("System.Byte")
+ CHAR = getTypeSafe("System.Char")
+ SHORT = getTypeSafe("System.Int16")
+ USHORT = getTypeSafe("System.UInt16")
+ INT = getTypeSafe("System.Int32")
+ UINT = getTypeSafe("System.UInt32")
+ LONG = getTypeSafe("System.Int64")
+ ULONG = getTypeSafe("System.UInt64")
+ FLOAT = getTypeSafe("System.Single")
+ DOUBLE = getTypeSafe("System.Double")
+ BOOLEAN = getTypeSafe("System.Boolean")
+ VOID = getTypeSafe("System.Void")
+ ENUM = getTypeSafe("System.Enum")
+ DELEGATE = getTypeSafe("System.MulticastDelegate")
+
+ OBJECT = getTypeSafe("System.Object")
+ STRING = getTypeSafe("System.String")
+ STRING_ARRAY = getTypeSafe("System.String[]")
+ VALUE_TYPE = getTypeSafe("System.ValueType")
+
+ SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute")
+ val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]"))
+ SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray)
+ SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes)
+
+ val delegate: Type = getTypeSafe("System.Delegate")
+ val dargs: Array[Type] = Array(delegate, delegate)
+ DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs)
+ DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs)
+ }
+ catch {
+ case e: RuntimeException =>
+ Console.println(e.getMessage)
+ throw e
+ }
+
+ //##########################################################################
+ // type mapping and lookup
+
+ def getType(name: String): Type = Type.GetType(name)
+
+ def getTypeSafe(name: String): Type = {
+ val t = Type.GetType(name)
+ assert(t != null, name)
+ t
+ }
+
+ def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]")
+
+ def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE }
+} // CLRTypes
+*/ \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
index 82d1dd6bc3..d16c9980d5 100644
--- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
@@ -1,851 +1,852 @@
-// /* NSC -- new scala compiler
-// * Copyright 2004-2011 LAMP/EPFL
-// */
-//
-// package scala.tools.nsc
-// package symtab
-// package clr
-//
+/* NSC -- new scala compiler
+ * Copyright 2004-2011 LAMP/EPFL
+ */
+
+package scala.tools.nsc
+package symtab
+package clr
+
// import java.io.IOException
// import io.MsilFile
// import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _}
// import scala.collection.{ mutable, immutable }
// import scala.reflect.internal.pickling.UnPickler
// import ch.epfl.lamp.compiler.msil.Type.TMVarUsage
-//
-// /**
-// * @author Nikolay Mihaylov
-// */
-// abstract class TypeParser {
-//
-// val global: Global
-//
-// import global._
-// import loaders.clrTypes
-//
-// //##########################################################################
-//
-// private var clazz: Symbol = _
-// private var instanceDefs: Scope = _ // was members
-// private var staticModule: Symbol = _ // was staticsClass
-// private var staticDefs: Scope = _ // was statics
-//
-// protected def statics: Symbol = staticModule.moduleClass
-//
-// protected var busy: Boolean = false // lock to detect recursive reads
-//
-// private implicit def stringToTermName(s: String): TermName = newTermName(s)
-//
-// private object unpickler extends UnPickler {
-// val global: TypeParser.this.global.type = TypeParser.this.global
-// }
-//
-// def parse(typ: MSILType, root: Symbol) {
-//
-// def handleError(e: Throwable) = {
-// if (settings.debug.value) e.printStackTrace() //debug
-// throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")")
-// }
-// assert(!busy)
-// busy = true
-//
-// if (root.isModule) {
-// this.clazz = root.companionClass
-// this.staticModule = root
-// } else {
-// this.clazz = root
-// this.staticModule = root.companionModule
-// }
-// try {
-// parseClass(typ)
-// } catch {
-// case e: FatalError => handleError(e)
-// case e: RuntimeException => handleError(e)
-// }
-// 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,
-// * therefore newTParams is redundant (other than for recording lexical order),
-// * it always contains the same elements as classTParams.value */
-// val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active )
-// val newTParams = new scala.collection.mutable.ListBuffer[Symbol]()
-// val methodTParams = scala.collection.mutable.Map[Int,Symbol]()
-//
-// private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = {
-// val ts = new scala.collection.mutable.ListBuffer[Type]
-// for (cnstrnt <- tvarCILDef.Constraints) {
-// ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right?
-// }
-// TypeBounds.upper(intersectionType(ts.toList, clazz))
-// // TODO variance???
-// }
-//
-// private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type,
-// addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = {
-// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead?
-// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe)
-// val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true);
-// // !!! this used to mutate a mutable map in definitions, but that map became
-// // immutable and this kept "working" with a no-op. So now it's commented out
-// // since I retired the deprecated code which allowed for that bug.
-// //
-// // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym
-//
-// if (isAddressOf) clrTypes.addressOfViews += vmsym
-// vmsym
-// }
-//
-// private def createDefaultConstructor(typ: MSILType) {
-// val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance
-// val declType= typ
-// val method = new ConstructorInfo(declType, attrs, Array[MSILType]())
-// val flags = Flags.JAVA
-// val owner = clazz
-// val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags)
-// val rettype = clazz.tpe
-// val mtype = methodType(Array[MSILType](), rettype);
-// val mInfo = mtype(methodSym)
-// methodSym.setInfo(mInfo)
-// instanceDefs.enter(methodSym);
-// clrTypes.constructors(methodSym) = method
-// }
-//
-// private def parseClass(typ: MSILType) {
-//
-// {
-// val t4c = clrTypes.types.get(clazz)
-// assert(t4c == None || t4c == Some(typ))
-// }
-// clrTypes.types(clazz) = typ
-//
-// {
-// val c4t = clrTypes.sym2type.get(typ)
-// assert(c4t == None || c4t == Some(clazz))
-// }
-// clrTypes.sym2type(typ) = clazz
-//
-// if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {
-// val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false);
-// assert (attrs.length == 1, attrs.length);
-// val a = attrs(0).asInstanceOf[MSILAttribute];
-// assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR);
-// val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]]
-// unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName);
-// val mClass = clrTypes.getType(typ.FullName + "$");
-// if (mClass != null) {
-// clrTypes.types(statics) = mClass;
-// val moduleInstance = mClass.GetField("MODULE$");
-// assert (moduleInstance != null, mClass);
-// clrTypes.fields(statics) = moduleInstance;
-// }
-// return
-// }
-// val flags = translateAttributes(typ)
-//
-// var clazzBoxed : Symbol = NoSymbol
-// var clazzMgdPtr : Symbol = NoSymbol
-//
-// val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum")
-//
-// if(canBeTakenAddressOf) {
-// clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed"))
-// clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr"))
-// clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr
-// /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed,
-// before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */
-// val typMgdPtr = MSILType.mkByRef(typ)
-// clrTypes.types(clazzMgdPtr) = typMgdPtr
-// clrTypes.sym2type(typMgdPtr) = clazzMgdPtr
-// /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance,
-// because there's no metadata-level representation for a "boxed valuetype" */
-// val instanceDefsMgdPtr = newScope
-// val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr)
-// clazzMgdPtr.setFlag(flags)
-// clazzMgdPtr.setInfo(classInfoMgdPtr)
-// }
-//
-// /* 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)
-// val tpsym = clazz.newTypeParameter(tpname)
-// classTParams.put(tvarCILDef.Number, tpsym)
-// newTParams += tpsym
-// // TODO wouldn't the following also be needed later, i.e. during getCLRType
-// tpsym.setInfo(definitions.AnyClass.tpe)
-// }
-// // second pass
-// for (tvarCILDef <- typ.getSortedTVars() ) {
-// 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
-// /* 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 = newScope
-// staticDefs = newScope
-//
-// val classInfoAsInMetadata = {
-// val ifaces: Array[MSILType] = typ.getInterfaces()
-// val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType())
-// else if (typ.IsInterface()) definitions.ObjectClass.tpe
-// else definitions.AnyClass.tpe; // this branch activates for System.Object only.
-// // parents (i.e., base type and interfaces)
-// val parents = new scala.collection.mutable.ListBuffer[Type]()
-// parents += superType
-// for (iface <- ifaces) {
-// parents += getCLRType(iface) // here the variance doesn't matter
-// }
-// // methods, properties, events, fields are entered in a moment
-// if (canBeTakenAddressOf) {
-// val instanceDefsBoxed = newScope
-// ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed)
-// } else
-// ClassInfoType(parents.toList, instanceDefs, clazz)
-// }
-//
-// val staticInfo = ClassInfoType(List(), staticDefs, statics)
-//
-// clazz.setFlag(flags)
-//
-// if (canBeTakenAddressOf) {
-// clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
-// else GenPolyType(ownTypeParams, classInfoAsInMetadata) )
-// clazzBoxed.setFlag(flags)
-// val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz)
-// clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType
-// else GenPolyType(ownTypeParams, rawValueInfoType) )
-// } else {
-// clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
-// else GenPolyType(ownTypeParams, classInfoAsInMetadata) )
-// }
-//
-// // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params
-// statics.setFlag(Flags.JAVA)
-// statics.setInfo(staticInfo)
-// staticModule.setFlag(Flags.JAVA)
-// staticModule.setInfo(statics.tpe)
-//
-//
-// if (canBeTakenAddressOf) {
-// // implicit conversions are owned by staticModule.moduleClass
-// createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false)
-// // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false)
-// createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true)
-// // a return can't have type managed-pointer, thus a dereference-conversion is not needed
-// // similarly, a method can't declare as return type "boxed valuetype"
-// if (!typ.IsEnum) {
-// // a synthetic default constructor for raw-type allows `new X' syntax
-// createDefaultConstructor(typ)
-// }
-// }
-//
-// // import nested types
-// for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem)
-// || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ )
-// {
-// val loader = new loaders.MsilFileLoader(new MsilFile(ntype))
-// val nclazz = statics.newClass(ntype.Name.toTypeName)
-// val nmodule = statics.newModule(ntype.Name)
-// nclazz.setInfo(loader)
-// nmodule.setInfo(loader)
-// staticDefs.enter(nclazz)
-// staticDefs.enter(nmodule)
-//
-// assert(nclazz.companionModule == nmodule, nmodule)
-// assert(nmodule.companionClass == nclazz, nclazz)
-// }
-//
-// val fields = typ.getFields()
-// for (field <- fields
-// if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly)
-// if (getCLRType(field.FieldType) != null)
-// ) {
-// assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement")
-// val flags = translateAttributes(field);
-// val name = newTermName(field.Name);
-// val fieldType =
-// if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType)))
-// ConstantType(getConstant(getCLRType(field.FieldType), field.getValue))
-// else
-// getCLRType(field.FieldType)
-// val owner = if (field.IsStatic()) statics else clazz;
-// val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType);
-// // TODO: set private within!!! -> look at typechecker/Namers.scala
-// (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym);
-// clrTypes.fields(sym) = field;
-// }
-//
-// for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() &&
-// !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType())
-// createMethod(constr);
-//
-// // initially also contains getters and setters of properties.
-// val methodsSet = new mutable.HashSet[MethodInfo]();
-// methodsSet ++= typ.getMethods();
-//
-// for (prop <- typ.getProperties) {
-// val propType: Type = getCLSType(prop.PropertyType);
-// if (propType != null) {
-// val getter: MethodInfo = prop.GetGetMethod(true);
-// val setter: MethodInfo = prop.GetSetMethod(true);
-// var gparamsLength: Int = -1;
-// if (!(getter == null || getter.IsPrivate || getter.IsAssembly
-// || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType))
-// {
-// assert(prop.PropertyType == getter.ReturnType);
-// val gparams: Array[ParameterInfo] = getter.GetParameters();
-// gparamsLength = gparams.length;
-// val name: Name = if (gparamsLength == 0) prop.Name else nme.apply;
-// val flags = translateAttributes(getter);
-// val owner: Symbol = if (getter.IsStatic) statics else clazz;
-// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
-// val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic
-// else methodType(getter, getter.ReturnType)(methodSym)
-// methodSym.setInfo(mtype);
-// methodSym.setFlag(Flags.ACCESSOR);
-// (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym)
-// clrTypes.methods(methodSym) = getter;
-// methodsSet -= getter;
-// }
-// if (!(setter == null || setter.IsPrivate || setter.IsAssembly
-// || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType))
-// {
-// val sparams: Array[ParameterInfo] = setter.GetParameters()
-// if(getter != null)
-// assert(getter.IsStatic == setter.IsStatic);
-// assert(setter.ReturnType == clrTypes.VOID);
-// if(getter != null)
-// assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter);
-//
-// val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name)
-// else nme.update;
-// val flags = translateAttributes(setter);
-// val mtype = methodType(setter, definitions.UnitClass.tpe);
-// val owner: Symbol = if (setter.IsStatic) statics else clazz;
-// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
-// methodSym.setInfo(mtype(methodSym))
-// methodSym.setFlag(Flags.ACCESSOR);
-// (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym);
-// clrTypes.methods(methodSym) = setter;
-// methodsSet -= setter;
-// }
-// }
-// }
-//
-// /* for (event <- typ.GetEvents) {
-// // adding += and -= methods to add delegates to an event.
-// // raising the event ist not possible from outside the class (this is so
-// // generally in .net world)
-// val adder: MethodInfo = event.GetAddMethod();
-// val remover: MethodInfo = event.GetRemoveMethod();
-// if (!(adder == null || adder.IsPrivate || adder.IsAssembly
-// || adder.IsFamilyAndAssembly))
-// {
-// assert(adder.ReturnType == clrTypes.VOID);
-// assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType));
-// val name = encode("+=");
-// val flags = translateAttributes(adder);
-// val mtype: Type = methodType(adder, adder.ReturnType);
-// createMethod(name, flags, mtype, adder, adder.IsStatic)
-// methodsSet -= adder;
-// }
-// if (!(remover == null || remover.IsPrivate || remover.IsAssembly
-// || remover.IsFamilyAndAssembly))
-// {
-// assert(remover.ReturnType == clrTypes.VOID);
-// assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType));
-// val name = encode("-=");
-// val flags = translateAttributes(remover);
-// val mtype: Type = methodType(remover, remover.ReturnType);
-// createMethod(name, flags, mtype, remover, remover.IsStatic)
-// methodsSet -= remover;
-// }
-// } */
-//
-// /* Adds view amounting to syntax sugar for a CLR implicit overload.
-// The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed.
-//
-// /* remember, there's typ.getMethods and type.GetMethods */
-// for (method <- typ.getMethods)
-// if(!method.HasPtrParamOrRetType &&
-// method.IsPublic && method.IsStatic && method.IsSpecialName &&
-// method.Name == "op_Implicit") {
-// // create a view: typ => method's return type
-// val viewRetType: Type = getCLRType(method.ReturnType)
-// val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList;
-// /* The spec says "The operator method shall be defined as a static method on either the operand or return type."
-// * We don't consider the declaring type for the purposes of definitions.functionType,
-// * instead we regard op_Implicit's argument type and return type as defining the view's signature.
-// */
-// if (viewRetType != null && !viewParamTypes.contains(null)) {
-// /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */
-// val funType: Type = definitions.functionType(viewParamTypes, viewRetType);
-// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead?
-// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType)
-// val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true);
-// methodsSet -= method;
-// }
-// }
-// */
-//
-// for (method <- methodsSet.iterator)
-// if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly()
-// && !method.HasPtrParamOrRetType)
-// createMethod(method);
-//
-// // Create methods and views for delegate support
-// if (clrTypes.isDelegateType(typ)) {
-// createDelegateView(typ)
-// createDelegateChainers(typ)
-// }
-//
-// // for enumerations introduce comparison and bitwise logical operations;
-// // the backend will recognize them and replace them with comparison or
-// // bitwise logical operations on the primitive underlying type
-//
-// if (typ.IsEnum) {
-// val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE);
-// val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR);
-//
-// val flags = Flags.JAVA | Flags.FINAL
-// for (cmpName <- ENUM_CMP_NAMES) {
-// val enumCmp = clazz.newMethod(NoPosition, cmpName)
-// val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe)
-// enumCmp.setFlag(flags).setInfo(enumCmpType)
-// instanceDefs.enter(enumCmp)
-// }
-//
-// for (bitLogName <- ENUM_BIT_LOG_NAMES) {
-// val enumBitLog = clazz.newMethod(NoPosition, bitLogName)
-// val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */)
-// enumBitLog.setFlag(flags).setInfo(enumBitLogType)
-// instanceDefs.enter(enumBitLog)
-// }
-// }
-//
-// } // parseClass
-//
-// private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = {
-// if(!method.IsGeneric) Nil
-// else {
-// methodTParams.clear
-// val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]()
-//
-// // first pass
-// for (mvarCILDef <- method.getSortedMVars() ) {
-// val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO)
-// val mtpsym = methodSym.newTypeParameter(mtpname)
-// methodTParams.put(mvarCILDef.Number, mtpsym)
-// newMethodTParams += mtpsym
-// // TODO wouldn't the following also be needed later, i.e. during getCLRType
-// mtpsym.setInfo(definitions.AnyClass.tpe)
-// }
-// // second pass
-// for (mvarCILDef <- method.getSortedMVars() ) {
-// val mtpsym = methodTParams(mvarCILDef.Number)
-// mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM
-// }
-//
-// newMethodTParams.toList
-// }
-// }
-//
-// private def createMethod(method: MethodBase) {
-//
-// val flags = translateAttributes(method);
-// val owner = if (method.IsStatic()) statics else clazz;
-// val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags)
-// /* 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;
-// /* START CLR generics (snippet 4) */
-// val mInfo = if (method.IsGeneric) GenPolyType(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())
-// clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo]
-// else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo];
-// }
-//
-// private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = {
-// val mtype = methodType(args, getCLSType(retType))
-// assert(mtype != null)
-// createMethod(name, flags, mtype, method, statik)
-// }
-//
-// private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = {
-// val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name)
-// methodSym.setFlag(flags).setInfo(mtype(methodSym))
-// (if (statik) staticDefs else instanceDefs).enter(methodSym)
-// if (method != null)
-// clrTypes.methods(methodSym) = method
-// methodSym
-// }
-//
-// private def createDelegateView(typ: MSILType) = {
-// val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo];
-// val invokeRetType: Type = getCLRType(invoke.ReturnType);
-// val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList;
-// val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType);
-//
-// val typClrType: Type = getCLRType(typ);
-// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed
-//
-// // create the forward view: delegate => function
-// val delegateParamTypes: List[Type] = List(typClrType);
-// // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods)
-// val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType)
-// val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true);
-//
-// // create the backward view: function => delegate
-// val functionParamTypes: List[Type] = List(funType);
-// val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType)
-// val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true);
-// }
-//
-// private def createDelegateChainers(typ: MSILType) = {
-// val flags: Long = Flags.JAVA | Flags.FINAL
-// val args: Array[MSILType] = Array(typ)
-//
-// var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false);
-// s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false);
-//
-// s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false);
-// s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false);
-// }
-//
-// private def getName(method: MethodBase): Name = {
-//
-// def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match {
-// case 1 => name match {
-// // PartitionI.10.3.1
-// case "op_Decrement" => Some(encode("--"))
-// case "op_Increment" => Some(encode("++"))
-// case "op_UnaryNegation" => Some(nme.UNARY_-)
-// case "op_UnaryPlus" => Some(nme.UNARY_+)
-// case "op_LogicalNot" => Some(nme.UNARY_!)
-// case "op_OnesComplement" => Some(nme.UNARY_~)
-// /* op_True and op_False have no operator symbol assigned,
-// Other methods that will have to be written in full are:
-// op_AddressOf & (unary)
-// op_PointerDereference * (unary) */
-// case _ => None
-// }
-// case 2 => name match {
-// // PartitionI.10.3.2
-// case "op_Addition" => Some(nme.ADD)
-// case "op_Subtraction" => Some(nme.SUB)
-// case "op_Multiply" => Some(nme.MUL)
-// case "op_Division" => Some(nme.DIV)
-// case "op_Modulus" => Some(nme.MOD)
-// case "op_ExclusiveOr" => Some(nme.XOR)
-// case "op_BitwiseAnd" => Some(nme.AND)
-// case "op_BitwiseOr" => Some(nme.OR)
-// case "op_LogicalAnd" => Some(nme.ZAND)
-// case "op_LogicalOr" => Some(nme.ZOR)
-// case "op_LeftShift" => Some(nme.LSL)
-// case "op_RightShift" => Some(nme.ASR)
-// case "op_Equality" => Some(nme.EQ)
-// case "op_GreaterThan" => Some(nme.GT)
-// case "op_LessThan" => Some(nme.LT)
-// case "op_Inequality" => Some(nme.NE)
-// case "op_GreaterThanOrEqual" => Some(nme.GE)
-// case "op_LessThanOrEqual" => Some(nme.LE)
-//
-// /* op_MemberSelection is reserved in Scala */
-//
-// /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift ,
-// * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */
-//
-// /*
-// The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full.
-//
-// op_RightShiftAssignment >>=
-// op_MultiplicationAssignment *=
-// op_PointerToMemberSelection ->*
-// op_SubtractionAssignment -=
-// op_ExclusiveOrAssignment ^=
-// op_LeftShiftAssignment <<=
-// op_ModulusAssignment %=
-// op_AdditionAssignment +=
-// op_BitwiseAndAssignment &=
-// op_BitwiseOrAssignment |=
-// op_Comma ,
-// op_DivisionAssignment /=
-// */
-// case _ => None
-// }
-// case _ => None
-// }
-//
-// if (method.IsConstructor()) return nme.CONSTRUCTOR;
-// val name = method.Name;
-// if (method.IsStatic()) {
-// if(method.IsSpecialName) {
-// val paramsArity = method.GetParameters().size
-// // handle operator overload, otherwise handle as any static method
-// val operName = operatorOverload(name, paramsArity)
-// if (operName.isDefined) { return operName.get; }
-// }
-// return newTermName(name);
-// }
-// val params = method.GetParameters();
-// name match {
-// case "GetHashCode" if (params.length == 0) => nme.hashCode_;
-// case "ToString" if (params.length == 0) => nme.toString_;
-// case "Finalize" if (params.length == 0) => nme.finalize_;
-// case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) =>
-// nme.equals_;
-// case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply;
-// case _ => newTermName(name);
-// }
-// }
-//
-// //##########################################################################
-//
-// private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = {
-// val rtype = getCLSType(rettype);
-// if (rtype == null) null else methodType(method, rtype);
-// }
-//
-// /** Return a method type for the given method. */
-// private def methodType(method: MethodBase, rettype: Type): Symbol => Type =
-// methodType(method.GetParameters().map(_.ParameterType), rettype);
-//
-// /** Return a method type for the provided argument types and return type. */
-// private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = {
-// def paramType(typ: MSILType): Type =
-// if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe
-// else getCLSType(typ);
-// val ptypes = argtypes.map(paramType).toList;
-// if (ptypes.contains(null)) null
-// else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype);
-// }
-//
-// //##########################################################################
-//
-// private def getClassType(typ: MSILType): Type = {
-// assert(typ != null);
-// val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe;
-// //if (res.isError())
-// // global.reporter.error("unknown class reference " + type.FullName);
-// res
-// }
-//
-// private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not
-// if (typ.IsTMVarUsage())
-// /* 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 */
-// || typ.IsNotPublic() || typ.IsNestedPrivate()
-// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()
-// || typ.IsPointer()
-// || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */
-// || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf()))
-// null
-// else
-// getCLRType(typ)
-// }
-//
-// private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type =
-// if (typ == clrTypes.OBJECT)
-// definitions.ObjectClass.tpe;
-// else if (typ == clrTypes.VALUE_TYPE)
-// definitions.AnyValClass.tpe
-// else if (typ == clrTypes.STRING)
-// definitions.StringClass.tpe;
-// else if (typ == clrTypes.VOID)
-// definitions.UnitClass.tpe
-// else if (typ == clrTypes.BOOLEAN)
-// definitions.BooleanClass.tpe
-// else if (typ == clrTypes.CHAR)
-// definitions.CharClass.tpe
-// else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib
-// definitions.ByteClass.tpe
-// else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib
-// definitions.ShortClass.tpe
-// else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib
-// definitions.IntClass.tpe
-// else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib
-// definitions.LongClass.tpe
-// else if (typ == clrTypes.FLOAT)
-// definitions.FloatClass.tpe
-// else if (typ == clrTypes.DOUBLE)
-// definitions.DoubleClass.tpe
-// else null
-//
-//
-// private def getCLRType(tMSIL: MSILType): Type = {
-// var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL)
-// if (res != null) res
-// else if (tMSIL.isInstanceOf[ConstructedType]) {
-// val ct = tMSIL.asInstanceOf[ConstructedType]
-// /* 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]) {
-// /* 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
-// // make unbounded Array[T] where T is a type variable into Array[T with Object]
-// // (this is necessary because such arrays have a representation which is incompatible
-// // with arrays of primitive types).
-// // TODO does that incompatibility also apply to .NET?
-// if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe))
-// elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe))
-// appliedType(definitions.ArrayClass.tpe, List(elemtp))
-// } else {
-// res = clrTypes.sym2type.get(tMSIL) match {
-// case Some(sym) => sym.tpe
-// case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) {
-// val addressed = getCLRType(tMSIL.GetElementType)
-// val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol?
-// clasym.info.load(clasym)
-// val secondAttempt = clrTypes.sym2type.get(tMSIL)
-// secondAttempt match { case Some(sym) => sym.tpe
-// case None => null
-// }
-// } else getClassType(tMSIL)
-// }
-// if (res == null)
-// null // TODO new RuntimeException()
-// else res
-// }
-// }
-//
-// // the values are Java-Box-Classes (e.g. Integer, Boolean, Character)
-// // java.lang.Number to get the value (if a number, not for boolean, character)
-// // see ch.epfl.lamp.compiler.msil.util.PEStream.java
-// def getConstant(constType: Type, value: Object): Constant = {
-// val typeClass = constType.typeSymbol
-// if (typeClass == definitions.BooleanClass)
-// Constant(value.asInstanceOf[java.lang.Boolean].booleanValue)
-// else if (typeClass == definitions.ByteClass)
-// Constant(value.asInstanceOf[java.lang.Number].byteValue)
-// else if (typeClass == definitions.ShortClass)
-// Constant(value.asInstanceOf[java.lang.Number].shortValue)
-// else if (typeClass == definitions.CharClass)
-// Constant(value.asInstanceOf[java.lang.Character].charValue)
-// else if (typeClass == definitions.IntClass)
-// Constant(value.asInstanceOf[java.lang.Number].intValue)
-// else if (typeClass == definitions.LongClass)
-// Constant(value.asInstanceOf[java.lang.Number].longValue)
-// else if (typeClass == definitions.FloatClass)
-// Constant(value.asInstanceOf[java.lang.Number].floatValue)
-// else if (typeClass == definitions.DoubleClass)
-// Constant(value.asInstanceOf[java.lang.Number].doubleValue)
-// else if (typeClass == definitions.StringClass)
-// Constant(value.asInstanceOf[java.lang.String])
-// else
-// abort("illegal value: " + value + ", class-symbol: " + typeClass)
-// }
-//
-// def isDefinedAtgetConstant(constType: Type): Boolean = {
-// val typeClass = constType.typeSymbol
-// if ( (typeClass == definitions.BooleanClass)
-// || (typeClass == definitions.ByteClass)
-// || (typeClass == definitions.ShortClass)
-// || (typeClass == definitions.CharClass)
-// || (typeClass == definitions.IntClass)
-// || (typeClass == definitions.LongClass)
-// || (typeClass == definitions.FloatClass)
-// || (typeClass == definitions.DoubleClass)
-// || (typeClass == definitions.StringClass)
-// )
-// true
-// else
-// false
-// }
-//
-// private def translateAttributes(typ: MSILType): Long = {
-// var flags: Long = Flags.JAVA;
-// if (typ.IsNotPublic() || typ.IsNestedPrivate()
-// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem())
-// flags = flags | Flags.PRIVATE;
-// else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem())
-// flags = flags | Flags.PROTECTED;
-// if (typ.IsAbstract())
-// flags = flags | Flags.ABSTRACT;
-// if (typ.IsSealed())
-// flags = flags | Flags.FINAL;
-// if (typ.IsInterface())
-// flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT;
-//
-// flags
-// }
-//
-// private def translateAttributes(field: FieldInfo): Long = {
-// var flags: Long = Flags.JAVA;
-// if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly())
-// flags = flags | Flags.PRIVATE;
-// else if (field.IsFamily() || field.IsFamilyOrAssembly())
-// flags = flags | Flags.PROTECTED;
-// if (field.IsInitOnly() || field.IsLiteral())
-// flags = flags | Flags.FINAL;
-// else
-// flags = flags | Flags.MUTABLE;
-// if (field.IsStatic)
-// flags = flags | Flags.STATIC
-//
-// flags
-// }
-//
-// private def translateAttributes(method: MethodBase): Long = {
-// var flags: Long = Flags.JAVA;
-// if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly())
-// flags = flags | Flags.PRIVATE;
-// else if (method.IsFamily() || method.IsFamilyOrAssembly())
-// flags = flags | Flags.PROTECTED;
-// if (method.IsAbstract())
-// flags = flags | Flags.DEFERRED;
-// if (method.IsStatic)
-// flags = flags | Flags.STATIC
-//
-// flags
-// }
-// }
+
+/**
+ * @author Nikolay Mihaylov
+ */
+abstract class TypeParser /*{
+
+ val global: Global
+
+ import global._
+ import loaders.clrTypes
+
+ //##########################################################################
+
+ private var clazz: Symbol = _
+ private var instanceDefs: Scope = _ // was members
+ private var staticModule: Symbol = _ // was staticsClass
+ private var staticDefs: Scope = _ // was statics
+
+ protected def statics: Symbol = staticModule.moduleClass
+
+ protected var busy: Boolean = false // lock to detect recursive reads
+
+ private implicit def stringToTermName(s: String): TermName = newTermName(s)
+
+ private object unpickler extends UnPickler {
+ val global: TypeParser.this.global.type = TypeParser.this.global
+ }
+
+ def parse(typ: MSILType, root: Symbol) {
+
+ def handleError(e: Throwable) = {
+ if (settings.debug.value) e.printStackTrace() //debug
+ throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")")
+ }
+ assert(!busy)
+ busy = true
+
+ if (root.isModule) {
+ this.clazz = root.companionClass
+ this.staticModule = root
+ } else {
+ this.clazz = root
+ this.staticModule = root.companionModule
+ }
+ try {
+ parseClass(typ)
+ } catch {
+ case e: FatalError => handleError(e)
+ case e: RuntimeException => handleError(e)
+ }
+ 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,
+ * therefore newTParams is redundant (other than for recording lexical order),
+ * it always contains the same elements as classTParams.value */
+ val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active )
+ val newTParams = new scala.collection.mutable.ListBuffer[Symbol]()
+ val methodTParams = scala.collection.mutable.Map[Int,Symbol]()
+
+ private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = {
+ val ts = new scala.collection.mutable.ListBuffer[Type]
+ for (cnstrnt <- tvarCILDef.Constraints) {
+ ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right?
+ }
+ TypeBounds.upper(intersectionType(ts.toList, clazz))
+ // TODO variance???
+ }
+
+ private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type,
+ addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = {
+ val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead?
+ val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe)
+ val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true);
+ // !!! this used to mutate a mutable map in definitions, but that map became
+ // immutable and this kept "working" with a no-op. So now it's commented out
+ // since I retired the deprecated code which allowed for that bug.
+ //
+ // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym
+
+ if (isAddressOf) clrTypes.addressOfViews += vmsym
+ vmsym
+ }
+
+ private def createDefaultConstructor(typ: MSILType) {
+ val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance
+ val declType= typ
+ val method = new ConstructorInfo(declType, attrs, Array[MSILType]())
+ val flags = Flags.JAVA
+ val owner = clazz
+ val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags)
+ val rettype = clazz.tpe
+ val mtype = methodType(Array[MSILType](), rettype);
+ val mInfo = mtype(methodSym)
+ methodSym.setInfo(mInfo)
+ instanceDefs.enter(methodSym);
+ clrTypes.constructors(methodSym) = method
+ }
+
+ private def parseClass(typ: MSILType) {
+
+ {
+ val t4c = clrTypes.types.get(clazz)
+ assert(t4c == None || t4c == Some(typ))
+ }
+ clrTypes.types(clazz) = typ
+
+ {
+ val c4t = clrTypes.sym2type.get(typ)
+ assert(c4t == None || c4t == Some(clazz))
+ }
+ clrTypes.sym2type(typ) = clazz
+
+ if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {
+ val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false);
+ assert (attrs.length == 1, attrs.length);
+ val a = attrs(0).asInstanceOf[MSILAttribute];
+ assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR);
+ val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]]
+ unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName);
+ val mClass = clrTypes.getType(typ.FullName + "$");
+ if (mClass != null) {
+ clrTypes.types(statics) = mClass;
+ val moduleInstance = mClass.GetField("MODULE$");
+ assert (moduleInstance != null, mClass);
+ clrTypes.fields(statics) = moduleInstance;
+ }
+ return
+ }
+ val flags = translateAttributes(typ)
+
+ var clazzBoxed : Symbol = NoSymbol
+ var clazzMgdPtr : Symbol = NoSymbol
+
+ val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum")
+
+ if(canBeTakenAddressOf) {
+ clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed"))
+ clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr"))
+ clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr
+ /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed,
+ before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */
+ val typMgdPtr = MSILType.mkByRef(typ)
+ clrTypes.types(clazzMgdPtr) = typMgdPtr
+ clrTypes.sym2type(typMgdPtr) = clazzMgdPtr
+ /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance,
+ because there's no metadata-level representation for a "boxed valuetype" */
+ val instanceDefsMgdPtr = newScope
+ val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr)
+ clazzMgdPtr.setFlag(flags)
+ clazzMgdPtr.setInfo(classInfoMgdPtr)
+ }
+
+/* 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)
+ val tpsym = clazz.newTypeParameter(tpname)
+ classTParams.put(tvarCILDef.Number, tpsym)
+ newTParams += tpsym
+ // TODO wouldn't the following also be needed later, i.e. during getCLRType
+ tpsym.setInfo(definitions.AnyClass.tpe)
+ }
+ // second pass
+ for (tvarCILDef <- typ.getSortedTVars() ) {
+ 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
+/* 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 = newScope
+ staticDefs = newScope
+
+ val classInfoAsInMetadata = {
+ val ifaces: Array[MSILType] = typ.getInterfaces()
+ val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType())
+ else if (typ.IsInterface()) definitions.ObjectClass.tpe
+ else definitions.AnyClass.tpe; // this branch activates for System.Object only.
+ // parents (i.e., base type and interfaces)
+ val parents = new scala.collection.mutable.ListBuffer[Type]()
+ parents += superType
+ for (iface <- ifaces) {
+ parents += getCLRType(iface) // here the variance doesn't matter
+ }
+ // methods, properties, events, fields are entered in a moment
+ if (canBeTakenAddressOf) {
+ val instanceDefsBoxed = newScope
+ ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed)
+ } else
+ ClassInfoType(parents.toList, instanceDefs, clazz)
+ }
+
+ val staticInfo = ClassInfoType(List(), staticDefs, statics)
+
+ clazz.setFlag(flags)
+
+ if (canBeTakenAddressOf) {
+ clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
+ else GenPolyType(ownTypeParams, classInfoAsInMetadata) )
+ clazzBoxed.setFlag(flags)
+ val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz)
+ clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType
+ else GenPolyType(ownTypeParams, rawValueInfoType) )
+ } else {
+ clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata
+ else GenPolyType(ownTypeParams, classInfoAsInMetadata) )
+ }
+
+ // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params
+ statics.setFlag(Flags.JAVA)
+ statics.setInfo(staticInfo)
+ staticModule.setFlag(Flags.JAVA)
+ staticModule.setInfo(statics.tpe)
+
+
+ if (canBeTakenAddressOf) {
+ // implicit conversions are owned by staticModule.moduleClass
+ createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false)
+ // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false)
+ createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true)
+ // a return can't have type managed-pointer, thus a dereference-conversion is not needed
+ // similarly, a method can't declare as return type "boxed valuetype"
+ if (!typ.IsEnum) {
+ // a synthetic default constructor for raw-type allows `new X' syntax
+ createDefaultConstructor(typ)
+ }
+ }
+
+ // import nested types
+ for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem)
+ || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ )
+ {
+ val loader = new loaders.MsilFileLoader(new MsilFile(ntype))
+ val nclazz = statics.newClass(ntype.Name.toTypeName)
+ val nmodule = statics.newModule(ntype.Name)
+ nclazz.setInfo(loader)
+ nmodule.setInfo(loader)
+ staticDefs.enter(nclazz)
+ staticDefs.enter(nmodule)
+
+ assert(nclazz.companionModule == nmodule, nmodule)
+ assert(nmodule.companionClass == nclazz, nclazz)
+ }
+
+ val fields = typ.getFields()
+ for (field <- fields
+ if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly)
+ if (getCLRType(field.FieldType) != null)
+ ) {
+ assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement")
+ val flags = translateAttributes(field);
+ val name = newTermName(field.Name);
+ val fieldType =
+ if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType)))
+ ConstantType(getConstant(getCLRType(field.FieldType), field.getValue))
+ else
+ getCLRType(field.FieldType)
+ val owner = if (field.IsStatic()) statics else clazz;
+ val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType);
+ // TODO: set private within!!! -> look at typechecker/Namers.scala
+ (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym);
+ clrTypes.fields(sym) = field;
+ }
+
+ for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() &&
+ !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType())
+ createMethod(constr);
+
+ // initially also contains getters and setters of properties.
+ val methodsSet = new mutable.HashSet[MethodInfo]();
+ methodsSet ++= typ.getMethods();
+
+ for (prop <- typ.getProperties) {
+ val propType: Type = getCLSType(prop.PropertyType);
+ if (propType != null) {
+ val getter: MethodInfo = prop.GetGetMethod(true);
+ val setter: MethodInfo = prop.GetSetMethod(true);
+ var gparamsLength: Int = -1;
+ if (!(getter == null || getter.IsPrivate || getter.IsAssembly
+ || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType))
+ {
+ assert(prop.PropertyType == getter.ReturnType);
+ val gparams: Array[ParameterInfo] = getter.GetParameters();
+ gparamsLength = gparams.length;
+ val name: Name = if (gparamsLength == 0) prop.Name else nme.apply;
+ val flags = translateAttributes(getter);
+ val owner: Symbol = if (getter.IsStatic) statics else clazz;
+ val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
+ val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic
+ else methodType(getter, getter.ReturnType)(methodSym)
+ methodSym.setInfo(mtype);
+ methodSym.setFlag(Flags.ACCESSOR);
+ (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym)
+ clrTypes.methods(methodSym) = getter;
+ methodsSet -= getter;
+ }
+ if (!(setter == null || setter.IsPrivate || setter.IsAssembly
+ || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType))
+ {
+ val sparams: Array[ParameterInfo] = setter.GetParameters()
+ if(getter != null)
+ assert(getter.IsStatic == setter.IsStatic);
+ assert(setter.ReturnType == clrTypes.VOID);
+ if(getter != null)
+ assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter);
+
+ val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name)
+ else nme.update;
+ val flags = translateAttributes(setter);
+ val mtype = methodType(setter, definitions.UnitClass.tpe);
+ val owner: Symbol = if (setter.IsStatic) statics else clazz;
+ val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
+ methodSym.setInfo(mtype(methodSym))
+ methodSym.setFlag(Flags.ACCESSOR);
+ (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym);
+ clrTypes.methods(methodSym) = setter;
+ methodsSet -= setter;
+ }
+ }
+ }
+
+/* for (event <- typ.GetEvents) {
+ // adding += and -= methods to add delegates to an event.
+ // raising the event ist not possible from outside the class (this is so
+ // generally in .net world)
+ val adder: MethodInfo = event.GetAddMethod();
+ val remover: MethodInfo = event.GetRemoveMethod();
+ if (!(adder == null || adder.IsPrivate || adder.IsAssembly
+ || adder.IsFamilyAndAssembly))
+ {
+ assert(adder.ReturnType == clrTypes.VOID);
+ assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType));
+ val name = encode("+=");
+ val flags = translateAttributes(adder);
+ val mtype: Type = methodType(adder, adder.ReturnType);
+ createMethod(name, flags, mtype, adder, adder.IsStatic)
+ methodsSet -= adder;
+ }
+ if (!(remover == null || remover.IsPrivate || remover.IsAssembly
+ || remover.IsFamilyAndAssembly))
+ {
+ assert(remover.ReturnType == clrTypes.VOID);
+ assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType));
+ val name = encode("-=");
+ val flags = translateAttributes(remover);
+ val mtype: Type = methodType(remover, remover.ReturnType);
+ createMethod(name, flags, mtype, remover, remover.IsStatic)
+ methodsSet -= remover;
+ }
+ } */
+
+/* Adds view amounting to syntax sugar for a CLR implicit overload.
+ The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed.
+
+ /* remember, there's typ.getMethods and type.GetMethods */
+ for (method <- typ.getMethods)
+ if(!method.HasPtrParamOrRetType &&
+ method.IsPublic && method.IsStatic && method.IsSpecialName &&
+ method.Name == "op_Implicit") {
+ // create a view: typ => method's return type
+ val viewRetType: Type = getCLRType(method.ReturnType)
+ val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList;
+ /* The spec says "The operator method shall be defined as a static method on either the operand or return type."
+ * We don't consider the declaring type for the purposes of definitions.functionType,
+ * instead we regard op_Implicit's argument type and return type as defining the view's signature.
+ */
+ if (viewRetType != null && !viewParamTypes.contains(null)) {
+ /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */
+ val funType: Type = definitions.functionType(viewParamTypes, viewRetType);
+ val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead?
+ val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType)
+ val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true);
+ methodsSet -= method;
+ }
+ }
+*/
+
+ for (method <- methodsSet.iterator)
+ if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly()
+ && !method.HasPtrParamOrRetType)
+ createMethod(method);
+
+ // Create methods and views for delegate support
+ if (clrTypes.isDelegateType(typ)) {
+ createDelegateView(typ)
+ createDelegateChainers(typ)
+ }
+
+ // for enumerations introduce comparison and bitwise logical operations;
+ // the backend will recognize them and replace them with comparison or
+ // bitwise logical operations on the primitive underlying type
+
+ if (typ.IsEnum) {
+ val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE);
+ val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR);
+
+ val flags = Flags.JAVA | Flags.FINAL
+ for (cmpName <- ENUM_CMP_NAMES) {
+ val enumCmp = clazz.newMethod(NoPosition, cmpName)
+ val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe)
+ enumCmp.setFlag(flags).setInfo(enumCmpType)
+ instanceDefs.enter(enumCmp)
+ }
+
+ for (bitLogName <- ENUM_BIT_LOG_NAMES) {
+ val enumBitLog = clazz.newMethod(NoPosition, bitLogName)
+ val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */)
+ enumBitLog.setFlag(flags).setInfo(enumBitLogType)
+ instanceDefs.enter(enumBitLog)
+ }
+ }
+
+ } // parseClass
+
+ private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = {
+ if(!method.IsGeneric) Nil
+ else {
+ methodTParams.clear
+ val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]()
+
+ // first pass
+ for (mvarCILDef <- method.getSortedMVars() ) {
+ val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO)
+ val mtpsym = methodSym.newTypeParameter(mtpname)
+ methodTParams.put(mvarCILDef.Number, mtpsym)
+ newMethodTParams += mtpsym
+ // TODO wouldn't the following also be needed later, i.e. during getCLRType
+ mtpsym.setInfo(definitions.AnyClass.tpe)
+ }
+ // second pass
+ for (mvarCILDef <- method.getSortedMVars() ) {
+ val mtpsym = methodTParams(mvarCILDef.Number)
+ mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM
+ }
+
+ newMethodTParams.toList
+ }
+ }
+
+ private def createMethod(method: MethodBase) {
+
+ val flags = translateAttributes(method);
+ val owner = if (method.IsStatic()) statics else clazz;
+ val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags)
+ /* 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;
+/* START CLR generics (snippet 4) */
+ val mInfo = if (method.IsGeneric) GenPolyType(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())
+ clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo]
+ else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo];
+ }
+
+ private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = {
+ val mtype = methodType(args, getCLSType(retType))
+ assert(mtype != null)
+ createMethod(name, flags, mtype, method, statik)
+ }
+
+ private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = {
+ val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name)
+ methodSym.setFlag(flags).setInfo(mtype(methodSym))
+ (if (statik) staticDefs else instanceDefs).enter(methodSym)
+ if (method != null)
+ clrTypes.methods(methodSym) = method
+ methodSym
+ }
+
+ private def createDelegateView(typ: MSILType) = {
+ val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo];
+ val invokeRetType: Type = getCLRType(invoke.ReturnType);
+ val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList;
+ val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType);
+
+ val typClrType: Type = getCLRType(typ);
+ val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed
+
+ // create the forward view: delegate => function
+ val delegateParamTypes: List[Type] = List(typClrType);
+ // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods)
+ val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType)
+ val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true);
+
+ // create the backward view: function => delegate
+ val functionParamTypes: List[Type] = List(funType);
+ val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType)
+ val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true);
+ }
+
+ private def createDelegateChainers(typ: MSILType) = {
+ val flags: Long = Flags.JAVA | Flags.FINAL
+ val args: Array[MSILType] = Array(typ)
+
+ var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false);
+ s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false);
+
+ s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false);
+ s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false);
+ }
+
+ private def getName(method: MethodBase): Name = {
+
+ def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match {
+ case 1 => name match {
+ // PartitionI.10.3.1
+ case "op_Decrement" => Some(encode("--"))
+ case "op_Increment" => Some(encode("++"))
+ case "op_UnaryNegation" => Some(nme.UNARY_-)
+ case "op_UnaryPlus" => Some(nme.UNARY_+)
+ case "op_LogicalNot" => Some(nme.UNARY_!)
+ case "op_OnesComplement" => Some(nme.UNARY_~)
+ /* op_True and op_False have no operator symbol assigned,
+ Other methods that will have to be written in full are:
+ op_AddressOf & (unary)
+ op_PointerDereference * (unary) */
+ case _ => None
+ }
+ case 2 => name match {
+ // PartitionI.10.3.2
+ case "op_Addition" => Some(nme.ADD)
+ case "op_Subtraction" => Some(nme.SUB)
+ case "op_Multiply" => Some(nme.MUL)
+ case "op_Division" => Some(nme.DIV)
+ case "op_Modulus" => Some(nme.MOD)
+ case "op_ExclusiveOr" => Some(nme.XOR)
+ case "op_BitwiseAnd" => Some(nme.AND)
+ case "op_BitwiseOr" => Some(nme.OR)
+ case "op_LogicalAnd" => Some(nme.ZAND)
+ case "op_LogicalOr" => Some(nme.ZOR)
+ case "op_LeftShift" => Some(nme.LSL)
+ case "op_RightShift" => Some(nme.ASR)
+ case "op_Equality" => Some(nme.EQ)
+ case "op_GreaterThan" => Some(nme.GT)
+ case "op_LessThan" => Some(nme.LT)
+ case "op_Inequality" => Some(nme.NE)
+ case "op_GreaterThanOrEqual" => Some(nme.GE)
+ case "op_LessThanOrEqual" => Some(nme.LE)
+
+ /* op_MemberSelection is reserved in Scala */
+
+ /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift ,
+ * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */
+
+ /*
+ The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full.
+
+ op_RightShiftAssignment >>=
+ op_MultiplicationAssignment *=
+ op_PointerToMemberSelection ->*
+ op_SubtractionAssignment -=
+ op_ExclusiveOrAssignment ^=
+ op_LeftShiftAssignment <<=
+ op_ModulusAssignment %=
+ op_AdditionAssignment +=
+ op_BitwiseAndAssignment &=
+ op_BitwiseOrAssignment |=
+ op_Comma ,
+ op_DivisionAssignment /=
+ */
+ case _ => None
+ }
+ case _ => None
+ }
+
+ if (method.IsConstructor()) return nme.CONSTRUCTOR;
+ val name = method.Name;
+ if (method.IsStatic()) {
+ if(method.IsSpecialName) {
+ val paramsArity = method.GetParameters().size
+ // handle operator overload, otherwise handle as any static method
+ val operName = operatorOverload(name, paramsArity)
+ if (operName.isDefined) { return operName.get; }
+ }
+ return newTermName(name);
+ }
+ val params = method.GetParameters();
+ name match {
+ case "GetHashCode" if (params.length == 0) => nme.hashCode_;
+ case "ToString" if (params.length == 0) => nme.toString_;
+ case "Finalize" if (params.length == 0) => nme.finalize_;
+ case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) =>
+ nme.equals_;
+ case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply;
+ case _ => newTermName(name);
+ }
+ }
+
+ //##########################################################################
+
+ private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = {
+ val rtype = getCLSType(rettype);
+ if (rtype == null) null else methodType(method, rtype);
+ }
+
+ /** Return a method type for the given method. */
+ private def methodType(method: MethodBase, rettype: Type): Symbol => Type =
+ methodType(method.GetParameters().map(_.ParameterType), rettype);
+
+ /** Return a method type for the provided argument types and return type. */
+ private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = {
+ def paramType(typ: MSILType): Type =
+ if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe
+ else getCLSType(typ);
+ val ptypes = argtypes.map(paramType).toList;
+ if (ptypes.contains(null)) null
+ else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype);
+ }
+
+ //##########################################################################
+
+ private def getClassType(typ: MSILType): Type = {
+ assert(typ != null);
+ val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe;
+ //if (res.isError())
+ // global.reporter.error("unknown class reference " + type.FullName);
+ res
+ }
+
+ private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not
+ if (typ.IsTMVarUsage())
+ /* 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 */
+ || typ.IsNotPublic() || typ.IsNestedPrivate()
+ || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()
+ || typ.IsPointer()
+ || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */
+ || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf()))
+ null
+ else
+ getCLRType(typ)
+ }
+
+ private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type =
+ if (typ == clrTypes.OBJECT)
+ definitions.ObjectClass.tpe;
+ else if (typ == clrTypes.VALUE_TYPE)
+ definitions.AnyValClass.tpe
+ else if (typ == clrTypes.STRING)
+ definitions.StringClass.tpe;
+ else if (typ == clrTypes.VOID)
+ definitions.UnitClass.tpe
+ else if (typ == clrTypes.BOOLEAN)
+ definitions.BooleanClass.tpe
+ else if (typ == clrTypes.CHAR)
+ definitions.CharClass.tpe
+ else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib
+ definitions.ByteClass.tpe
+ else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib
+ definitions.ShortClass.tpe
+ else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib
+ definitions.IntClass.tpe
+ else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib
+ definitions.LongClass.tpe
+ else if (typ == clrTypes.FLOAT)
+ definitions.FloatClass.tpe
+ else if (typ == clrTypes.DOUBLE)
+ definitions.DoubleClass.tpe
+ else null
+
+
+ private def getCLRType(tMSIL: MSILType): Type = {
+ var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL)
+ if (res != null) res
+ else if (tMSIL.isInstanceOf[ConstructedType]) {
+ val ct = tMSIL.asInstanceOf[ConstructedType]
+ /* 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]) {
+ /* 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
+ // make unbounded Array[T] where T is a type variable into Array[T with Object]
+ // (this is necessary because such arrays have a representation which is incompatible
+ // with arrays of primitive types).
+ // TODO does that incompatibility also apply to .NET?
+ if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe))
+ elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe))
+ appliedType(definitions.ArrayClass.tpe, List(elemtp))
+ } else {
+ res = clrTypes.sym2type.get(tMSIL) match {
+ case Some(sym) => sym.tpe
+ case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) {
+ val addressed = getCLRType(tMSIL.GetElementType)
+ val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol?
+ clasym.info.load(clasym)
+ val secondAttempt = clrTypes.sym2type.get(tMSIL)
+ secondAttempt match { case Some(sym) => sym.tpe
+ case None => null
+ }
+ } else getClassType(tMSIL)
+ }
+ if (res == null)
+ null // TODO new RuntimeException()
+ else res
+ }
+ }
+
+ // the values are Java-Box-Classes (e.g. Integer, Boolean, Character)
+ // java.lang.Number to get the value (if a number, not for boolean, character)
+ // see ch.epfl.lamp.compiler.msil.util.PEStream.java
+ def getConstant(constType: Type, value: Object): Constant = {
+ val typeClass = constType.typeSymbol
+ if (typeClass == definitions.BooleanClass)
+ Constant(value.asInstanceOf[java.lang.Boolean].booleanValue)
+ else if (typeClass == definitions.ByteClass)
+ Constant(value.asInstanceOf[java.lang.Number].byteValue)
+ else if (typeClass == definitions.ShortClass)
+ Constant(value.asInstanceOf[java.lang.Number].shortValue)
+ else if (typeClass == definitions.CharClass)
+ Constant(value.asInstanceOf[java.lang.Character].charValue)
+ else if (typeClass == definitions.IntClass)
+ Constant(value.asInstanceOf[java.lang.Number].intValue)
+ else if (typeClass == definitions.LongClass)
+ Constant(value.asInstanceOf[java.lang.Number].longValue)
+ else if (typeClass == definitions.FloatClass)
+ Constant(value.asInstanceOf[java.lang.Number].floatValue)
+ else if (typeClass == definitions.DoubleClass)
+ Constant(value.asInstanceOf[java.lang.Number].doubleValue)
+ else if (typeClass == definitions.StringClass)
+ Constant(value.asInstanceOf[java.lang.String])
+ else
+ abort("illegal value: " + value + ", class-symbol: " + typeClass)
+ }
+
+ def isDefinedAtgetConstant(constType: Type): Boolean = {
+ val typeClass = constType.typeSymbol
+ if ( (typeClass == definitions.BooleanClass)
+ || (typeClass == definitions.ByteClass)
+ || (typeClass == definitions.ShortClass)
+ || (typeClass == definitions.CharClass)
+ || (typeClass == definitions.IntClass)
+ || (typeClass == definitions.LongClass)
+ || (typeClass == definitions.FloatClass)
+ || (typeClass == definitions.DoubleClass)
+ || (typeClass == definitions.StringClass)
+ )
+ true
+ else
+ false
+ }
+
+ private def translateAttributes(typ: MSILType): Long = {
+ var flags: Long = Flags.JAVA;
+ if (typ.IsNotPublic() || typ.IsNestedPrivate()
+ || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem())
+ flags = flags | Flags.PRIVATE;
+ else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem())
+ flags = flags | Flags.PROTECTED;
+ if (typ.IsAbstract())
+ flags = flags | Flags.ABSTRACT;
+ if (typ.IsSealed())
+ flags = flags | Flags.FINAL;
+ if (typ.IsInterface())
+ flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT;
+
+ flags
+ }
+
+ private def translateAttributes(field: FieldInfo): Long = {
+ var flags: Long = Flags.JAVA;
+ if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly())
+ flags = flags | Flags.PRIVATE;
+ else if (field.IsFamily() || field.IsFamilyOrAssembly())
+ flags = flags | Flags.PROTECTED;
+ if (field.IsInitOnly() || field.IsLiteral())
+ flags = flags | Flags.FINAL;
+ else
+ flags = flags | Flags.MUTABLE;
+ if (field.IsStatic)
+ flags = flags | Flags.STATIC
+
+ flags
+ }
+
+ private def translateAttributes(method: MethodBase): Long = {
+ var flags: Long = Flags.JAVA;
+ if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly())
+ flags = flags | Flags.PRIVATE;
+ else if (method.IsFamily() || method.IsFamilyOrAssembly())
+ flags = flags | Flags.PROTECTED;
+ if (method.IsAbstract())
+ flags = flags | Flags.DEFERRED;
+ if (method.IsStatic)
+ flags = flags | Flags.STATIC
+
+ flags
+ }
+}
+*/ \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala
index 260c350ede..e46f3cbc77 100644
--- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala
@@ -1,13 +1,13 @@
-// /* NSC -- new Scala compiler
-// * Copyright 2006-2011 LAMP/EPFL
-// * @author Martin Odersky
-// */
-//
-// // $Id$
-//
-// package scala.tools.nsc
-// package util
-//
+/* NSC -- new Scala compiler
+ * Copyright 2006-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+// $Id$
+
+package scala.tools.nsc
+package util
+
// import java.io.File
// import java.net.URL
// import java.util.StringTokenizer
@@ -16,154 +16,155 @@
// import scala.tools.nsc.io.{ AbstractFile, MsilFile }
// import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly }
// import ClassPath.{ ClassPathContext, isTraitImplementation }
-//
-// /** Keeping the MSIL classpath code in its own file is important to make sure
-// * we don't accidentally introduce a dependency on msil.jar in the jvm.
-// */
-//
-// object MsilClassPath {
-// def collectTypes(assemFile: AbstractFile) = {
-// var res: Array[MSILType] = MSILType.EmptyTypes
-// val assem = Assembly.LoadFrom(assemFile.path)
-// if (assem != null) {
-// // DeclaringType == null: true for non-inner classes
-// res = assem.GetTypes() filter (_.DeclaringType == null)
-// Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0)
-// }
-// res
-// }
-//
-// /** On the java side this logic is in PathResolver, but as I'm not really
-// * up to folding MSIL into that, I am encapsulating it here.
-// */
-// def fromSettings(settings: Settings): MsilClassPath = {
-// val context =
-// if (settings.inline.value) new MsilContext
-// else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) }
-//
-// import settings._
-// new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context)
-// }
-//
-// class MsilContext extends ClassPathContext[MsilFile] {
-// def toBinaryName(rep: MsilFile) = rep.msilType.Name
-// def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this)
-// }
-//
-// private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = {
-// import ClassPath._
-// val etr = new mutable.ListBuffer[ClassPath[MsilFile]]
-// val names = new mutable.HashSet[String]
-//
-// // 1. Assemblies from -Xassem-extdirs
-// for (dirName <- expandPath(ext, expandStar = false)) {
-// val dir = AbstractFile.getDirectory(dirName)
-// if (dir ne null) {
-// for (file <- dir) {
-// val name = file.name.toLowerCase
-// if (name.endsWith(".dll") || name.endsWith(".exe")) {
-// names += name
-// etr += context.newClassPath(file)
-// }
-// }
-// }
-// }
-//
-// // 2. Assemblies from -Xassem-path
-// for (fileName <- expandPath(user, expandStar = false)) {
-// val file = AbstractFile.getFile(fileName)
-// if (file ne null) {
-// val name = file.name.toLowerCase
-// if (name.endsWith(".dll") || name.endsWith(".exe")) {
-// names += name
-// etr += context.newClassPath(file)
-// }
-// }
-// }
-//
-// def check(n: String) {
-// if (!names.contains(n))
-// throw new AssertionError("Cannot find assembly "+ n +
-// ". Use -Xassem-extdirs or -Xassem-path to specify its location")
-// }
-// check("mscorlib.dll")
-// check("scalaruntime.dll")
-//
-// // 3. Source path
-// for (dirName <- expandPath(source, expandStar = false)) {
-// val file = AbstractFile.getDirectory(dirName)
-// if (file ne null) etr += new SourcePath[MsilFile](file, context)
-// }
-//
-// etr.toList
-// }
-// }
-// import MsilClassPath._
-//
-// /**
-// * A assembly file (dll / exe) containing classes and namespaces
-// */
-// class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] {
-// def name = {
-// val i = namespace.lastIndexOf('.')
-// if (i < 0) namespace
-// else namespace drop (i + 1)
-// }
-// def asURLs = List(new java.net.URL(name))
-// def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here?
-//
-// private lazy val first: Int = {
-// var m = 0
-// var n = types.length - 1
-// while (m < n) {
-// val l = (m + n) / 2
-// val res = types(l).FullName.compareTo(namespace)
-// if (res < 0) m = l + 1
-// else n = l
-// }
-// if (types(m).FullName.startsWith(namespace)) m else types.length
-// }
-//
-// lazy val classes = {
-// val cls = new mutable.ListBuffer[ClassRep]
-// var i = first
-// while (i < types.length && types(i).Namespace.startsWith(namespace)) {
-// // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..)
-// if (types(i).Namespace == namespace)
-// cls += ClassRep(Some(new MsilFile(types(i))), None)
-// i += 1
-// }
-// cls.toIndexedSeq
-// }
-//
-// lazy val packages = {
-// val nsSet = new mutable.HashSet[String]
-// var i = first
-// while (i < types.length && types(i).Namespace.startsWith(namespace)) {
-// val subns = types(i).Namespace
-// if (subns.length > namespace.length) {
-// // example: namespace = "System", subns = "System.Reflection.Emit"
-// // => find second "." and "System.Reflection" to nsSet.
-// val end = subns.indexOf('.', namespace.length + 1)
-// nsSet += (if (end < 0) subns
-// else subns.substring(0, end))
-// }
-// i += 1
-// }
-// val xs = for (ns <- nsSet.toList)
-// yield new AssemblyClassPath(types, ns, context)
-//
-// xs.toIndexedSeq
-// }
-//
-// val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
-//
-// override def toString() = "assembly classpath "+ namespace
-// }
-//
-// /**
-// * The classpath when compiling with target:msil. Binary files are represented as
-// * MSILType values.
-// */
-// class MsilClassPath(ext: String, user: String, source: String, context: MsilContext)
-// extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } \ No newline at end of file
+
+/** Keeping the MSIL classpath code in its own file is important to make sure
+ * we don't accidentally introduce a dependency on msil.jar in the jvm.
+ */
+
+object MsilClassPath /*{
+ def collectTypes(assemFile: AbstractFile) = {
+ var res: Array[MSILType] = MSILType.EmptyTypes
+ val assem = Assembly.LoadFrom(assemFile.path)
+ if (assem != null) {
+ // DeclaringType == null: true for non-inner classes
+ res = assem.GetTypes() filter (_.DeclaringType == null)
+ Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0)
+ }
+ res
+ }
+
+ /** On the java side this logic is in PathResolver, but as I'm not really
+ * up to folding MSIL into that, I am encapsulating it here.
+ */
+ def fromSettings(settings: Settings): MsilClassPath = {
+ val context =
+ if (settings.inline.value) new MsilContext
+ else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) }
+
+ import settings._
+ new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context)
+ }
+
+ class MsilContext extends ClassPathContext[MsilFile] {
+ def toBinaryName(rep: MsilFile) = rep.msilType.Name
+ def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this)
+ }
+
+ private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = {
+ import ClassPath._
+ val etr = new mutable.ListBuffer[ClassPath[MsilFile]]
+ val names = new mutable.HashSet[String]
+
+ // 1. Assemblies from -Xassem-extdirs
+ for (dirName <- expandPath(ext, expandStar = false)) {
+ val dir = AbstractFile.getDirectory(dirName)
+ if (dir ne null) {
+ for (file <- dir) {
+ val name = file.name.toLowerCase
+ if (name.endsWith(".dll") || name.endsWith(".exe")) {
+ names += name
+ etr += context.newClassPath(file)
+ }
+ }
+ }
+ }
+
+ // 2. Assemblies from -Xassem-path
+ for (fileName <- expandPath(user, expandStar = false)) {
+ val file = AbstractFile.getFile(fileName)
+ if (file ne null) {
+ val name = file.name.toLowerCase
+ if (name.endsWith(".dll") || name.endsWith(".exe")) {
+ names += name
+ etr += context.newClassPath(file)
+ }
+ }
+ }
+
+ def check(n: String) {
+ if (!names.contains(n))
+ throw new AssertionError("Cannot find assembly "+ n +
+ ". Use -Xassem-extdirs or -Xassem-path to specify its location")
+ }
+ check("mscorlib.dll")
+ check("scalaruntime.dll")
+
+ // 3. Source path
+ for (dirName <- expandPath(source, expandStar = false)) {
+ val file = AbstractFile.getDirectory(dirName)
+ if (file ne null) etr += new SourcePath[MsilFile](file, context)
+ }
+
+ etr.toList
+ }
+}
+import MsilClassPath._
+
+/**
+ * A assembly file (dll / exe) containing classes and namespaces
+ */
+class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] {
+ def name = {
+ val i = namespace.lastIndexOf('.')
+ if (i < 0) namespace
+ else namespace drop (i + 1)
+ }
+ def asURLs = List(new java.net.URL(name))
+ def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here?
+
+ private lazy val first: Int = {
+ var m = 0
+ var n = types.length - 1
+ while (m < n) {
+ val l = (m + n) / 2
+ val res = types(l).FullName.compareTo(namespace)
+ if (res < 0) m = l + 1
+ else n = l
+ }
+ if (types(m).FullName.startsWith(namespace)) m else types.length
+ }
+
+ lazy val classes = {
+ val cls = new mutable.ListBuffer[ClassRep]
+ var i = first
+ while (i < types.length && types(i).Namespace.startsWith(namespace)) {
+ // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..)
+ if (types(i).Namespace == namespace)
+ cls += ClassRep(Some(new MsilFile(types(i))), None)
+ i += 1
+ }
+ cls.toIndexedSeq
+ }
+
+ lazy val packages = {
+ val nsSet = new mutable.HashSet[String]
+ var i = first
+ while (i < types.length && types(i).Namespace.startsWith(namespace)) {
+ val subns = types(i).Namespace
+ if (subns.length > namespace.length) {
+ // example: namespace = "System", subns = "System.Reflection.Emit"
+ // => find second "." and "System.Reflection" to nsSet.
+ val end = subns.indexOf('.', namespace.length + 1)
+ nsSet += (if (end < 0) subns
+ else subns.substring(0, end))
+ }
+ i += 1
+ }
+ val xs = for (ns <- nsSet.toList)
+ yield new AssemblyClassPath(types, ns, context)
+
+ xs.toIndexedSeq
+ }
+
+ val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
+
+ override def toString() = "assembly classpath "+ namespace
+}
+
+/**
+ * The classpath when compiling with target:msil. Binary files are represented as
+ * MSILType values.
+ */
+class MsilClassPath(ext: String, user: String, source: String, context: MsilContext)
+extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { }
+*/ \ No newline at end of file