From 4dc7be4b10cdb0df96fead1b1e37eba02f68a7c2 Mon Sep 17 00:00:00 2001 From: michelou Date: Thu, 24 May 2007 11:05:58 +0000 Subject: added call to ilasm in MSIL backend --- .../scala/tools/ant/templates/tool-unix.tmpl | 5 +- .../scala/tools/ant/templates/tool-windows.tmpl | 10 +- src/compiler/scala/tools/nsc/Properties.scala | 18 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 2311 ++++++++++---------- 4 files changed, 1192 insertions(+), 1152 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl index 2233056bb3..1a303c2831 100644 --- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl @@ -70,4 +70,7 @@ if $cygwin; then BOOT_CLASSPATH=`cygpath --path --$format "$BOOT_CLASSPATH"` fi -${JAVACMD:=java} ${JAVA_OPTS:=@javaflags@} -Xbootclasspath/a:"$BOOT_CLASSPATH" -cp "$EXTENSION_CLASSPATH" -Dscala.home="$SCALA_HOME" -Denv.classpath="$CLASSPATH" @properties@ @class@ @toolflags@ "$@@" +ILASM=`which ilasm` +[ -x "$ILASM" ] || ILASM="" + +${JAVACMD:=java} ${JAVA_OPTS:=@javaflags@} -Xbootclasspath/a:"$BOOT_CLASSPATH" -cp "$EXTENSION_CLASSPATH" -Dscala.home="$SCALA_HOME" -Denv.classpath="$CLASSPATH" -Dilasm.tool="$ILASM" @properties@ @class@ @toolflags@ "$@@" diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index 48b5161f34..5398672fac 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -32,6 +32,10 @@ rem We use the value of the JAVA_OPTS environment variable if defined set _JAVA_OPTS=%JAVA_OPTS% if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=@javaflags@ +rem We use the value of the ILASM environment variable if defined +set _ILASM=%ILASM% +if "%_ILASM%"=="" call :find_ilasm ilasm.exe + set _EXTENSION_CLASSPATH=@extclasspath@ if "%_EXTENSION_CLASSPATH%"=="" ( for %%f in ("%_SCALA_HOME%\lib\*") do call :add_cpath "%%f" @@ -59,7 +63,7 @@ shift goto loop :exec -set _PROPS=-Dscala.home="%_SCALA_HOME%" -Denv.classpath="%CLASSPATH%" @properties@ +set _PROPS=-Dscala.home="%_SCALA_HOME%" -Denv.classpath="%CLASSPATH%" -Dilasm.tool="%_ILASM%" @properties@ rem echo %_JAVACMD% -Xbootclasspath/a:"%_BOOT_CLASSPATH%" %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" @class@ @toolflags@ %_ARGS% %_JAVACMD% -Xbootclasspath/a:"%_BOOT_CLASSPATH%" %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" @class@ @toolflags@ %_ARGS% @@ -85,6 +89,10 @@ rem set _SCALA_HOME=%~dps0.. set _SCALA_HOME=%_BIN_DIR%.. goto :eof +:find_ilasm + set _ILASM=%~$PATH:1 +goto :eof + rem ########################################################################## rem # errors diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index f9f9734c9d..7d89b3ceb9 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -24,6 +24,8 @@ object Properties { props } + private val isWin = System.getProperty("os.name") startsWith "Windows" + /** The version number of the jar this was loaded from, or * "(unknown)" if it cannot be determined. */ @@ -45,9 +47,19 @@ object Properties { val scalaHome: String = System.getProperty("scala.home") - val cmdName: String = { - val isWin = System.getProperty("os.name") startsWith "Windows" + val envClasspath: String = + System.getProperty("env.classpath") + + val cmdName: String = if (isWin) "scala.bat" else "scala" - } + val ilasmFormat: java.text.MessageFormat = { + val ilasm = System.getProperty("ilasm.tool", "") + if (ilasm == "") null + else + new java.text.MessageFormat(ilasm + ( + if (isWin) " /quiet /exe /output={0} {1}" + else " --format exe --output={0} {1}" + )) + } } diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index b73ac3329b..2240f5db38 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -38,7 +38,7 @@ abstract class GenMSIL extends SubComponent { override def erasedTypes = true - override def run: Unit = { + override def run { if (settings.debug.value) inform("[running phase " + name + " on icode]") val codeGenerator = new BytecodeGenerator @@ -59,8 +59,9 @@ abstract class GenMSIL extends SubComponent { } } - override def apply(unit: CompilationUnit): Unit = + override def apply(unit: CompilationUnit) { abort("MSIL works on icode classes, not on compilation units!") + } } /** @@ -91,7 +92,7 @@ abstract class GenMSIL extends SubComponent { 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) + MsilType.EmptyTypes) val TYPE_FROM_HANDLE = clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle"))) @@ -134,7 +135,7 @@ abstract class GenMSIL extends SubComponent { initMappings() // ******************************************************************** // Create the mappings - private def initMappings(): Unit = { + private def initMappings() { mapType(definitions.AnyClass, MOBJECT) mapType(definitions.AnyRefClass, MOBJECT) //mapType(definitions.AllRefClass, clrTypes.getType("scala.AllRef$")) @@ -214,35 +215,35 @@ abstract class GenMSIL extends SubComponent { var mmodule: ModuleBuilder = _ var mcode: ILGenerator = _ - var assemName : String = _ + var assemName: String = _ var firstSourceName = "" - var outDir : File = _ + var outDir: File = _ - def initAssembly(): Unit = { + 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"), "Source file doesn't end with .scala") - assemName = firstSourceName.substring(0, firstSourceName.length() - 6) - } + 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"), "Source file doesn't end with .scala") + 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) - outDir = f.getParentFile() - assemName = f.getName() + 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) + outDir = f.getParentFile() + assemName = f.getName() } if (outDir == null) - outDir = new File(".") + outDir = new File(".") val assemblyName = new AssemblyName() @@ -252,7 +253,7 @@ abstract class GenMSIL extends SubComponent { val 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()) + new File(outDir, moduleName).getAbsolutePath()) assert (mmodule != null) initMappings() @@ -272,59 +273,61 @@ abstract class GenMSIL extends SubComponent { * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000) * **/ - def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder): Unit = currentRun.symData.get(sym) match { - case Some(pickle) => - val symtab: Array[Byte] = new Array[Byte](pickle.writeIndex + 8) - symtab(0) = 1.toByte - var size:Int = pickle.writeIndex - for (i <- 2 until 6) { - symtab(i) = (size & 0xff).toByte - size = size >> 8 - } - - System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) - - tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) - - currentRun.symData -= sym - currentRun.symData -= sym.linkedSym - //log("Generated ScalaSig Attr for " + sym)//debug - case _ => - log("Could not find pickle information for " + sym) + def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) { + currentRun.symData.get(sym) match { + case Some(pickle) => + val symtab: Array[Byte] = new Array[Byte](pickle.writeIndex + 8) + symtab(0) = 1.toByte + var size:Int = pickle.writeIndex + for (i <- 2 until 6) { + symtab(i) = (size & 0xff).toByte + size = size >> 8 + } + + System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) + + tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) + + currentRun.symData -= sym + currentRun.symData -= sym.linkedSym + //log("Generated ScalaSig Attr for " + sym)//debug + case _ => + log("Could not find pickle information for " + sym) + } } - def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo]): Unit = { + def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo]) { return // FIXME if (settings.debug.value) - log("creating attributes: " + attributes + " for member : " + member) + log("creating attributes: " + attributes + " for member : " + member) for (attr@ AnnotationInfo(typ, annArgs, nvPairs) <- attributes ; if attr.isConstant) /* !typ.symbol.hasFlag(Flags.JAVA) */ { -// assert(consts.length <= 1, -// "too many constant arguments for attribute; "+consts.toString()) - - // Problem / TODO having the symbol of the attribute type would be nicer - // (i hope that type.symbol is the same as the one in types2create) - // AND: this will crash if the attribute Type is already compiled (-> not a typeBuilder) - // when this is solved, types2create will be the same as icodes.classes, thus superfluous - val attrType: TypeBuilder = getType(typ.symbol).asInstanceOf[TypeBuilder] -// val attrType: MsilType = getType(typ.symbol) - - // Problem / TODO: i have no idea which constructor is used. This - // information should be available in AnnotationInfo. - attrType.CreateType() // else, GetConstructors can't be used - val constr: ConstructorInfo = attrType.GetConstructors()(0) - // prevent a second call of CreateType, only needed because there's no - // otehr way than GetConstructors()(0) to get the constructor, if there's - // no constructor symbol available. - - val args: Array[Byte] = +// assert(consts.length <= 1, +// "too many constant arguments for attribute; "+consts.toString()) + + // Problem / TODO having the symbol of the attribute type would be nicer + // (i hope that type.symbol is the same as the one in types2create) + // AND: this will crash if the attribute Type is already compiled (-> not a typeBuilder) + // when this is solved, types2create will be the same as icodes.classes, thus superfluous + val attrType: TypeBuilder = getType(typ.symbol).asInstanceOf[TypeBuilder] +// val attrType: MsilType = getType(typ.symbol) + + // Problem / TODO: i have no idea which constructor is used. This + // information should be available in AnnotationInfo. + attrType.CreateType() // else, GetConstructors can't be used + val constr: ConstructorInfo = attrType.GetConstructors()(0) + // prevent a second call of CreateType, only needed because there's no + // otehr 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) + member.SetCustomAttribute(constr, args) } } @@ -334,140 +337,153 @@ abstract class GenMSIL extends SubComponent { 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)) { + // 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) + } 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) + 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)): Unit = { - // 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) + 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().subArray(0, length) } - def writeAssembly(): Unit = { + def writeAssembly() { if (entryPoint != null) { - assert(entryPoint.enclClass.isModuleClass, "main-method not defined in a module") - 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) + assert(entryPoint.enclClass.isModuleClass, "main-method not defined in a module") + 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() val filename = new File(outDir, assemName + ".msil").getPath() if (settings.debug.value) - log("output file name: " + filename) + log("output file name: " + filename) try { - massembly.Save(filename) + massembly.Save(filename) + val fm = Properties.ilasmFormat + if (fm != null) { + val exeName = new File(outDir, assemName + ".exe").getPath() + val cmd = fm.format(Array(/*output*/exeName, /*input*/filename)) + try { + Runtime.getRuntime().exec(cmd) + } catch { + case ex: java.io.IOException => + Console.println("Cannot run command: " + cmd) + exit(1) + } + } } catch { - case _: Error => abort("Could not save file " + filename) + case _: Error => abort("Could not save file " + filename) } } - private def createTypes(): Unit = + private def createTypes() { for (sym <- classes.keys) { - if (settings.debug.value) - log("Calling CreatType for " + sym + ", " + types(sym)) - types(sym).asInstanceOf[TypeBuilder].CreateType() + if (settings.debug.value) + log("Calling CreatType for " + sym + ", " + types(sym)) + types(sym).asInstanceOf[TypeBuilder].CreateType() } + } - private[GenMSIL] def genClass(iclass: IClass): Unit = { + private[GenMSIL] def genClass(iclass: IClass) { val sym = iclass.symbol if (settings.debug.value) log("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) @@ -475,24 +491,24 @@ abstract class GenMSIL extends SubComponent { 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" + // 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) - })) { - if (settings.debug.value) - log("auto-generating cloneable method for " + sym) - val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | - MethodAttributes.HideBySig) - 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) - } + if (iclass.methods.forall(m => { + !((m.symbol.name.toString() != "clone" || m.symbol.name.toString() != "Clone") && + m.symbol.tpe.paramTypes.length != 0) + })) { + if (settings.debug.value) + log("auto-generating cloneable method for " + sym) + val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | + MethodAttributes.HideBySig) + 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 match { @@ -502,28 +518,28 @@ abstract class GenMSIL extends SubComponent { tBuilder.setPosition(line, iclass.cunit.source.file.name) if (isTopLevelModule(sym)) { - if (settings.debug.value) - log("TopLevelModule: " + sym) - if (sym.linkedClassOfModule == NoSymbol) { - if (settings.debug.value) - log(" no linked class: " + sym) - dumpMirrorClass(sym) - } else if (!currentRun.compiles(sym.linkedClassOfModule)) { - if (settings.debug.value) - log(" not compiling linked class: " + sym) - dumpMirrorClass(sym) - } + if (settings.debug.value) + log("TopLevelModule: " + sym) + if (sym.linkedClassOfModule == NoSymbol) { + if (settings.debug.value) + log(" no linked class: " + sym) + dumpMirrorClass(sym) + } else if (!currentRun.compiles(sym.linkedClassOfModule)) { + if (settings.debug.value) + log(" not compiling linked class: " + sym) + dumpMirrorClass(sym) + } } // the pickling info is not written to the module class, but to it's // linked class (the mirror class eventually dumped) if (!(tBuilder.Name.endsWith("$") && sym.isModuleClass)){ - // think the if inside could be removed, because in this case, addSymtabAttribute is - // called in the dumpMirrorClass method - addSymtabAttribute(if (isTopLevelModule(sym)) sym.sourceModule else sym, tBuilder) + // think the if inside could be removed, because in this case, addSymtabAttribute is + // called in the dumpMirrorClass method + addSymtabAttribute(if (isTopLevelModule(sym)) sym.sourceModule else sym, tBuilder) - // TODO: remove; check the above think: - assert(!isTopLevelModule(sym), "can't remove the 'if'") + // TODO: remove; check the above think: + assert(!isTopLevelModule(sym), "can't remove the 'if'") } addAttributes(tBuilder, sym.attributes) @@ -534,21 +550,21 @@ abstract class GenMSIL extends SubComponent { } //genClass - private def genMethod(m: IMethod): Unit = { + private def genMethod(m: IMethod) { if (settings.debug.value) - log("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + - " owner: " + m.symbol.owner) + log("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() + mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator() } else { - val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] - if (!mBuilder.IsAbstract()) + val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] + if (!mBuilder.IsAbstract()) try { - mcode = mBuilder.GetILGenerator() + mcode = mBuilder.GetILGenerator() } catch { case e: Exception => System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) @@ -559,20 +575,20 @@ abstract class GenMSIL extends SubComponent { "::" + mBuilder.DeclaringType) throw e } - else - mcode = null + else + mcode = null } if (mcode != null) { - for (local <- m.locals.diff(m.params)) { - if (settings.debug.value) - log("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) + for (local <- m.locals.diff(m.params)) { + if (settings.debug.value) + log("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) } } @@ -582,20 +598,20 @@ abstract class GenMSIL extends SubComponent { // icode) if there's no code after a try-catch block var needAdditionalRet: Boolean = false - def genCode(m: IMethod): Unit = { + def genCode(m: IMethod) { code = m.code labels.clear linearization = linearizer.linearize(m) val orderedBlocks = (if (m.exh != Nil) orderBlocksForExh(linearization, m.exh) - else linearization) + else linearization) makeLabels(orderedBlocks) // orderBlocksForExh may create new Blocks -> new Labels genBlocks(orderedBlocks) if (needAdditionalRet) { - mcode.Emit(OpCodes.Ret) - needAdditionalRet = false + mcode.Emit(OpCodes.Ret) + needAdditionalRet = false } } @@ -614,120 +630,120 @@ abstract class GenMSIL extends SubComponent { // def getExceptionBlock(exh: ExceptionHandler): Option[ExceptionBlock] def close(): Unit /* protected def findExceptionBlock(list: List[Block], exh: ExceptionHandler): Option[ExceptionBlock] = { - var res: Option[ExceptionBlock] = None - var i: Int = 0 - while (i < list.length && res == None) { - val b = list(i) - val exB = b.getExceptionBlock(exh) - exB match { - case some: Some[ExceptionBlock] => res = some - case None => () - } - i = i + 1 - } - res + var res: Option[ExceptionBlock] = None + var i: Int = 0 + while (i < list.length && res == None) { + val b = list(i) + val exB = b.getExceptionBlock(exh) + exB match { + case some: Some[ExceptionBlock] => res = some + case None => () + } + i = i + 1 + } + res } */ } case class CodeBlock(parent: BlockList0) extends Block { var basicBlocks: List[BasicBlock] = Nil def isEmpty = basicBlocks.isEmpty override def firstBasicBlock: BasicBlock = { - if(isEmpty) null - else { - if (closed) basicBlocks.head - else basicBlocks.last - } + if(isEmpty) null + else { + if (closed) basicBlocks.head + else basicBlocks.last + } } override def lastBasicBlock: BasicBlock = { - if(isEmpty) null - else { - if (closed) basicBlocks.last - else basicBlocks.head - } + if(isEmpty) null + else { + if (closed) basicBlocks.last + else basicBlocks.head + } } override def parentBlockList = Some(parent) // override def getExceptionBlock(exh: ExceptionHandler): Option[ExceptionBlock] = None - override def close(): Unit = { - basicBlocks = basicBlocks.reverse - closed = true + override def close() { + basicBlocks = basicBlocks.reverse + closed = true } override def toString() = { - var res = "" - res = res + TopBlock.indent + "CodeBlock(" + basicBlocks + ")\n" - res + var res = "" + res = res + TopBlock.indent + "CodeBlock(" + basicBlocks + ")\n" + res } } abstract class BlockList0 extends Block { var blocks: List[Block] = Nil override def firstBasicBlock: BasicBlock = { - if(blocks.isEmpty) null - else { - if (closed) blocks.head.firstBasicBlock - else blocks.last.firstBasicBlock - } + if(blocks.isEmpty) null + else { + if (closed) blocks.head.firstBasicBlock + else blocks.last.firstBasicBlock + } } override def lastBasicBlock: BasicBlock = { - if(blocks.isEmpty) null - else { - if (closed) blocks.last.lastBasicBlock - else blocks.head.lastBasicBlock - } + if(blocks.isEmpty) null + else { + if (closed) blocks.last.lastBasicBlock + else blocks.head.lastBasicBlock + } } /* override def getExceptionBlock(exh: ExceptionHandler): Option[ExceptionBlock] = { - findExceptionBlock(blocks, exh) + findExceptionBlock(blocks, exh) } */ def addExceptionBlock(exh: ExceptionHandler) = { - if (settings.debug.value) - log("new exc block with " + exh + " to " + this) - val e = new ExceptionBlock(this, exh) - blocks = e :: blocks - e + if (settings.debug.value) + log("new exc block with " + exh + " to " + this) + val e = new ExceptionBlock(this, exh) + blocks = e :: blocks + e } def addBasicBlock(bb: BasicBlock) = { - if (settings.debug.value) - log("adding bb " + bb + " to " + this) - var cb: CodeBlock = if (!blocks.isEmpty) { - blocks.head match { - case blk: CodeBlock => blk - case _ => null - } - } else null - if (cb == null) { - cb = new CodeBlock(this) - blocks = cb :: blocks - } - cb.basicBlocks = bb :: cb.basicBlocks - } - override def close(): Unit = { - blocks.foreach(.close) - blocks = blocks.reverse - closed = true + if (settings.debug.value) + log("adding bb " + bb + " to " + this) + var cb: CodeBlock = if (!blocks.isEmpty) { + blocks.head match { + case blk: CodeBlock => blk + case _ => null + } + } else null + if (cb == null) { + cb = new CodeBlock(this) + blocks = cb :: blocks + } + cb.basicBlocks = bb :: cb.basicBlocks + } + override def close() { + blocks.foreach(.close) + blocks = blocks.reverse + closed = true } override def toString() = { - var res = "" - res = res + TopBlock.indent + "BlockList0:\n" - TopBlock.indent = TopBlock.indent + " " - for (b <- blocks) - res = res + b + "\n" - TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-2) - res + var res = "" + res = res + TopBlock.indent + "BlockList0:\n" + TopBlock.indent = TopBlock.indent + " " + for (b <- blocks) + res = res + b + "\n" + TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-2) + res } } case class BlockList(parent: Block) extends BlockList0 { override def parentBlockList: Option[BlockList0] = { - if (parent == TopBlock) - Some(TopBlock) - else parent match { - case bl: BlockList => Some(bl) - case cb: CatchBlock => Some(cb) - case _ => parent.parentBlockList - } + if (parent == TopBlock) + Some(TopBlock) + else parent match { + case bl: BlockList => Some(bl) + case cb: CatchBlock => Some(cb) + case _ => parent.parentBlockList + } } override def toString() = { - var res = "" - res = res + TopBlock.indent + "BlockList:\n" - res = res + super.toString() - res + var res = "" + res = res + TopBlock.indent + "BlockList:\n" + res = res + super.toString() + res } } case class ExceptionBlock(parent: Block, handler: ExceptionHandler) extends Block { @@ -735,88 +751,88 @@ abstract class GenMSIL extends SubComponent { var catchBlocks: List[CatchBlock] = Nil var finallyBlock: BlockList = new BlockList(this) override def firstBasicBlock = { - tryBlock.firstBasicBlock + tryBlock.firstBasicBlock } override def lastBasicBlock = { - if (!finallyBlock.blocks.isEmpty) - finallyBlock.lastBasicBlock - else if(!catchBlocks.isEmpty) { - if (closed) catchBlocks.last.lastBasicBlock - else catchBlocks.head.lastBasicBlock - } else { - tryBlock.lastBasicBlock - } + if (!finallyBlock.blocks.isEmpty) + finallyBlock.lastBasicBlock + else if(!catchBlocks.isEmpty) { + if (closed) catchBlocks.last.lastBasicBlock + else catchBlocks.head.lastBasicBlock + } else { + tryBlock.lastBasicBlock + } } override def parentBlockList: Option[BlockList0] = { - if (parent == TopBlock) - Some(TopBlock) - else parent match { - case bl: BlockList => Some(bl) - case cb: CatchBlock => Some(cb) - case _ => parent.parentBlockList - } + if (parent == TopBlock) + Some(TopBlock) + else parent match { + case bl: BlockList => Some(bl) + case cb: CatchBlock => Some(cb) + case _ => parent.parentBlockList + } } /* override def getExceptionBlock(exh: ExceptionHandler): Option[ExceptionBlock] = { - if (exh == handler) Some(this) - else { - val t = if (tryBlock == null) Nil else List(tryBlock) - val f = if (finallyBlock == null) Nil else List(finallyBlock) - findExceptionBlock(t ::: catchBlocks ::: f, exh) - } + if (exh == handler) Some(this) + else { + val t = if (tryBlock == null) Nil else List(tryBlock) + val f = if (finallyBlock == null) Nil else List(finallyBlock) + findExceptionBlock(t ::: catchBlocks ::: f, exh) + } } */ def addCatchBlock(exSym: Symbol): CatchBlock = { - if (settings.debug.value) - log("new catch block with " + exSym + " to " + this) - val c = new CatchBlock(this, exSym) - catchBlocks = c :: catchBlocks - c - } - override def close(): Unit = { - tryBlock.close - catchBlocks.foreach(.close) - catchBlocks = catchBlocks.reverse - finallyBlock.close - closed = true + if (settings.debug.value) + log("new catch block with " + exSym + " to " + this) + val c = new CatchBlock(this, exSym) + catchBlocks = c :: catchBlocks + c + } + override def close() { + tryBlock.close + catchBlocks.foreach(.close) + catchBlocks = catchBlocks.reverse + finallyBlock.close + closed = true } override def toString() = { - var res = "" - res = res + TopBlock.indent + "ExceptionBlock, handler: " + handler + "\n" - res = res + TopBlock.indent + " " + "try:\n" - TopBlock.indent = TopBlock.indent + " " - res = res + tryBlock + "\n" - TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) - res = res + TopBlock.indent + " " + "catch:\n" - TopBlock.indent = TopBlock.indent + " " - for (b <- catchBlocks) - res = res + b + "\n" - TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) - res = res + TopBlock.indent + " " + "finally:\n" - TopBlock.indent = TopBlock.indent + " " - res = res + finallyBlock + "\n" - TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) - res + var res = "" + res = res + TopBlock.indent + "ExceptionBlock, handler: " + handler + "\n" + res = res + TopBlock.indent + " " + "try:\n" + TopBlock.indent = TopBlock.indent + " " + res = res + tryBlock + "\n" + TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) + res = res + TopBlock.indent + " " + "catch:\n" + TopBlock.indent = TopBlock.indent + " " + for (b <- catchBlocks) + res = res + b + "\n" + TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) + res = res + TopBlock.indent + " " + "finally:\n" + TopBlock.indent = TopBlock.indent + " " + res = res + finallyBlock + "\n" + TopBlock.indent = TopBlock.indent.substring(0,TopBlock.indent.length-4) + res } } case class CatchBlock(parent: ExceptionBlock, exSym: Symbol) extends BlockList0 { override def parentBlockList: Option[BlockList0] = { - parent.parentBlockList + parent.parentBlockList } override def toString() = { - var res = "" - res = res + TopBlock.indent + "CatchBlock:\n" - res = res + super.toString() - res + var res = "" + res = res + TopBlock.indent + "CatchBlock:\n" + res = res + super.toString() + res } } case object TopBlock extends BlockList0 { var indent = "" override def parentBlockList = None override def toString() = { - var res = "" - res = res + TopBlock.indent + "TopBlock:\n" - res = res + super.toString() - res + var res = "" + res = res + TopBlock.indent + "TopBlock:\n" + res = res + super.toString() + res } } @@ -838,216 +854,216 @@ abstract class GenMSIL extends SubComponent { TopBlock.blocks = Nil var currentBlock: BlockList0 = TopBlock def addBlocks(b: List[BasicBlock]):Unit = b match { - case Nil => if (settings.debug.value) log("adding " + b) - - case x :: xs => - if (settings.debug.value) log("adding " + b) - // problem: block may already be added, and and needs to be moved. - // if nextblock NOT in b: check if nextblock in blocksToPut, if NOT, check if movable, else don't put - if (nextBlock != null && b.contains(nextBlock)) { - val blocksToAdd = nextBlock :: b.diff(List(nextBlock)) - nextBlock = null - addBlocks(blocksToAdd) - } - else if (untreatedHandlers.forall(h => !(h.covers(x)))) { - - if (settings.debug.value) log(" no new handler for " + x) - if (untreatedHandlers.forall(h => !(h.blocks.contains(x) || - (h.finalizer != null && - h.finalizer.covers(x))))) - { - // the block is not part of some catch or finally code - currentBlock.addBasicBlock(x) - blocksToPut = blocksToPut.diff(List(x)) - if (settings.debug.value) log(" -> addBlocks(" + xs + ")") - addBlocks(xs) - } else { - if (settings.debug.value) log("x is part of catch or finally block") - - // check if the covered code of the handler x belongs to is empty - // this check is not needed for finalizers: empty try with finalizer - // is optimized by compiler (no try left) - if(untreatedHandlers.forall(h => - (!h.blocks.contains(x) || h.covered.isEmpty))) { - blocksToPut = blocksToPut.diff(List(x)) - addBlocks(xs) - } else - addBlocks(xs ::: List(x)) - } - } else { // there are new handlers for this block - - var firstBlockAfter: HashMap[ExceptionHandler,BasicBlock] = new HashMap() - val savedCurrentBlock = currentBlock - /** - * the output blocks of this method are changed so that: - * - only one block has a successor outside the set of blocks - * - this block is the last of the reusulting list - * - * side-effect: it stores the successor in the hashMap - * firstBlockAfter, which has to be emitted first after try/catch/finally, - * because the target of the Leave-instruction will always be the first - * instruction after EndExceptionBlock - * - * returns: the output blocks plus an Option containing the possibly created - * new block - **/ - def adaptBlocks(blocks: List[BasicBlock], exh: ExceptionHandler): (List[BasicBlock], Option[BasicBlock]) = { - def outsideTargets(block: BasicBlock, blocks: List[BasicBlock]) = { - block.successors.filter(scc => !blocks.contains(scc)) - } - // get leaving blocks and their outside targets - def leavingBlocks(blocks: List[BasicBlock]): List[(BasicBlock, List[BasicBlock])] = { - for {b <- blocks - val t = outsideTargets(b, blocks) - if t.length != 0 } yield (b, t) - } - - def replaceOutJumps(blocks: List[BasicBlock], leaving: List[(BasicBlock, List[BasicBlock])], exh: ExceptionHandler): (List[BasicBlock], Option[BasicBlock]) = { - def replaceJump(block: BasicBlock, from: BasicBlock, to: BasicBlock) = block.lastInstruction match { - case JUMP(where) => - //assert(from == where) - block.replaceInstruction(block.lastInstruction, JUMP(to)) - case CJUMP(success, failure, cond, kind) => - if (from == success) - block.replaceInstruction(block.lastInstruction, CJUMP(to, failure, cond, kind)) - else - //assert(from == failure) - if (from == failure) - block.replaceInstruction(block.lastInstruction, CJUMP(success, to, cond, kind)) - case CZJUMP(success, failure, cond, kind) => - if (from == success) - block.replaceInstruction(block.lastInstruction, CZJUMP(to, failure, cond, kind)) - else - //assert(from == failure) - if (from == failure) - block.replaceInstruction(block.lastInstruction, CZJUMP(success, to, cond, kind)) - case SWITCH(tags, labels) => // labels: List[BasicBlock] - val newLabels = labels.map(b => if (b == from) to else b) - assert(newLabels.contains(to)) - block.replaceInstruction(block.lastInstruction, SWITCH(tags, newLabels)) - case _ => () //abort("expected branch at the end of block " + block) - } - - val jumpOutBlock = blocks.last.code.newBlock - jumpOutBlock.emit(JUMP(firstBlockAfter(exh))) - jumpOutBlock.close - leaving.foreach(p => { - val lBlock = p._1 - val target = p._2(0) // the elemets of p._2 are all the same, checked before - replaceJump(lBlock, target, jumpOutBlock) - }) - (blocks ::: List(jumpOutBlock), Some(jumpOutBlock)) - } - - val leaving = leavingBlocks(blocks) - if (leaving.length == 0) - (blocks, None) - else if (leaving.length == 1) { - val outside = leaving(0)._2 - //assert(outside.forall(b => b == outside(0)), "exception-block leaving to multiple targets") - if (!firstBlockAfter.isDefinedAt(exh)) - firstBlockAfter(exh) = outside(0) - //else () - //assert(firstBlockAfter(exh) == outside(0), "try/catch leaving to multiple targets: " + firstBlockAfter(exh) + ", new: " + outside(0)) - val last = leaving(0)._1 - (blocks.diff(List(last)) ::: List(last), None) - } else { - val outside = leaving.flatMap(p => p._2) - //assert(outside.forall(b => b == outside(0)), "exception-block leaving to multiple targets") - if (!firstBlockAfter.isDefinedAt(exh)) - firstBlockAfter(exh) = outside(0) - //else - //assert(firstBlockAfter(exh) == outside(0), "try/catch leaving to multiple targets") - replaceOutJumps(blocks, leaving, exh) - } - } - - var affectedHandlers: List[ExceptionHandler] = Nil - untreatedHandlers.foreach( (h) => { - if (h.covers(x)){ - affectedHandlers = h :: affectedHandlers - } - }) - affectedHandlers = affectedHandlers.filter(h => {h.covered.length == affectedHandlers(0).covered.length}) - untreatedHandlers = untreatedHandlers.diff(affectedHandlers) - - // shorter try-catch-finally last (the ones contained in another) - affectedHandlers = affectedHandlers.sort({(h1, h2) => h1.covered.length > h2.covered.length}) - - // more than one catch produces more than one exh, but we only need one - var singleAffectedHandler: ExceptionHandler = affectedHandlers(0) // List[ExceptionHandler] = Nil - var exceptionBlock: Option[ExceptionBlock] = None - affectedHandlers.foreach(h1 => { - val (adaptedBlocks, newBlock) = adaptBlocks(blocksToPut.intersect(h1.blocks), singleAffectedHandler) - newBlock match { - case Some(block) => - blocksToPut = blocksToPut ::: List(block) - h1.addBlock(block) - case None => () - } - val orderedCatchBlocks = h1.startBlock :: adaptedBlocks.diff(List(h1.startBlock)) - - exceptionBlock match { - case Some(excBlock) => - val catchBlock = excBlock.addCatchBlock(h1.cls) - currentBlock = catchBlock - addBlocks(orderedCatchBlocks) - case None => - val excBlock = currentBlock.addExceptionBlock(singleAffectedHandler) - exceptionBlock = Some(excBlock) - - val (tryBlocks, newBlock) = adaptBlocks(blocksToPut.intersect(singleAffectedHandler.covered), singleAffectedHandler) - - newBlock match { - case Some(block) => - blocksToPut = blocksToPut ::: List(block) - singleAffectedHandler.addCoveredBlock(block) - case None => () - } - currentBlock = excBlock.tryBlock - addBlocks(tryBlocks) - - if (singleAffectedHandler.finalizer != null && singleAffectedHandler.finalizer != NoFinalizer) { - val (blocks0, newBlock) = adaptBlocks(blocksToPut.intersect(singleAffectedHandler.finalizer.blocks), singleAffectedHandler) - newBlock match { - case Some(block) => - blocksToPut = blocksToPut ::: List(block) - singleAffectedHandler.finalizer.addBlock(block) - case None => () - } - val blocks = singleAffectedHandler.finalizer.startBlock :: blocks0.diff(List(singleAffectedHandler.finalizer.startBlock)) - currentBlock = excBlock.finallyBlock - addBlocks(blocks) - } - - val catchBlock = excBlock.addCatchBlock(singleAffectedHandler.cls) - currentBlock = catchBlock - addBlocks(orderedCatchBlocks) - } - if (firstBlockAfter.isDefinedAt(singleAffectedHandler)) - nextBlock = firstBlockAfter(singleAffectedHandler) - else - nextBlock = null - }) - - currentBlock = savedCurrentBlock - - if (settings.debug.value) - log(" -> addBlocks(" + xs.intersect(blocksToPut) + ")") - addBlocks(xs.intersect(blocksToPut)) - } + case Nil => if (settings.debug.value) log("adding " + b) + + case x :: xs => + if (settings.debug.value) log("adding " + b) + // problem: block may already be added, and and needs to be moved. + // if nextblock NOT in b: check if nextblock in blocksToPut, if NOT, check if movable, else don't put + if (nextBlock != null && b.contains(nextBlock)) { + val blocksToAdd = nextBlock :: b.diff(List(nextBlock)) + nextBlock = null + addBlocks(blocksToAdd) + } + else if (untreatedHandlers.forall(h => !(h.covers(x)))) { + + if (settings.debug.value) log(" no new handler for " + x) + if (untreatedHandlers.forall(h => !(h.blocks.contains(x) || + (h.finalizer != null && + h.finalizer.covers(x))))) + { + // the block is not part of some catch or finally code + currentBlock.addBasicBlock(x) + blocksToPut = blocksToPut.diff(List(x)) + if (settings.debug.value) log(" -> addBlocks(" + xs + ")") + addBlocks(xs) + } else { + if (settings.debug.value) log("x is part of catch or finally block") + + // check if the covered code of the handler x belongs to is empty + // this check is not needed for finalizers: empty try with finalizer + // is optimized by compiler (no try left) + if(untreatedHandlers.forall(h => + (!h.blocks.contains(x) || h.covered.isEmpty))) { + blocksToPut = blocksToPut.diff(List(x)) + addBlocks(xs) + } else + addBlocks(xs ::: List(x)) + } + } else { // there are new handlers for this block + + var firstBlockAfter: HashMap[ExceptionHandler,BasicBlock] = new HashMap() + val savedCurrentBlock = currentBlock + /** + * the output blocks of this method are changed so that: + * - only one block has a successor outside the set of blocks + * - this block is the last of the reusulting list + * + * side-effect: it stores the successor in the hashMap + * firstBlockAfter, which has to be emitted first after try/catch/finally, + * because the target of the Leave-instruction will always be the first + * instruction after EndExceptionBlock + * + * returns: the output blocks plus an Option containing the possibly created + * new block + **/ + def adaptBlocks(blocks: List[BasicBlock], exh: ExceptionHandler): (List[BasicBlock], Option[BasicBlock]) = { + def outsideTargets(block: BasicBlock, blocks: List[BasicBlock]) = { + block.successors.filter(scc => !blocks.contains(scc)) + } + // get leaving blocks and their outside targets + def leavingBlocks(blocks: List[BasicBlock]): List[(BasicBlock, List[BasicBlock])] = { + for {b <- blocks + val t = outsideTargets(b, blocks) + if t.length != 0 } yield (b, t) + } + + def replaceOutJumps(blocks: List[BasicBlock], leaving: List[(BasicBlock, List[BasicBlock])], exh: ExceptionHandler): (List[BasicBlock], Option[BasicBlock]) = { + def replaceJump(block: BasicBlock, from: BasicBlock, to: BasicBlock) = block.lastInstruction match { + case JUMP(where) => + //assert(from == where) + block.replaceInstruction(block.lastInstruction, JUMP(to)) + case CJUMP(success, failure, cond, kind) => + if (from == success) + block.replaceInstruction(block.lastInstruction, CJUMP(to, failure, cond, kind)) + else + //assert(from == failure) + if (from == failure) + block.replaceInstruction(block.lastInstruction, CJUMP(success, to, cond, kind)) + case CZJUMP(success, failure, cond, kind) => + if (from == success) + block.replaceInstruction(block.lastInstruction, CZJUMP(to, failure, cond, kind)) + else + //assert(from == failure) + if (from == failure) + block.replaceInstruction(block.lastInstruction, CZJUMP(success, to, cond, kind)) + case SWITCH(tags, labels) => // labels: List[BasicBlock] + val newLabels = labels.map(b => if (b == from) to else b) + assert(newLabels.contains(to)) + block.replaceInstruction(block.lastInstruction, SWITCH(tags, newLabels)) + case _ => () //abort("expected branch at the end of block " + block) + } + + val jumpOutBlock = blocks.last.code.newBlock + jumpOutBlock.emit(JUMP(firstBlockAfter(exh))) + jumpOutBlock.close + leaving.foreach(p => { + val lBlock = p._1 + val target = p._2(0) // the elemets of p._2 are all the same, checked before + replaceJump(lBlock, target, jumpOutBlock) + }) + (blocks ::: List(jumpOutBlock), Some(jumpOutBlock)) + } + + val leaving = leavingBlocks(blocks) + if (leaving.length == 0) + (blocks, None) + else if (leaving.length == 1) { + val outside = leaving(0)._2 + //assert(outside.forall(b => b == outside(0)), "exception-block leaving to multiple targets") + if (!firstBlockAfter.isDefinedAt(exh)) + firstBlockAfter(exh) = outside(0) + //else () + //assert(firstBlockAfter(exh) == outside(0), "try/catch leaving to multiple targets: " + firstBlockAfter(exh) + ", new: " + outside(0)) + val last = leaving(0)._1 + (blocks.diff(List(last)) ::: List(last), None) + } else { + val outside = leaving.flatMap(p => p._2) + //assert(outside.forall(b => b == outside(0)), "exception-block leaving to multiple targets") + if (!firstBlockAfter.isDefinedAt(exh)) + firstBlockAfter(exh) = outside(0) + //else + //assert(firstBlockAfter(exh) == outside(0), "try/catch leaving to multiple targets") + replaceOutJumps(blocks, leaving, exh) + } + } + + var affectedHandlers: List[ExceptionHandler] = Nil + untreatedHandlers.foreach( (h) => { + if (h.covers(x)){ + affectedHandlers = h :: affectedHandlers + } + }) + affectedHandlers = affectedHandlers.filter(h => {h.covered.length == affectedHandlers(0).covered.length}) + untreatedHandlers = untreatedHandlers.diff(affectedHandlers) + + // shorter try-catch-finally last (the ones contained in another) + affectedHandlers = affectedHandlers.sort({(h1, h2) => h1.covered.length > h2.covered.length}) + + // more than one catch produces more than one exh, but we only need one + var singleAffectedHandler: ExceptionHandler = affectedHandlers(0) // List[ExceptionHandler] = Nil + var exceptionBlock: Option[ExceptionBlock] = None + affectedHandlers.foreach(h1 => { + val (adaptedBlocks, newBlock) = adaptBlocks(blocksToPut.intersect(h1.blocks), singleAffectedHandler) + newBlock match { + case Some(block) => + blocksToPut = blocksToPut ::: List(block) + h1.addBlock(block) + case None => () + } + val orderedCatchBlocks = h1.startBlock :: adaptedBlocks.diff(List(h1.startBlock)) + + exceptionBlock match { + case Some(excBlock) => + val catchBlock = excBlock.addCatchBlock(h1.cls) + currentBlock = catchBlock + addBlocks(orderedCatchBlocks) + case None => + val excBlock = currentBlock.addExceptionBlock(singleAffectedHandler) + exceptionBlock = Some(excBlock) + + val (tryBlocks, newBlock) = adaptBlocks(blocksToPut.intersect(singleAffectedHandler.covered), singleAffectedHandler) + + newBlock match { + case Some(block) => + blocksToPut = blocksToPut ::: List(block) + singleAffectedHandler.addCoveredBlock(block) + case None => () + } + currentBlock = excBlock.tryBlock + addBlocks(tryBlocks) + + if (singleAffectedHandler.finalizer != null && singleAffectedHandler.finalizer != NoFinalizer) { + val (blocks0, newBlock) = adaptBlocks(blocksToPut.intersect(singleAffectedHandler.finalizer.blocks), singleAffectedHandler) + newBlock match { + case Some(block) => + blocksToPut = blocksToPut ::: List(block) + singleAffectedHandler.finalizer.addBlock(block) + case None => () + } + val blocks = singleAffectedHandler.finalizer.startBlock :: blocks0.diff(List(singleAffectedHandler.finalizer.startBlock)) + currentBlock = excBlock.finallyBlock + addBlocks(blocks) + } + + val catchBlock = excBlock.addCatchBlock(singleAffectedHandler.cls) + currentBlock = catchBlock + addBlocks(orderedCatchBlocks) + } + if (firstBlockAfter.isDefinedAt(singleAffectedHandler)) + nextBlock = firstBlockAfter(singleAffectedHandler) + else + nextBlock = null + }) + + currentBlock = savedCurrentBlock + + if (settings.debug.value) + log(" -> addBlocks(" + xs.intersect(blocksToPut) + ")") + addBlocks(xs.intersect(blocksToPut)) + } } // begin method orderBlocksForExh if (settings.debug.value) - log("before: " + blocks) + log("before: " + blocks) // some blocks may have been removed by linearization untreatedHandlers.foreach(h => { - h.blocks = h.blocks.intersect(blocksToPut) - h.covered = h.covered.intersect(blocksToPut) - if (h.finalizer != null && h.finalizer != NoFinalizer) - h.finalizer.blocks = h.finalizer.blocks.intersect(blocksToPut) + h.blocks = h.blocks.intersect(blocksToPut) + h.covered = h.covered.intersect(blocksToPut) + if (h.finalizer != null && h.finalizer != NoFinalizer) + h.finalizer.blocks = h.finalizer.blocks.intersect(blocksToPut) }) addBlocks(blocks) @@ -1058,71 +1074,71 @@ abstract class GenMSIL extends SubComponent { bb2exHInstructions.clear def addExHInstruction(b: BasicBlock, ehi: ExHInstruction) = { - if (settings.debug.value) - log("adding exhinstr: " + b + " -> " + ehi) + if (settings.debug.value) + log("adding exhinstr: " + b + " -> " + ehi) - if (bb2exHInstructions.contains(b)){ - bb2exHInstructions(b) = ehi :: bb2exHInstructions(b) - } else { - bb2exHInstructions(b) = List(ehi) - } + if (bb2exHInstructions.contains(b)){ + bb2exHInstructions(b) = ehi :: bb2exHInstructions(b) + } else { + bb2exHInstructions(b) = List(ehi) + } } omitJumpBlocks.clear def omitJump(blk: BasicBlock) = { - omitJumpBlocks += blk + omitJumpBlocks += blk } var orderedBlocks: List[BasicBlock] = Nil - def flatten(block: Block): Unit = { - if (block == TopBlock) { - for (b <- TopBlock.blocks) flatten(b) - } else block match { - case cb: CodeBlock => - orderedBlocks = orderedBlocks ::: cb.basicBlocks - case bl: BlockList => - for (b <- bl.blocks) flatten(b) - case cb: CatchBlock => - for (b <- cb.blocks) flatten(b) - case eb: ExceptionBlock => - val handler = eb.handler - addExHInstruction(eb.tryBlock.firstBasicBlock, new BeginExceptionBlock(handler)) - omitJump(eb.tryBlock.lastBasicBlock) - flatten(eb.tryBlock) - for (c <- eb.catchBlocks) { - val t: MsilType = (if (c.exSym == NoSymbol) EXCEPTION - else getType(c.exSym)) - addExHInstruction(c.firstBasicBlock, new BeginCatchBlock(handler, t)) - omitJump(c.lastBasicBlock) - flatten(c) - } - if (handler.finalizer != null && handler.finalizer != NoFinalizer) { - addExHInstruction(eb.finallyBlock.firstBasicBlock, new BeginFinallyBlock(handler)) - flatten(eb.finallyBlock) - addExHInstruction(eb.finallyBlock.lastBasicBlock, new EndExceptionBlock(handler)) - omitJump(eb.finallyBlock.lastBasicBlock) - } else { - addExHInstruction(eb.catchBlocks.last.lastBasicBlock, new EndExceptionBlock(handler)) - } - } + def flatten(block: Block) { + if (block == TopBlock) { + for (b <- TopBlock.blocks) flatten(b) + } else block match { + case cb: CodeBlock => + orderedBlocks = orderedBlocks ::: cb.basicBlocks + case bl: BlockList => + for (b <- bl.blocks) flatten(b) + case cb: CatchBlock => + for (b <- cb.blocks) flatten(b) + case eb: ExceptionBlock => + val handler = eb.handler + addExHInstruction(eb.tryBlock.firstBasicBlock, new BeginExceptionBlock(handler)) + omitJump(eb.tryBlock.lastBasicBlock) + flatten(eb.tryBlock) + for (c <- eb.catchBlocks) { + val t: MsilType = (if (c.exSym == NoSymbol) EXCEPTION + else getType(c.exSym)) + addExHInstruction(c.firstBasicBlock, new BeginCatchBlock(handler, t)) + omitJump(c.lastBasicBlock) + flatten(c) + } + if (handler.finalizer != null && handler.finalizer != NoFinalizer) { + addExHInstruction(eb.finallyBlock.firstBasicBlock, new BeginFinallyBlock(handler)) + flatten(eb.finallyBlock) + addExHInstruction(eb.finallyBlock.lastBasicBlock, new EndExceptionBlock(handler)) + omitJump(eb.finallyBlock.lastBasicBlock) + } else { + addExHInstruction(eb.catchBlocks.last.lastBasicBlock, new EndExceptionBlock(handler)) + } + } } flatten(TopBlock) assert(untreatedHandlers.forall((h) => h.covered.isEmpty), - "untreated exception handlers left: " + untreatedHandlers) + "untreated exception handlers left: " + untreatedHandlers) // remove catch blocks from empty handlers (finally-blocks remain) untreatedHandlers.foreach((h) => { - orderedBlocks = orderedBlocks.diff(h.blocks) + orderedBlocks = orderedBlocks.diff(h.blocks) }) // take care of order in which exHInstructions are executed (BeginExceptionBlock as last) bb2exHInstructions.keys.foreach((b) => { - bb2exHInstructions(b).sort((i1, i2) => (!i1.isInstanceOf[BeginExceptionBlock])) + bb2exHInstructions(b).sort((i1, i2) => (!i1.isInstanceOf[BeginExceptionBlock])) }) if (settings.debug.value){ - log("after: " + orderedBlocks) - log(" exhInstr: " + bb2exHInstructions) + log("after: " + orderedBlocks) + log(" exhInstr: " + bb2exHInstructions) } orderedBlocks @@ -1132,49 +1148,50 @@ abstract class GenMSIL extends SubComponent { var lastBlock: BasicBlock = _ var nextBlock: BasicBlock = _ - def genBlocks(l: List[BasicBlock]): Unit = l match { - case Nil => () - case x :: Nil => currentBlock = x; nextBlock = null; genBlock(x) - case x :: y :: ys => currentBlock = x; nextBlock = y; genBlock(x); genBlocks(y :: ys) + def genBlocks(l: List[BasicBlock]) { + l match { + case Nil => () + case x :: Nil => currentBlock = x; nextBlock = null; genBlock(x) + case x :: y :: ys => currentBlock = x; nextBlock = y; genBlock(x); genBlocks(y :: ys) + } } - var ignoreNextDup: Boolean = false val excResultLocals: Stack[LocalBuilder] = new Stack() - def genBlock(b: BasicBlock): Unit = { + def genBlock(b: BasicBlock) { // at begin of the first block, there's nothing to save => // lastBlock != null is secure def saveResult(resType: MsilType) = if (resType != MVOID && lastBlock != null) { - lastBlock.lastInstruction match { - case THROW() => () - case _ => - val lb: LocalBuilder = excResultLocals.top - mcode.Emit(OpCodes.Stloc, lb) - } + lastBlock.lastInstruction match { + case THROW() => () + case _ => + val lb: LocalBuilder = excResultLocals.top + mcode.Emit(OpCodes.Stloc, lb) + } } if (bb2exHInstructions.contains(b)){ - bb2exHInstructions(b).foreach((i) => i match { - case BeginExceptionBlock(handler) => - if (settings.debug.value) log("begin ex blk: " + handler) - mcode.BeginExceptionBlock() - val resType = msilType(handler.resultKind) - if (resType != MVOID) { - val l = mcode.DeclareLocal(resType) - l.SetLocalSymInfo("$exhResult") - excResultLocals.push(l) - } - case BeginCatchBlock(handler, exType) => - if (settings.debug.value) log("begin catch blk: " + handler + ", tpe: " + exType) - saveResult(msilType(handler.resultKind)) - mcode.BeginCatchBlock(exType) - case BeginFinallyBlock(handler) => - saveResult(msilType(handler.resultKind)) - mcode.BeginFinallyBlock() - case EndExceptionBlock(handler) => () - case _ => abort("unknown case: " + i) - }) + bb2exHInstructions(b).foreach((i) => i match { + case BeginExceptionBlock(handler) => + if (settings.debug.value) log("begin ex blk: " + handler) + mcode.BeginExceptionBlock() + val resType = msilType(handler.resultKind) + if (resType != MVOID) { + val l = mcode.DeclareLocal(resType) + l.SetLocalSymInfo("$exhResult") + excResultLocals.push(l) + } + case BeginCatchBlock(handler, exType) => + if (settings.debug.value) log("begin catch blk: " + handler + ", tpe: " + exType) + saveResult(msilType(handler.resultKind)) + mcode.BeginCatchBlock(exType) + case BeginFinallyBlock(handler) => + saveResult(msilType(handler.resultKind)) + mcode.BeginFinallyBlock() + case EndExceptionBlock(handler) => () + case _ => abort("unknown case: " + i) + }) } mcode.MarkLabel(labels(b)) @@ -1185,19 +1202,19 @@ abstract class GenMSIL extends SubComponent { b traverse ( instr => { - needAdditionalRet = false + needAdditionalRet = false - val currentLineNr = (instr.pos).line match { + val currentLineNr = (instr.pos).line match { case Some(line) => line case None => log("Warning: wrong position in: " + method) lastLineNr - } // if getting line number fails + } // if getting line number fails - if (currentLineNr != lastLineNr) { - mcode.setPosition(currentLineNr) - lastLineNr = currentLineNr - } + if (currentLineNr != lastLineNr) { + mcode.setPosition(currentLineNr) + lastLineNr = currentLineNr + } instr match { case THIS(clasz) => @@ -1207,7 +1224,7 @@ abstract class GenMSIL extends SubComponent { const.tag match { case UnitTag => () case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1 - else OpCodes.Ldc_I4_0) + else OpCodes.Ldc_I4_0) case ByteTag => loadI4(const.byteValue, mcode) case ShortTag => loadI4(const.shortValue, mcode) case CharTag => loadI4(const.charValue, mcode) @@ -1224,107 +1241,107 @@ abstract class GenMSIL extends SubComponent { } case LOAD_ARRAY_ITEM(kind) => - (kind: @unchecked) match { - case BOOL => mcode.Emit(OpCodes.Ldelem_I1) - case BYTE => mcode.Emit(OpCodes.Ldelem_U1) - 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) is not possible, for Array[Array[Int]], the - // load will be case REFERENCE(java.lang.Object) - - // case UNIT is not possible: an Array[Unit] will be an - // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) - } + (kind: @unchecked) match { + case BOOL => mcode.Emit(OpCodes.Ldelem_I1) + case BYTE => mcode.Emit(OpCodes.Ldelem_U1) + 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) is not possible, for Array[Array[Int]], the + // load will be case REFERENCE(java.lang.Object) + + // case UNIT is not possible: an Array[Unit] will be an + // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) + } case LOAD_LOCAL(local) => - if (settings.debug.value) - log("load_local for " + local) - val isArg: Boolean = local.arg - val i = local.index + if (settings.debug.value) + log("load_local for " + local) + val isArg: Boolean = local.arg + val i = local.index if (isArg) { - loadArg(mcode)(i) - } - else { - loadLocal(i, local, mcode) - } + loadArg(mcode)(i) + } + else { + loadLocal(i, local, mcode) + } case LOAD_FIELD(field, isStatic) => if (settings.debug.value) log("LOAD_FIELD with owner: " + field.owner + - " flags: " + Flags.flagsToString(field.owner.flags)) + " flags: " + Flags.flagsToString(field.owner.flags)) - var fieldInfo: FieldInfo = fields.get(field) match { - case Some(fInfo) => fInfo - case None => - val fInfo = getType(field.owner).GetField(msilName(field)) - fields(field) = fInfo + var fieldInfo: 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.Ldsfld else OpCodes.Ldfld, fieldInfo) + } + mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) case LOAD_MODULE(module) => if (settings.debug.value) log("genearting LOAD_MODULE for: " + showsym(module)) - mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(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 UNIT / ARRRAY are not possible (see comment at LOAD_ARRAY_ITEM) - } + (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 UNIT / ARRRAY are not possible (see comment at LOAD_ARRAY_ITEM) + } case STORE_LOCAL(local) => - val isArg: Boolean = local.arg - val i = local.index - if (settings.debug.value) - log("store_local for " + local + ", index " + i) + val isArg: Boolean = local.arg + val i = local.index + if (settings.debug.value) + log("store_local for " + local + ", index " + i) - // there are some locals defined by the compiler that - // are isArg and are need to be stored. + // 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)) - } - } + 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_FIELD(field, isStatic) => - val fieldInfo: FieldInfo = fields.get(field) match { - case Some(fInfo) => fInfo - case None => - val fInfo = getType(field.owner).GetField(msilName(field)) - fields(field) = fInfo + val fieldInfo: 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) + } + mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) case CALL_PRIMITIVE(primitive) => @@ -1332,49 +1349,49 @@ abstract class GenMSIL extends SubComponent { case CALL_METHOD(msym, style) => - if (msym.isClassConstructor) { - val constructorInfo: ConstructorInfo = getConstructor(msym) - (style: @unchecked) match { - // normal constructor calls are Static.. - case Static(_) => + 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) 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)) - { - notInitializedModules -= clasz.symbol - mcode.Emit(OpCodes.Ldarg_0) - mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) - } - } - - } else { - // java.lang.String.substring(int start_incl, int end_excl) - // System.String.Substring(int start_incl, int length) - if (msym == JSTRING_SUBSTRING_INT_INT) { - val endLocal = mcode.DeclareLocal(MINT) - endLocal.SetLocalSymInfo("$substring_end") - mcode.Emit(OpCodes.Stloc, endLocal) - mcode.Emit(OpCodes.Dup) // duplicate start_incl - mcode.Emit(OpCodes.Neg) - mcode.Emit(OpCodes.Ldloc, endLocal) // load end_excl - mcode.Emit(OpCodes.Add) // compute length (-start + end) - } - - var doEmit: Boolean = true - types.get(msym.owner) match { + mcode.Emit(OpCodes.Newobj, constructorInfo) + case SuperCall(_) => + mcode.Emit(OpCodes.Call, constructorInfo) + if (isStaticModule(clasz.symbol) && + notInitializedModules.contains(clasz.symbol)) + { + notInitializedModules -= clasz.symbol + mcode.Emit(OpCodes.Ldarg_0) + mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) + } + } + + } else { + // java.lang.String.substring(int start_incl, int end_excl) + // System.String.Substring(int start_incl, int length) + if (msym == JSTRING_SUBSTRING_INT_INT) { + val endLocal = mcode.DeclareLocal(MINT) + endLocal.SetLocalSymInfo("$substring_end") + mcode.Emit(OpCodes.Stloc, endLocal) + mcode.Emit(OpCodes.Dup) // duplicate start_incl + mcode.Emit(OpCodes.Neg) + mcode.Emit(OpCodes.Ldloc, endLocal) // load end_excl + mcode.Emit(OpCodes.Add) // compute length (-start + end) + } + + var doEmit: Boolean = true + types.get(msym.owner) match { case Some(typ) if (typ.IsEnum) => { - def negBool = { - mcode.Emit(OpCodes.Ldc_I4_0) - mcode.Emit(OpCodes.Ceq) - } - doEmit = false + 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) } + 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 } @@ -1384,75 +1401,75 @@ abstract class GenMSIL extends SubComponent { else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } else - doEmit = true - } + doEmit = true + } case _ => () } - // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType - val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase){ - msym.tpe match { - case MethodType(parameterTypes, resultType) - if (parameterTypes.length == 1 && msym.name == nme.view_) => - val isDel = definitions.isCorrespondingDelegate(resultType, parameterTypes(0)) - (isDel, parameterTypes(0), 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 method: MethodInfo = getMethod(methodSym) - val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) - if (methodSym.isStatic) { - mcode.Emit(OpCodes.Ldftn, method) - } else { - mcode.Emit(OpCodes.Dup) - mcode.Emit(OpCodes.Ldvirtftn, method) - } - mcode.Emit(OpCodes.Newobj, delegCtor) - } - - if (doEmit) { - val methodInfo: MethodInfo = getMethod(msym) - style match { - case SuperCall(_) => - mcode.Emit(OpCodes.Call, methodInfo) - case Dynamic => - mcode.Emit(if (dynToStatMapped(msym)) OpCodes.Call else OpCodes.Callvirt, + // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType + val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase){ + msym.tpe match { + case MethodType(parameterTypes, resultType) + if (parameterTypes.length == 1 && msym.name == nme.view_) => + val isDel = definitions.isCorrespondingDelegate(resultType, parameterTypes(0)) + (isDel, parameterTypes(0), 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 method: MethodInfo = getMethod(methodSym) + val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) + if (methodSym.isStatic) { + mcode.Emit(OpCodes.Ldftn, method) + } else { + mcode.Emit(OpCodes.Dup) + mcode.Emit(OpCodes.Ldvirtftn, method) + } + mcode.Emit(OpCodes.Newobj, delegCtor) + } + + if (doEmit) { + val methodInfo: MethodInfo = getMethod(msym) + style match { + case SuperCall(_) => + mcode.Emit(OpCodes.Call, methodInfo) + case Dynamic => + mcode.Emit(if (dynToStatMapped(msym)) OpCodes.Call else OpCodes.Callvirt, methodInfo) case Static(_) => - mcode.Emit(OpCodes.Call, methodInfo) - } - } - } + mcode.Emit(OpCodes.Call, methodInfo) + } + } + } case BOX(boxType) => emitBox(mcode, boxType) //mcode.Emit(OpCodes.Box, msilType(boxType)) case UNBOX(boxType) => emitUnbox(mcode, boxType) case NEW(REFERENCE(cls)) => - ignoreNextDup = true + ignoreNextDup = true // works also for arrays and reference-types case CREATE_ARRAY(elem) => mcode.Emit(OpCodes.Newarr, msilType(elem)) @@ -1466,102 +1483,102 @@ abstract class GenMSIL extends SubComponent { 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." + // 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(tpe) => mcode.Emit(OpCodes.Castclass, msilType(tpe)) - // no SWITCH is generated when there's - // - a default case ("case _ => ...") in the matching expr - // - OR is used ("case 1 | 2 => ...") + // 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 ist 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: Int = 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)) + // 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 ist 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: Int = 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 (nextBlock != defaultTarget && !omitJumpBlocks.contains(currentBlock)) - mcode.Emit(OpCodes.Br, defaultTarget) + mcode.Emit(OpCodes.Br, defaultTarget) case JUMP(where) => if (nextBlock != where && !omitJumpBlocks.contains(currentBlock)) - mcode.Emit(OpCodes.Br, labels(where)) + mcode.Emit(OpCodes.Br, labels(where)) 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 - if (nextBlock == success || omitJumpBlocks.contains(currentBlock)) { - emitBr(cond.negate, labels(failure), isFloat) - } else { - emitBr(cond, labels(success), isFloat) - if (nextBlock != failure && !omitJumpBlocks.contains(currentBlock)) { - mcode.Emit(OpCodes.Br, labels(failure)) - } - } + // 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 + if (nextBlock == success || omitJumpBlocks.contains(currentBlock)) { + emitBr(cond.negate, labels(failure), isFloat) + } else { + emitBr(cond, labels(success), isFloat) + if (nextBlock != failure && !omitJumpBlocks.contains(currentBlock)) { + mcode.Emit(OpCodes.Br, labels(failure)) + } + } case CZJUMP(success, failure, cond, kind) => - (kind: @unchecked) match { - case BOOL | REFERENCE(_) => - if (nextBlock == success || omitJumpBlocks.contains(currentBlock)) { - emitBrBool(cond.negate, labels(failure)) - } else { - emitBrBool(cond, labels(success)) - if (nextBlock != failure && !omitJumpBlocks.contains(currentBlock)) { - mcode.Emit(OpCodes.Br, labels(failure)) - } - } - } + (kind: @unchecked) match { + case BOOL | REFERENCE(_) => + if (nextBlock == success || omitJumpBlocks.contains(currentBlock)) { + emitBrBool(cond.negate, labels(failure)) + } else { + emitBrBool(cond, labels(success)) + if (nextBlock != failure && !omitJumpBlocks.contains(currentBlock)) { + mcode.Emit(OpCodes.Br, labels(failure)) + } + } + } case RETURN(kind) => - mcode.Emit(OpCodes.Ret) + mcode.Emit(OpCodes.Ret) case THROW() => - mcode.Emit(OpCodes.Throw) + mcode.Emit(OpCodes.Throw) case DROP(kind) => - mcode.Emit(OpCodes.Pop) + mcode.Emit(OpCodes.Pop) case DUP(kind) => - // needed to create new instances - if (!ignoreNextDup) { - mcode.Emit(OpCodes.Dup) - } else { - ignoreNextDup = false - } - + // needed to create new instances + if (!ignoreNextDup) { + mcode.Emit(OpCodes.Dup) + } else { + ignoreNextDup = false + } case MONITOR_ENTER() => - mcode.Emit(OpCodes.Call, MMONITOR_ENTER) + mcode.Emit(OpCodes.Call, MMONITOR_ENTER) case MONITOR_EXIT() => - mcode.Emit(OpCodes.Call, MMONITOR_EXIT) + mcode.Emit(OpCodes.Call, MMONITOR_EXIT) - case SCOPE_ENTER(_) | SCOPE_EXIT(_) => () + case SCOPE_ENTER(_) | SCOPE_EXIT(_) => + () } }) // end b traverse instr => { .. } @@ -1569,34 +1586,34 @@ abstract class GenMSIL extends SubComponent { lastBlock = b // this way, saveResult knows lastBlock if (bb2exHInstructions.contains(b)){ - bb2exHInstructions(b).foreach((i) => i match { - case BeginExceptionBlock(handler) => () - case BeginCatchBlock(handler, exType) => () - case BeginFinallyBlock(handler) => () - case EndExceptionBlock(handler) => - if (settings.debug.value) log("end ex blk: " + handler) - val resType = msilType(handler.resultKind) - if (handler.finalizer == null || handler.finalizer == NoFinalizer) - saveResult(resType) - mcode.EndExceptionBlock() - if (resType != MVOID) { - val lb: LocalBuilder = excResultLocals.pop - mcode.Emit(OpCodes.Ldloc, lb) - } else - needAdditionalRet = true - case _ => abort("unknown case: " + i) - }) + bb2exHInstructions(b).foreach((i) => i match { + case BeginExceptionBlock(handler) => () + case BeginCatchBlock(handler, exType) => () + case BeginFinallyBlock(handler) => () + case EndExceptionBlock(handler) => + if (settings.debug.value) log("end ex blk: " + handler) + val resType = msilType(handler.resultKind) + if (handler.finalizer == null || handler.finalizer == NoFinalizer) + saveResult(resType) + mcode.EndExceptionBlock() + if (resType != MVOID) { + val lb: LocalBuilder = excResultLocals.pop + mcode.Emit(OpCodes.Ldloc, lb) + } else + needAdditionalRet = true + case _ => abort("unknown case: " + i) + }) } } // end genBlock - def genPrimitive(primitive: Primitive, pos: Position): Unit = { + 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) + // 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) } @@ -1613,42 +1630,40 @@ abstract class GenMSIL extends SubComponent { } 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 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 LSL => mcode.Emit(OpCodes.Shl) + case ASR => mcode.Emit(OpCodes.Shr) + case LSR => mcode.Emit(OpCodes.Shr_Un) + } case Conversion(src, dst) => if (settings.debug.value) log("Converting from: " + src + " to: " + dst) - dst match { - case BYTE => mcode.Emit(OpCodes.Conv_U1) - 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: " + method.sourceFile + ":" + - pos.line.get) - } + dst match { + case BYTE => mcode.Emit(OpCodes.Conv_U1) + 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: " + method.sourceFile + ":" + + pos.line.get) + } case ArrayLength(_) => mcode.Emit(OpCodes.Ldlen) case StartConcat => - mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) + mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) case StringConcat(el) => @@ -1657,21 +1672,22 @@ abstract class GenMSIL extends SubComponent { case _ => msilType(el) } - val argTypes:Array[MsilType] = Array(elemType) - val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes ) - mcode.Emit(OpCodes.Callvirt, stringBuilderAppend) + 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) + mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING) - case _ => abort("Unimplemented primitive " + primitive) + case _ => + abort("Unimplemented primitive " + primitive) } } ////////////////////// loading /////////////////////// - def loadI4(value: Int, code: ILGenerator):Unit = value match { + 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) @@ -1683,10 +1699,10 @@ abstract class GenMSIL extends SubComponent { 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) + if (value >= -128 && value <= 127) + code.Emit(OpCodes.Ldc_I4_S, value) + else + code.Emit(OpCodes.Ldc_I4, value) } def loadArg(code: ILGenerator)(i: Int) = i match { @@ -1695,10 +1711,10 @@ abstract class GenMSIL extends SubComponent { 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) + 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) = i match { @@ -1707,10 +1723,10 @@ abstract class GenMSIL extends SubComponent { 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)) + if (i >= -128 && i <= 127) + code.Emit(OpCodes.Ldloc_S, localBuilders(local)) + else + code.Emit(OpCodes.Ldloc, localBuilders(local)) } ////////////////////// labels /////////////////////// @@ -1718,29 +1734,29 @@ abstract class GenMSIL extends SubComponent { val labels: HashMap[BasicBlock, Label] = new HashMap() // labels for branches - def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) = { + 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) + 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) = { + 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 boolen - // method returned false), and we are in the case EQ, then - // we need to emit Brfalse (EQ Zero means false). vice versa + // EQ -> Brfalse, NE -> Brtrue; this is because we come from + // a CZJUMP. If the value on the stack is 0 (e.g. a boolen + // 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) } } - def makeLabels(bs: List[BasicBlock]) = { + def makeLabels(bs: List[BasicBlock]) { if (settings.debug.value) log("Making labels for: " + method) for (bb <- bs) labels(bb) = mcode.DefineLabel() @@ -1752,7 +1768,7 @@ abstract class GenMSIL extends SubComponent { * Compute the indexes of each local variable of the given * method. */ - def computeLocalVarsIndex(m: IMethod): Unit = { + def computeLocalVarsIndex(m: IMethod) { val params = m.params var idx = 1 if (isStaticSymbol(m.symbol)) @@ -1802,9 +1818,9 @@ abstract class GenMSIL extends SubComponent { return "scala.AllRef$" (if (sym.isClass || (sym.isModule && !sym.isMethod)) - sym.fullNameString + sym.fullNameString else - sym.simpleName.toString().trim()) + suffix + sym.simpleName.toString().trim()) + suffix } @@ -1819,14 +1835,14 @@ abstract class GenMSIL extends SubComponent { mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) sym.attributes foreach { a => a match { - case AnnotationInfo(SerializableAttr, _, _) => - // TODO: add the Serializable TypeAttribute also if the attribute - // System.SerializableAttribute is present (.net attribute, not scala) - // Best way to do it: compare with - // definitions.getClass("System.SerializableAttribute").tpe - // when frontend available - mf = mf | TypeAttributes.Serializable - case _ => () + case AnnotationInfo(SerializableAttr, _, _) => + // TODO: add the Serializable TypeAttribute also if the attribute + // System.SerializableAttribute is present (.net attribute, not scala) + // Best way to do it: compare with + // definitions.getClass("System.SerializableAttribute").tpe + // when frontend available + mf = mf | TypeAttributes.Serializable + case _ => () }} mf @@ -1836,18 +1852,18 @@ abstract class GenMSIL extends SubComponent { def msilMethodFlags(sym: Symbol): Short = { var mf: Int = MethodAttributes.HideBySig | (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private - else if (sym hasFlag Flags.PROTECTED) MethodAttributes.Family - else MethodAttributes.Public) + else if (sym hasFlag Flags.PROTECTED) MethodAttributes.Family + else MethodAttributes.Public) if (!sym.isClassConstructor) { if (isStaticSymbol(sym)) - mf = mf | FieldAttributes.Static + mf = mf | FieldAttributes.Static else { - mf = mf | MethodAttributes.Virtual - if (sym.isFinal && !types(sym.owner).IsInterface) - mf = mf | MethodAttributes.Final - if (sym.hasFlag(Flags.DEFERRED) || types(sym.owner).IsInterface) - mf = mf | MethodAttributes.Abstract + mf = mf | MethodAttributes.Virtual + if (sym.isFinal && !types(sym.owner).IsInterface) + mf = mf | MethodAttributes.Final + if (sym.hasFlag(Flags.DEFERRED) || types(sym.owner).IsInterface) + mf = mf | MethodAttributes.Abstract } } @@ -1857,21 +1873,21 @@ abstract class GenMSIL extends SubComponent { 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 + else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem + else FieldAttributes.Public if (sym hasFlag Flags.FINAL) - mf = mf | FieldAttributes.InitOnly + mf = mf | FieldAttributes.InitOnly if (isStaticSymbol(sym)) - mf = mf | FieldAttributes.Static + mf = mf | FieldAttributes.Static // TRANSIENT: "not nerialized", VOLATILE: doesn't exist on .net // TODO: add this attribute also if the class has the custom attribute // System.NotSerializedAttribute sym.attributes.foreach( a => a match { case AnnotationInfo(TransientAtt, _, _) => - mf = mf | FieldAttributes.NotSerialized + mf = mf | FieldAttributes.NotSerialized case _ => () }) @@ -1895,30 +1911,30 @@ abstract class GenMSIL extends SubComponent { val localBuilders: HashMap[Local, LocalBuilder] = new HashMap() - private[GenMSIL] def findEntryPoint(cls: IClass) = { + 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.symbol == definitions.StringClass){ - return true - } - case _ => () - } - } + if (sym.tpe.paramTypes.length == 1) { + toTypeKind(sym.tpe.paramTypes(0)) match { + case ARRAY(elem) => + if (elem.toType.symbol == definitions.StringClass){ + return true + } + case _ => () + } + } false } for (m <- cls.methods) { - if (isEntryPoint(m.symbol)) { - if (entryPoint == null) - entryPoint = m.symbol - } + if (isEntryPoint(m.symbol)) { + if (entryPoint == null) + entryPoint = m.symbol + } } if (firstSourceName == "") - if (cls.symbol.sourceFile != null) // is null for nested classes - firstSourceName = cls.symbol.sourceFile.name + if (cls.symbol.sourceFile != null) // is null for nested classes + firstSourceName = cls.symbol.sourceFile.name } // ##################################################################### @@ -1958,12 +1974,12 @@ abstract class GenMSIL extends SubComponent { } } - def mapType(sym: Symbol, mType: MsilType) = { + def mapType(sym: Symbol, mType: MsilType) { assert(mType != null, showsym(sym)) types(sym) = mType } - def createTypeBuilder(iclass: IClass): Unit = { + def createTypeBuilder(iclass: IClass) { def getMsilType(tpe: Type): MsilType = { val sym = tpe.symbol types.get(sym) match { @@ -1982,16 +1998,16 @@ abstract class GenMSIL extends SubComponent { val superType = if (isInterface(sym)) null else getMsilType(parents.head) if (settings.debug.value) - log("super type: " + parents(0).symbol + ", msil type: " + superType) + log("super type: " + parents(0).symbol + ", msil type: " + superType) val interfaces: Array[MsilType] = parents.tail.map(getMsilType).toArray if (parents.length > 1) { - if (settings.debug.value){ - log("interfaces:") - for (i <- 0.until(interfaces.length)){ - log(" type: " + parents(i + 1).symbol + ", msil type: " + interfaces(i)) - } - } + if (settings.debug.value){ + log("interfaces:") + for (i <- 0.until(interfaces.length)){ + log(" type: " + parents(i + 1).symbol + ", msil type: " + interfaces(i)) + } + } } //TODO here: if the class is not top-level, use DefineNestedType? @@ -2000,18 +2016,19 @@ abstract class GenMSIL extends SubComponent { mapType(sym, tBuilder) } // createTypeBuilder - - def createClassMembers(iclass: IClass): Unit = try { - createClassMembers0(iclass) - } - catch { - case e: Throwable => - System.err.println(showsym(iclass.symbol)) - System.err.println("with methods = " + iclass.methods) - throw e + def createClassMembers(iclass: IClass) { + try { + createClassMembers0(iclass) + } + catch { + case e: Throwable => + System.err.println(showsym(iclass.symbol)) + System.err.println("with methods = " + iclass.methods) + throw e + } } - def createClassMembers0(iclass: IClass): Unit = { + def createClassMembers0(iclass: IClass) { val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder] for (ifield <- iclass.fields) { val sym = ifield.symbol @@ -2037,32 +2054,32 @@ abstract class GenMSIL extends SubComponent { val attr = msilMethodFlags(sym) if (m.symbol.isClassConstructor) { - val constr = + 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.attributes) + constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) + } + mapConstructor(sym, constr) + addAttributes(constr, sym.attributes) } else { - var resType = msilType(m.returnType) - val method = + var resType = msilType(m.returnType) + val method = ownerType.DefineMethod(getMethodName(sym), attr, resType, paramTypes) for (i <- 0.until(paramTypes.length)){ - method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) - } + method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) + } if (!methods.contains(sym)) - mapMethod(sym, method) - addAttributes(method, sym.attributes) + mapMethod(sym, method) + addAttributes(method, sym.attributes) if (settings.debug.value) log("\t created MethodBuilder " + method) } } if (isStaticModule(iclass.symbol)){ - addModuleInstanceField(iclass.symbol) - notInitializedModules += iclass.symbol - addStaticInit(iclass.symbol) + addModuleInstanceField(iclass.symbol) + notInitializedModules += iclass.symbol + addStaticInit(iclass.symbol) } } // createClassMembers @@ -2078,20 +2095,20 @@ abstract class GenMSIL extends SubComponent { private def isCloneable(sym: Symbol): Boolean = { !sym.attributes.forall( a => a match { - case AnnotationInfo(CloneableAttr, _, _) => false - case _ => true + case AnnotationInfo(CloneableAttr, _, _) => false + case _ => true }) } - private def addModuleInstanceField(sym: Symbol): Unit = { + private def addModuleInstanceField(sym: Symbol) { if (settings.debug.value) - log("Adding Module-Instance Field for " + showsym(sym)) + log("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) + tBuilder, + (FieldAttributes.Public | + //FieldAttributes.InitOnly | + FieldAttributes.Static).toShort) fields(sym) = fb } @@ -2121,13 +2138,13 @@ abstract class GenMSIL extends SubComponent { //fields(moduleClassSym) } - private def addStaticInit(sym: Symbol): Unit = { + private def addStaticInit(sym: Symbol) { val tBuilder = getType(sym).asInstanceOf[TypeBuilder] val staticInit = tBuilder.DefineConstructor( - (MethodAttributes.Static | MethodAttributes.Public).toShort, - CallingConventions.Standard, - MsilType.EmptyTypes) + (MethodAttributes.Static | MethodAttributes.Public).toShort, + CallingConventions.Standard, + MsilType.EmptyTypes) val sicode = staticInit.GetILGenerator() @@ -2140,8 +2157,7 @@ abstract class GenMSIL extends SubComponent { sicode.Emit(OpCodes.Ret) } - - private def dumpMirrorClass(sym: Symbol): Unit = { + private def dumpMirrorClass(sym: Symbol) { val tBuilder = getType(sym) assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) if (settings.debug.value) @@ -2149,44 +2165,44 @@ abstract class GenMSIL extends SubComponent { val moduleName = msilName(sym) val mirrorName = moduleName.substring(0, moduleName.length() - 1) val mirrorTypeBuilder = mmodule.DefineType(mirrorName, - TypeAttributes.Class | - TypeAttributes.Public | - TypeAttributes.Sealed, - //FIXME: an object may have a super-type (a class, not an object) -> not in mirror class? - MOBJECT, - MsilType.EmptyTypes) + TypeAttributes.Class | + TypeAttributes.Public | + TypeAttributes.Sealed, + //FIXME: an object may have a super-type (a class, not an object) -> not in mirror class? + MOBJECT, + MsilType.EmptyTypes) for (m <- sym.tpe.nonPrivateMembers if m.owner != definitions.ObjectClass && !m.hasFlag(Flags.PROTECTED) && m.isMethod && !m.isClassConstructor && !isStaticSymbol(m) && !m.hasFlag(Flags.CASE)) - { - if (settings.debug.value) + { + if (settings.debug.value) log(" 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(getMethodName(m), - MethodAttributes.Public | - MethodAttributes.Static, - msilType(m.tpe.resultType), - paramTypes) - - var i = 0 - while(i < paramTypes.length) { - mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i)) - i = i + 1 - } - - val mirrorCode = mirrorMethod.GetILGenerator() - mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym)) + // CHECK: verify if getMethodName is better than msilName + val mirrorMethod = mirrorTypeBuilder.DefineMethod(getMethodName(m), + MethodAttributes.Public | + MethodAttributes.Static, + 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)) 0.until(paramTypes.length) foreach loadArg(mirrorCode) - mirrorCode.Emit(OpCodes.Call, getMethod(m)) - mirrorCode.Emit(OpCodes.Ret) - } + mirrorCode.Emit(OpCodes.Call, getMethod(m)) + mirrorCode.Emit(OpCodes.Ret) + } addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder) @@ -2202,31 +2218,31 @@ abstract class GenMSIL extends SubComponent { private def initDelegateCallers() = { delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public | - TypeAttributes.Sealed) + TypeAttributes.Sealed) } private def createDelegateCaller(functionType: Type, delegateType: Type) = { if (delegateCallers == null) - initDelegateCallers() + 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) + "$anonfunField$$" + nbDelegateCallers, mFunctionType, + FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static) mcode.Emit(OpCodes.Stsfld, anonfunField) // create the static caller method and the delegate object val (paramTypes, returnType) = delegateType.member(nme.apply).tpe match { - case MethodType(delParams, delReturn) => (delParams, delReturn) - case _ => abort("not a delegate type: " + delegateType) + 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, - msilType(returnType), paramTypes.map(msilType).toArray) + "$delegateCaller$$" + nbDelegateCallers, + MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static, + msilType(returnType), paramTypes.map(msilType).toArray) for (i <- 0 until paramTypes.length) - caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) + caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) mcode.Emit(OpCodes.Ldnull) mcode.Emit(OpCodes.Ldftn, caller) @@ -2238,8 +2254,8 @@ abstract class GenMSIL extends SubComponent { val dcode: ILGenerator = caller.GetILGenerator() dcode.Emit(OpCodes.Ldsfld, anonfunField) for (i <- 0 until paramTypes.length) { - loadArg(dcode)(i) - emitBox(dcode, toTypeKind(paramTypes(i))) + loadArg(dcode)(i) + emitBox(dcode, toTypeKind(paramTypes(i))) } dcode.Emit(OpCodes.Callvirt, functionApply) emitUnbox(dcode, toTypeKind(returnType)) @@ -2339,7 +2355,7 @@ abstract class GenMSIL extends SubComponent { /* * add a mapping between sym and mInfo */ - private def mapMethod(sym: Symbol, mInfo: MethodInfo):Unit = { + private def mapMethod(sym: Symbol, mInfo: MethodInfo) { assert (mInfo != null, mInfo) methods(sym) = mInfo } @@ -2347,10 +2363,10 @@ abstract class GenMSIL extends SubComponent { /* * add mapping between sym and method with newName, paramTypes of newClass */ - private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]): Unit = { + 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 + ")") + newName + "(" + paramTypes + ")") mapMethod(sym, methodInfo) if (methodInfo.IsStatic) dynToStatMapped += sym @@ -2363,11 +2379,11 @@ abstract class GenMSIL extends SubComponent { */ private def mapMethod( clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String, newParamTypes: Array[MsilType]):Unit = { - val methodSym = lookupMethod(clazz, name, paramTypes) - assert(methodSym != null, "cannot find method " + name + "(" + - paramTypes + ")" + " in class " + clazz) - mapMethod(methodSym, newClass, newName, newParamTypes) + 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) } /* @@ -2376,8 +2392,8 @@ abstract class GenMSIL extends SubComponent { */ private def mapMethod( clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String):Unit = { - mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) + newClass: MsilType, newName: String) { + mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) } /* @@ -2386,51 +2402,52 @@ abstract class GenMSIL extends SubComponent { */ private def mapMethod( clazz: Symbol, name: Name, - newClass: MsilType, newName: String):Unit = { - 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))) + 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(paramTypes, resType) => - mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) + // paramTypes: List[Type], resType: Type + case MethodType(paramTypes, resType) => + mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) - case _ => abort("member not found: " + clazz + ", " + name) - } + 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 = { + 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 = 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) + 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) } } @@ -2438,19 +2455,19 @@ abstract class GenMSIL extends SubComponent { val name = methodSym.name val params = methodSym.tpe.paramTypes if (name == nme.finalize_ && params.length == 0) - "Finalize" + "Finalize" else if (name == nme.toString_ && params.length == 0) - "ToString" + "ToString" else if (name == nme.hashCode_ && params.length == 0) - "GetHashCode" + "GetHashCode" else if (name == nme.equals_ && params.length == 1 && - params(0) == definitions.ObjectClass.tpe) - "Equals" + params(0) == definitions.ObjectClass.tpe) + "Equals" // FIXME: why is there no nme.clone_ ? else if (name.toString() == "clone" && params.length == 0) - "Clone" + "Clone" else - msilName(methodSym) + msilName(methodSym) } private def showsym(sym: Symbol): String = (sym.toString + -- cgit v1.2.3