summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2007-02-06 16:06:34 +0000
committermihaylov <mihaylov@epfl.ch>2007-02-06 16:06:34 +0000
commitf54efe4dc3d13ffab28e6c1e7b0fced4b79eb8d0 (patch)
treeedc177727863228bfaa809ecb7c9dee89c6bc4fb
parent89e9d67df8a1cfa075808da59238b20f406f7f51 (diff)
downloadscala-f54efe4dc3d13ffab28e6c1e7b0fced4b79eb8d0.tar.gz
scala-f54efe4dc3d13ffab28e6c1e7b0fced4b79eb8d0.tar.bz2
scala-f54efe4dc3d13ffab28e6c1e7b0fced4b79eb8d0.zip
Merged the dotnet-scala branch
-rw-r--r--build.xml18
-rw-r--r--lib/msil.jar.desired.sha12
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala17
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala46
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala35
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala2464
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala149
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala164
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala254
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala506
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala50
-rw-r--r--src/library/scala/Console.scala6
-rw-r--r--src/library/scala/Enumeration.scala2
-rw-r--r--src/library/scala/compat/Platform.scala5
-rw-r--r--src/library/scala/runtime/BoxedObjectArray.scala4
-rw-r--r--src/library/scala/util/automata/BaseBerrySethi.scala9
-rw-r--r--test/files/jvm/bug560bis.check (renamed from test/files/run/bug560bis.check)0
-rw-r--r--test/files/jvm/bug560bis.scala (renamed from test/files/run/bug560bis.scala)0
-rw-r--r--test/files/run/Course-2002-03.scala8
-rw-r--r--test/files/run/bugs.scala12
-rw-r--r--test/files/run/richs-msil.check66
-rw-r--r--test/files/run/richs.check3
-rw-r--r--test/files/run/richs.scala40
-rw-r--r--test/files/run/try.scala4
-rwxr-xr-xtest/scalatest4
33 files changed, 3736 insertions, 158 deletions
diff --git a/build.xml b/build.xml
index 4170ac5d3a..fc645de8b5 100644
--- a/build.xml
+++ b/build.xml
@@ -39,6 +39,7 @@ PROPERTIES
<property name="lib.starr.jar" value="${lib.dir}/scala-library.jar"/>
<property name="comp.starr.jar" value="${lib.dir}/scala-compiler.jar"/>
<property name="fjbg.jar" value="${lib.dir}/fjbg.jar"/>
+ <property name="msil.jar" value="${lib.dir}/msil.jar"/>
<property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
<property name="ant-contrib.jar" value="${lib.dir}/ant-contrib.jar"/>
<!-- Sets location of build folders -->
@@ -77,6 +78,7 @@ INITIALISATION
<available file="${lib.starr.jar}"/>
<available file="${comp.starr.jar}"/>
<available file="${fjbg.jar}"/>
+ <available file="${msil.jar}"/>
<available file="${ant-contrib.jar}"/>
</and></not></condition>
</fail>
@@ -206,6 +208,7 @@ SETUP
<pathelement location="${locker.dir}/lib/library"/>
<pathelement location="${locker.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
</path>
<taskdef
name="locker"
@@ -218,6 +221,7 @@ SETUP
<pathelement location="${quick.dir}/lib/library"/>
<pathelement location="${quick.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
</path>
<taskdef
name="quick" classname="scala.tools.ant.Scalac"
@@ -268,6 +272,15 @@ BUILD SUPPORT MACROS
resource="${fjbg.jar}" overwrite="yes" failonerror="no"/>
</else></if>
</then></if>
+ <if><not><available file="@{build.dir}/lib/msil.jar"/></not><then>
+ <if><isset property="os.win"/><then>
+ <copy file="${msil.jar}" tofile="@{build.dir}/lib/msil.jar"/>
+ </then><else>
+ <symlink
+ link="@{build.dir}/lib/msil.jar"
+ resource="${msil.jar}" overwrite="yes" failonerror="no"/>
+ </else></if>
+ </then></if>
</sequential>
</macrodef>
@@ -317,6 +330,7 @@ BUILD LOCAL REFERENCE (LOCKER) LAYER
<pathelement location="${locker.dir}/lib/library"/>
<pathelement location="${locker.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
</classpath>
<include name="**/*.scala"/>
@@ -462,6 +476,7 @@ BUILD QUICK-TEST LAYER
<pathelement location="${quick.dir}/lib/library"/>
<pathelement location="${quick.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
</classpath>
<include name="**/*.scala"/>
@@ -607,6 +622,7 @@ TEST
<pathelement location="${strap.dir}/lib/library"/>
<pathelement location="${strap.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
</classpath>
<include name="**/*.scala"/>
@@ -743,6 +759,7 @@ DOCUMENTATION
<pathelement location="${quick.dir}/lib/library"/>
<pathelement location="${quick.dir}/lib/compiler"/>
<pathelement location="${fjbg.jar}"/>
+ <pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
</classpath>
<include name="**/*.scala"/>
@@ -851,6 +868,7 @@ GENERATES A DISTRIBUTION
<jar destfile="${dist.current.dir}/lib/${comp.jar.name}">
<fileset dir="${strap.dir}/lib/compiler"/>
<zipfileset src="${fjbg.jar}"/>
+ <zipfileset src="${msil.jar}"/>
<manifest>
<attribute name="Signature-Version" value="${version.number}"/>
<attribute name="Built-By" value="${user.name}"/>
diff --git a/lib/msil.jar.desired.sha1 b/lib/msil.jar.desired.sha1
index 90c937b347..16a870321d 100644
--- a/lib/msil.jar.desired.sha1
+++ b/lib/msil.jar.desired.sha1
@@ -1 +1 @@
-eee44b93d8b1936061e55ec9207e8c4151198e08 ?msil.jar
+faa61a2a0ffb671563efed989c0ae5c265d75ae1 ?msil.jar
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index e32544f12d..29ab8b6183 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -28,6 +28,7 @@ import transform._
import backend.icode.{ICodes, GenICode, Checkers}
import backend.ScalaPrimitives
import backend.jvm.GenJVM
+import backend.msil.GenMSIL
import backend.opt.{Inliners, ClosureElimination, DeadCodeElimination}
import backend.icode.analysis._
@@ -170,11 +171,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val classPath0 = new ClassPath(false && onlyPresentation)
val classPath = new classPath0.Build(
- settings.classpath.value,
+ if (forMSIL) "" else settings.classpath.value,
settings.sourcepath.value,
settings.outdir.value,
- settings.bootclasspath.value,
- settings.extdirs.value)
+ if (forMSIL) "" else settings.bootclasspath.value,
+ if (forMSIL) "" else settings.extdirs.value)
if (settings.verbose.value) {
inform("[Classpath = " + classPath+"]")
@@ -201,7 +202,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this
}
- def rootLoader: LazyType = new loaders.PackageLoader(classPath.root /* getRoot() */)
+ def rootLoader: LazyType = if (forMSIL) new loaders.NamespaceLoader(classPath.root)
+ else new loaders.PackageLoader(classPath.root /* getRoot() */)
val migrateMsg = "migration problem when moving from Scala version 1.0 to version 2.0:\n"
@@ -343,6 +345,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this
}
+ object genMSIL extends GenMSIL {
+ val global: Global.this.type = Global.this
+ }
+
object icodeChecker extends checkers.ICodeChecker()
object typer extends analyzer.Typer(
@@ -371,7 +377,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// inliner,
// closureElimination,
// deadCode,
- genJVM,
+ if (forMSIL) genMSIL else genJVM,
sampleTransform)
protected def insertBefore(c: SubComponent, cs: List[SubComponent], before: SubComponent): List[SubComponent] = cs match {
@@ -633,6 +639,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
def forCLDC: Boolean = settings.target.value == "cldc"
+ def forMSIL: Boolean = settings.target.value == "msil"
def onlyPresentation = settings.doc.value
// position stuff
final val positionConfiguration: PositionConfiguration = initConfig;
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 8013b219b7..8bb895745b 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -92,6 +92,8 @@ class Settings(error: String => unit) {
val documenttitle = StringSetting ("-documenttitle", "documenttitle", "Specify document title of generated HTML documentation", documenttitleDefault)
val target = ChoiceSetting ("-target", "Specify which backend to use", List("jvm-1.5", "jvm-1.4", "msil", "cldc"), "jvm-1.4")
val migrate = BooleanSetting("-migrate", "Assist in migrating from Scala version 1.0")
+ val assemname = StringSetting ("-o", "file", "Name of the output assembly (only relevant with -target:msil)", "")
+ val assemrefs = StringSetting ("-r", "path", "List of assemblies referenced by the program (only relevant with -target:msil)", ".")
val debug = new BooleanSetting("-debug", "Output debugging messages") { override def hiddenToIDE = true }
val deprecation = BooleanSetting ("-deprecation", "enable detailed deprecation warnings")
val unchecked = BooleanSetting ("-unchecked", "enable detailed unchecked warnings")
diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
index b665e3fbc1..1e3253186d 100644
--- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -445,7 +445,7 @@ abstract class ScalaPrimitives {
/** Add a primitive operation to the map */
def addPrimitive(s: Symbol, code: Int): Unit = {
assert(!(primitives contains s), "Duplicate primitive " + s)
- primitives += s -> code
+ primitives(s) = code
}
def addPrimitives(cls: Symbol, method: Name, code: Int): Unit = {
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
index 8f9d0a52e8..dd6a0a4487 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
@@ -24,6 +24,8 @@ trait ExceptionHandlers requires ICodes {
private var _startBlock: BasicBlock = _;
var finalizer: Finalizer = _;
+ var resultKind: TypeKind = _;
+
def setStartBlock(b: BasicBlock) = _startBlock = b;
def startBlock = _startBlock;
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 82f6eadc44..7dc3b8524f 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -480,14 +480,14 @@ abstract class GenICode extends SubComponent {
val kind = toTypeKind(tree.tpe)
var handlers = for (val CaseDef(pat, _, body) <- catches.reverse)
yield pat match {
- case Typed(Ident(nme.WILDCARD), tpt) => Pair(tpt.tpe.symbol, {
+ case Typed(Ident(nme.WILDCARD), tpt) => Triple(tpt.tpe.symbol, kind, {
ctx: Context =>
ctx.bb.emit(DROP(REFERENCE(tpt.tpe.symbol)));
val ctx1 = genLoad(body, ctx, kind);
genLoad(finalizer, ctx1, UNIT);
})
- case Ident(nme.WILDCARD) => Pair(definitions.ThrowableClass, {
+ case Ident(nme.WILDCARD) => Triple(definitions.ThrowableClass, kind, {
ctx: Context =>
ctx.bb.emit(DROP(REFERENCE(definitions.ThrowableClass)))
val ctx1 = genLoad(body, ctx, kind)
@@ -498,7 +498,7 @@ abstract class GenICode extends SubComponent {
val exception = new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false)
ctx.method.addLocal(exception);
- Pair(pat.symbol.tpe.symbol, {
+ Triple(pat.symbol.tpe.symbol, kind, {
ctx: Context =>
ctx.bb.emit(STORE_LOCAL(exception), pat.pos);
val ctx1 = genLoad(body, ctx, kind);
@@ -507,7 +507,7 @@ abstract class GenICode extends SubComponent {
}
if (finalizer != EmptyTree)
- handlers = Pair(NoSymbol, {
+ handlers = Triple(NoSymbol, kind, {
ctx: Context =>
val exception = new Local(ctx.method.symbol.newVariable(finalizer.pos, unit.fresh.newName("exc"))
.setFlag(Flags.SYNTHETIC)
@@ -686,10 +686,10 @@ abstract class GenICode extends SubComponent {
ctx1.bb.close
ctx1.newBlock
- } else if (isPrimitive(fun.symbol)) { // primitive method call
+ } else if (isPrimitive(sym)) { // primitive method call
val Select(receiver, _) = fun
- val code = scalaPrimitives.getPrimitive(fun.symbol, receiver.tpe)
+ val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
var ctx1 = ctx
if (scalaPrimitives.isArithmeticOp(code)) {
@@ -733,6 +733,7 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("synchronized block start");
+
ctx1 = ctx1.Try(
bodyCtx => {
val ctx1 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */)
@@ -740,7 +741,8 @@ abstract class GenICode extends SubComponent {
ctx1.bb.emit(MONITOR_EXIT(), tree.pos)
ctx1
}, List(
- Pair(NoSymbol, exhCtx => {
+ // tree.tpe / fun.tpe is object, which is no longer true after this transformation
+ Triple(NoSymbol, expectedType, exhCtx => {
exhCtx.bb.emit(LOAD_LOCAL(monitor))
exhCtx.bb.emit(MONITOR_EXIT(), tree.pos)
exhCtx.bb.emit(THROW())
@@ -756,9 +758,8 @@ abstract class GenICode extends SubComponent {
genCoercion(tree, ctx1, code)
generatedType = scalaPrimitives.generatedKind(code)
} else
- abort("Primitive operation not handled yet: " +
- fun.symbol.fullNameString + "(" + fun.symbol.simpleName + ") "
- + " at: " + unit.position(tree.pos));
+ abort("Primitive operation not handled yet: " + sym.fullNameString + "(" +
+ fun.symbol.simpleName + ") " + " at: " + unit.position(tree.pos));
ctx1
} else { // normal method call
if (settings.debug.value)
@@ -775,7 +776,7 @@ abstract class GenICode extends SubComponent {
if (invokeStyle.hasInstance) genLoadQualifier(fun, ctx)
else ctx
- ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx1)
+ ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1)
val hostClass = fun match {
case Select(qualifier, _)
@@ -983,6 +984,11 @@ abstract class GenICode extends SubComponent {
def isStaticSymbol(s: Symbol): Boolean =
s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass
+// def isUnbox(s: Symbol): Boolean = (
+// s.name.==(nme.unbox) && s.owner.isModuleClass
+// && s.owner.linkedClassOfClass.isSubClass(definitions.AnyValClass)
+// )
+
/**
* Generate code that loads args into label parameters.
*/
@@ -1044,7 +1050,7 @@ abstract class GenICode extends SubComponent {
* @param ctx ...
* @param cast ...
*/
- def genBoxedConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = {
+ def genBoxedConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean): Unit = {
assert(to.isValueType || to.isArrayType,
"Expecting conversion to value type: " + to)
@@ -1054,7 +1060,12 @@ abstract class GenICode extends SubComponent {
case ARRAY(elem) =>
definitions.boxedArrayClass(elem.toType.symbol)
case _ =>
- definitions.boxedClass(to.toType.symbol)
+ if (cast) {
+ ctx.bb.emit(UNBOX(to))
+ return
+ }
+ else
+ definitions.boxedClass(to.toType.symbol)
}
if (cast) {
@@ -1709,9 +1720,10 @@ abstract class GenICode extends SubComponent {
* 'covered' by this exception handler (in addition to the
* previously active handlers).
*/
- def newHandler(cls: Symbol): ExceptionHandler = {
+ def newHandler(cls: Symbol, resultKind: TypeKind): ExceptionHandler = {
handlerCount = handlerCount + 1
val exh = new ExceptionHandler(method, "" + handlerCount, cls)
+ exh.resultKind = resultKind
method.addHandler(exh)
handlers = exh :: handlers
if (settings.debug.value)
@@ -1762,14 +1774,14 @@ abstract class GenICode extends SubComponent {
* } ))</code>
*/
def Try(body: Context => Context,
- handlers: List[Pair[Symbol, (Context => Context)]],
+ handlers: List[Triple[Symbol, TypeKind, (Context => Context)]],
finalizer: Tree) = {
val outerCtx = this.dup
val afterCtx = outerCtx.newBlock
val exhs = handlers.map { handler =>
- val exh = this.newHandler(handler._1)
- val ctx1 = handler._2(outerCtx.enterHandler(exh))
+ val exh = this.newHandler(handler._1, handler._2)
+ val ctx1 = handler._3(outerCtx.enterHandler(exh))
ctx1.bb.emit(JUMP(afterCtx.bb))
ctx1.bb.close
exh
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 20c1c190ed..0946d75672 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -32,23 +32,7 @@ trait TypeKinds requires ICodes {
* represent the types that the VM know (or the ICode
* view of what VMs know).
*/
- abstract class TypeKind {
-
- /** Returns a string representation of this type kind. */
- override def toString(): String = this match {
- case UNIT => "UNIT"
- case BOOL => "BOOL"
- case BYTE => "BYTE"
- case SHORT => "SHORT"
- case CHAR => "CHAR"
- case INT => "INT"
- case LONG => "LONG"
- case FLOAT => "FLOAT"
- case DOUBLE => "DOUBLE"
- case REFERENCE(cls) => "REFERENCE(" + cls.fullNameString + ")"
- case ARRAY(elem) => "ARRAY[" + elem + "]"
- case _ => abort("Unkown type kind.")
- }
+ sealed abstract class TypeKind {
def toType: Type = this match {
case UNIT => definitions.UnitClass.tpe
@@ -61,6 +45,7 @@ trait TypeKinds requires ICodes {
case FLOAT => definitions.FloatClass.tpe
case DOUBLE => definitions.DoubleClass.tpe
case REFERENCE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil)
+ //case VALUE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil);
case ARRAY(elem) => typeRef(definitions.ArrayClass.typeConstructor.prefix,
definitions.ArrayClass,
elem.toType :: Nil)
@@ -216,7 +201,7 @@ trait TypeKinds requires ICodes {
// }
/** A class type. */
- case class REFERENCE(cls: Symbol) extends TypeKind {
+ final case class REFERENCE(cls: Symbol) extends TypeKind {
assert(cls ne null,
"REFERENCE to null class symbol.")
assert(cls != definitions.ArrayClass,
@@ -260,8 +245,20 @@ trait TypeKinds requires ICodes {
}
}
+// final case class VALUE(cls: Symbol) extends TypeKind {
+// override def equals(other: Any): Boolean = other match {
+// case VALUE(cls2) => cls == cls2;
+// case _ => false;
+// }
+
+// def maxType(other: TypeKind): TypeKind =
+// abort(toString() + " maxType " + other.toString());
+
+// override def toString(): String =
+// "VALUE(" + cls.fullNameString + ")";
+// }
- case class ARRAY(val elem: TypeKind) extends TypeKind {
+ final case class ARRAY(val elem: TypeKind) extends TypeKind {
override def toString(): String =
"ARRAY[" + elem + "]"
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
new file mode 100644
index 0000000000..e4f66a861a
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -0,0 +1,2464 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2007 LAMP/EPFL
+ */
+
+// $Id$
+
+package scala.tools.nsc.backend.msil
+
+import java.io.File
+import java.nio.{ByteBuffer, ByteOrder}
+
+import scala.collection.mutable.{Map, HashMap, HashSet, Stack}
+import scala.tools.nsc.symtab._
+import scala.tools.nsc.util.Position
+import compat.StringBuilder
+
+import ch.epfl.lamp.compiler.msil.{Type => MsilType, _}
+import ch.epfl.lamp.compiler.msil.emit._
+
+/**
+ */
+abstract class GenMSIL extends SubComponent {
+ import global._
+ import loaders.clrTypes
+ import clrTypes.{types, constructors, methods, fields}
+ import icodes._
+ import icodes.opcodes._
+
+ /** Create a new phase */
+ override def newPhase(p: Phase) = new MsilPhase(p)
+
+ val phaseName = "msil"
+ /** MSIL code generation phase
+ */
+ class MsilPhase(prev: Phase) extends GlobalPhase(prev) {
+ def name = phaseName
+ override def newFlags = phaseNewFlags
+
+ override def erasedTypes = true
+
+ override def run: Unit = {
+ if (settings.debug.value) inform("[running phase " + name + " on icode]")
+
+ val codeGenerator = new BytecodeGenerator
+
+ //classes is ICodes.classes, a HashMap[Symbol, IClass]
+ classes.values foreach codeGenerator.findEntryPoint
+
+ codeGenerator.initAssembly
+
+ classes.values foreach codeGenerator.createTypeBuilder
+ classes.values foreach codeGenerator.createClassMembers
+
+
+ try {
+ classes.values foreach codeGenerator.genClass
+ } finally {
+ codeGenerator.writeAssembly
+ }
+ }
+
+ override def apply(unit: CompilationUnit): Unit =
+ abort("MSIL works on icode classes, not on compilation units!")
+ }
+
+ /**
+ * MSIL bytecode generator.
+ *
+ */
+ class BytecodeGenerator {
+
+ val MODULE_INSTANCE_NAME = "MODULE$"
+
+ import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, UBYTE => MBYTE, SHORT => MSHORT,
+ CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT,
+ DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING,
+ STRING_ARRAY => MSTRING_ARRAY, SCALA_SYMTAB_ATTR => SYMTAB_ATTRIBUTE,
+ SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR,
+ SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR}
+
+ val EXCEPTION = clrTypes.getType("System.Exception")
+ val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE)
+
+ val ICLONEABLE = clrTypes.getType("System.ICloneable")
+ val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes)
+
+ val MMONITOR = clrTypes.getType("System.Threading.Monitor")
+ val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT))
+ val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT))
+
+ val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder")
+ val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes)
+ val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString",
+ MsilType.EmptyTypes)
+
+ val TYPE_FROM_HANDLE =
+ clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle")))
+
+ val INT_PTR = clrTypes.getType("System.IntPtr")
+
+ val JOBJECT = definitions.ObjectClass
+ val JSTRING = definitions.StringClass
+
+ var JSTRING_SUBSTRING_INT_INT: Symbol = _
+
+ val SystemConvert = clrTypes.getType("System.Convert")
+
+ val objParam = Array(MOBJECT)
+
+// val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam)
+ val toByte: MethodInfo = SystemConvert.GetMethod("ToByte", objParam)
+ val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam)
+ val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam)
+ val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam)
+ val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam)
+ val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam)
+ val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam)
+
+ //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT")
+ val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT)
+
+ // Scala attributes
+ // symtab.Definitions -> object (singleton..)
+ val SerializableAttr = definitions.SerializableAttr.tpe
+ val CloneableAttr = definitions.getClass("scala.cloneable").tpe
+ val TransientAtt = definitions.getClass("scala.transient").tpe
+ // remoting: the architectures are too different, no mapping (no portable code
+ // possible)
+
+ // java instance methods that are mapped to static methods in .net
+ // these will need to be called with OpCodes.Call (not Callvirt)
+ val dynToStatMapped: HashSet[Symbol] = new HashSet()
+
+ initMappings()
+ // ********************************************************************
+ // Create the mappings
+ private def initMappings(): Unit = {
+ mapType(definitions.AnyClass, MOBJECT)
+ mapType(definitions.AnyRefClass, MOBJECT)
+ //mapType(definitions.AllRefClass, clrTypes.getType("scala.AllRef$"))
+ //mapType(definitions.AllClass, clrTypes.getType("scala.All$"))
+ // FIXME: for some reason the upper two lines map to null
+ mapType(definitions.AllRefClass, EXCEPTION)
+ mapType(definitions.AllClass, EXCEPTION)
+
+ val jEmpty = new Array[Type](0)
+ val jString1 = Array(JSTRING.tpe)
+ val jInt1 = Array(definitions.IntClass.tpe)
+ val jInt2 = Array(definitions.IntClass.tpe, definitions.IntClass.tpe)
+ val jLong1 = Array(definitions.LongClass.tpe)
+ val jStringInt = Array(JSTRING.tpe, definitions.IntClass.tpe)
+ val jChar2 = Array(definitions.CharClass.tpe, definitions.CharClass.tpe)
+
+ val mObject1 = Array(MOBJECT)
+ val mString1 = Array(MSTRING)
+ val mString2 = Array(MSTRING, MSTRING)
+ val mChar1 = Array(MCHAR)
+ val mCharInt = Array(MCHAR, MINT)
+
+ JSTRING_SUBSTRING_INT_INT = lookupMethod(JSTRING, "substring", jInt2)
+
+ mapMethod(JOBJECT, "clone", MOBJECT, "MemberwiseClone")
+ mapMethod(JOBJECT, nme.equals_, MOBJECT, "Equals")
+ mapMethod(JOBJECT, nme.hashCode_, MOBJECT, "GetHashCode")
+ mapMethod(JOBJECT, nme.toString_, MOBJECT, "ToString")
+ mapMethod(JOBJECT, nme.finalize_, MOBJECT, "Finalize")
+ mapMethod(JOBJECT, nme.wait_, jEmpty, MMONITOR, "Wait", mObject1)
+ mapMethod(JOBJECT, nme.wait_, jLong1, MMONITOR, "Wait", Array(MOBJECT, MINT))
+ mapMethod(JOBJECT, nme.notify_, jEmpty, MMONITOR, "Pulse", mObject1)
+ mapMethod(JOBJECT, nme.notifyAll_, jEmpty, MMONITOR, "PulseAll", mObject1)
+
+ mapMethod(JSTRING, "compareTo",MSTRING, "CompareTo")
+ mapMethod(JSTRING, "length", MSTRING, "get_Length")
+ mapMethod(JSTRING, "charAt", MSTRING, "get_Chars")
+
+ mapMethod(JSTRING, "concat", jString1, MSTRING, "Concat", mString2)
+ mapMethod(JSTRING, "indexOf", jInt1, MSTRING, "IndexOf", mChar1)
+ mapMethod(JSTRING, "indexOf", jInt2, MSTRING, "IndexOf", mCharInt)
+
+ mapMethod(JSTRING, "indexOf", jString1, MSTRING, "IndexOf")
+ mapMethod(JSTRING, "indexOf", jStringInt, MSTRING, "IndexOf")
+ mapMethod(JSTRING, "lastIndexOf", jInt1, MSTRING, "LastIndexOf", mChar1)
+ mapMethod(JSTRING, "lastIndexOf", jInt2, MSTRING, "LastIndexOf", mCharInt)
+ mapMethod(JSTRING, "lastIndexOf", jString1, MSTRING, "LastIndexOf")
+ mapMethod(JSTRING, "lastIndexOf", jStringInt, MSTRING, "LastIndexOf")
+
+ mapMethod(JSTRING, "toLowerCase", jEmpty, MSTRING, "ToLower")
+ mapMethod(JSTRING, "toUpperCase", jEmpty, MSTRING, "ToUpper")
+ mapMethod(JSTRING, "startsWith", jString1, MSTRING, "StartsWith")
+ mapMethod(JSTRING, "endsWith", jString1, MSTRING, "EndsWith")
+ mapMethod(JSTRING, "substring", jInt1, MSTRING, "Substring")
+ mapMethod(JSTRING, "substring", jInt2, MSTRING, "Substring")
+ mapMethod(JSTRING, "trim", jEmpty, MSTRING, "Trim")
+ mapMethod(JSTRING, "intern", jEmpty, MSTRING, "Intern", mString1)
+ mapMethod(JSTRING, "replace", jChar2, MSTRING, "Replace")
+ mapMethod(JSTRING, "toCharArray", MSTRING, "ToCharArray")
+
+ mapType(definitions.BooleanClass, MBOOL)
+ mapType(definitions.ByteClass, MBYTE)
+ mapType(definitions.ShortClass, MSHORT)
+ mapType(definitions.CharClass, MCHAR)
+ mapType(definitions.IntClass, MINT)
+ mapType(definitions.LongClass, MLONG)
+ mapType(definitions.FloatClass, MFLOAT)
+ mapType(definitions.DoubleClass, MDOUBLE)
+
+ }
+
+ var clasz: IClass = _
+ var method: IMethod = _
+ var code: Code = _
+
+ var massembly: AssemblyBuilder = _
+ var mmodule: ModuleBuilder = _
+ var mcode: ILGenerator = _
+
+ var assemName : String = _
+ var firstSourceName = ""
+ var outDir : File = _
+
+ def initAssembly(): Unit = {
+
+ 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)
+ }
+ } 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 (outDir == null)
+ outDir = new File(".")
+
+
+ val assemblyName = new AssemblyName()
+ assemblyName.Name = assemName
+ massembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName)
+
+ 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())
+ assert (mmodule != null)
+ initMappings()
+
+ }
+
+
+ /**
+ * Form of the custom Attribute parameter (Ecma-335.pdf)
+ * - p. 163 for CustomAttrib Form,
+ * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!)
+ * !! least significant *byte* first if values longer than one byte !!
+ *
+ * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00
+ * 2: FixedArgs (directly the data, get number and types from related constructor)
+ * 2.1: length of the array (unsigned int32, take care on order of the 4 bytes)
+ * 2.2: the byte array data
+ * 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(val i <- Iterator.range(2, 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[AttrInfo]): Unit = {
+ return // FIXME
+
+ if (settings.debug.value)
+ log("creating attributes: " + attributes + " for member : " + member)
+ for(val AttrInfo(typ, consts, nvPairs) <- attributes /* !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 AttrInfo.
+ 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(consts, nvPairs)
+ member.SetCustomAttribute(constr, args)
+ }
+ }
+
+ def getAttributeArgs(consts: List[Constant], nvPairs: List[Pair[Name, Constant]]): Array[Byte] = {
+ val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough!
+ buf.order(ByteOrder.LITTLE_ENDIAN)
+ buf.putShort(1.toShort) // signature
+
+ def emitSerString(str: String) = {
+ // this is wrong, it has to be the length of the UTF-8 byte array, which
+ // may be longer (see clr-book on page 302)
+// val length: Int = str.length
+ val strBytes: Array[Byte] = try {
+ str.getBytes("UTF-8")
+ } catch {
+ case _: Error => abort("could not get byte-array for string: " + str)
+ }
+ val length: Int = strBytes.length //this length is stored big-endian
+ if (length < 128)
+ buf.put(length.toByte)
+ else if (length < (1<<14)) {
+ buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0'
+ buf.put((length | 0xff).toByte)
+ } else if (length < (1 << 29)) {
+ buf.put(((length >> 24) | 0xc0).toByte)
+ buf.put(((length >> 16) & 0xff).toByte)
+ buf.put(((length >> 8) & 0xff).toByte)
+ buf.put(((length ) & 0xff).toByte)
+ } else
+ abort("string too long for attribute parameter: " + length)
+ buf.put(strBytes)
+ }
+
+ def emitConst(const: Constant): Unit = const.tag match {
+ case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte)
+ case ByteTag => buf.put(const.byteValue)
+ case ShortTag => buf.putShort(const.shortValue)
+ case CharTag => buf.putChar(const.charValue)
+ case IntTag => buf.putInt(const.intValue)
+ case LongTag => buf.putLong(const.longValue)
+ case FloatTag => buf.putFloat(const.floatValue)
+ case DoubleTag => buf.putDouble(const.doubleValue)
+ case StringTag =>
+ val str: String = const.stringValue
+ if (str == null) {
+ buf.put(0xff.toByte)
+ } else {
+ emitSerString(str)
+ }
+ case ArrayTag =>
+ val arr: Array[Constant] = const.arrayValue
+ if (arr == null) {
+ buf.putInt(0xffffffff)
+ } else {
+ buf.putInt(arr.length)
+ arr.foreach(emitConst)
+ }
+
+ // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ???
+
+ case _ => abort("could not handle attribute argument: " + const)
+ }
+
+ consts foreach emitConst
+ buf.putShort(nvPairs.length.toShort)
+ def emitNamedArg(nvPair: Pair[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)
+ }
+
+ val length = buf.position()
+ buf.array().subArray(0, length)
+ }
+
+ def writeAssembly(): Unit = {
+ 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)
+ }
+ createTypes()
+ val filename = new File(outDir, assemName + ".msil").getPath()
+ if (settings.debug.value)
+ log("output file name: " + filename)
+ try {
+ massembly.Save(filename)
+ } catch {
+ case _: Error => abort("Could not save file " + filename)
+ }
+ }
+
+ private def createTypes(): Unit =
+ for (val sym <- classes.keys) {
+ if (settings.debug.value)
+ log("Calling CreatType for " + sym + ", " + types(sym))
+ types(sym).asInstanceOf[TypeBuilder].CreateType()
+ }
+
+ private[GenMSIL] def genClass(iclass: IClass): Unit = {
+ val sym = iclass.symbol
+ if (settings.debug.value)
+ log("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags))
+ clasz = iclass
+
+ val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
+ if (isCloneable(sym)){
+ // FIXME: why there's no nme.clone_ ?
+ // "Clone": if the code is non-portable, "Clone" is defined, not "clone"
+ // TODO: improve condition (should override AnyRef.clone)
+ if (iclass.methods.forall(m => {
+ !((m.symbol.name.toString() != "clone" || m.symbol.name.toString() != "Clone") &&
+ m.symbol.tpe.paramTypes.length != 0)
+ })) {
+ 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)
+ }
+ }
+
+ tBuilder.setPosition(iclass.cunit.position(sym.pos).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)
+ }
+ }
+
+ // 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)
+
+ // TODO: remove; check the above think:
+ assert(!isTopLevelModule(sym), "can't remove the 'if'")
+ }
+
+ addAttributes(tBuilder, sym.attributes)
+
+ if (iclass.symbol != definitions.ArrayClass)
+ iclass.methods foreach genMethod
+
+ } //genClass
+
+
+ private def genMethod(m: IMethod): Unit = {
+ if (settings.debug.value)
+ 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()
+ } else {
+ val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder]
+ if (!mBuilder.IsAbstract())
+ try {
+ mcode = mBuilder.GetILGenerator()
+ } catch {
+ case e: Exception =>
+ System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol)
+ System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner)
+ System.out.println("mBuilder = " + mBuilder)
+ System.out.println("mBuilder.DeclaringType = " +
+ TypeAttributes.toString(mBuilder.DeclaringType.Attributes) +
+ "::" + mBuilder.DeclaringType)
+ throw e
+ }
+ else
+ mcode = null
+ }
+
+ if (mcode != null) {
+ for (val 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)
+ }
+
+ }
+
+ var linearization: List[BasicBlock] = Nil
+ // a "ret" instruction is needed (which is not present in
+ // icode) if there's no code after a try-catch block
+ var needAdditionalRet: Boolean = false
+
+ def genCode(m: IMethod): Unit = {
+
+ code = m.code
+
+ labels.clear
+ linearization = linearizer.linearize(m)
+ val orderedBlocks = (if (m.exh != Nil) orderBlocksForExh(linearization, m.exh)
+ else linearization)
+
+ makeLabels(orderedBlocks) // orderBlocksForExh may create new Blocks -> new Labels
+ genBlocks(orderedBlocks)
+ if (needAdditionalRet) {
+ mcode.Emit(OpCodes.Ret)
+ needAdditionalRet = false
+ }
+ }
+
+ abstract class ExHInstruction(handler: ExceptionHandler) { }
+ case class BeginExceptionBlock(handler: ExceptionHandler) extends ExHInstruction(handler)
+ case class BeginCatchBlock(handler: ExceptionHandler, exceptionType: MsilType) extends ExHInstruction(handler)
+ case class BeginFinallyBlock(handler: ExceptionHandler) extends ExHInstruction(handler)
+ case class EndExceptionBlock(handler: ExceptionHandler) extends ExHInstruction(handler)
+
+
+ abstract class Block {
+ var closed: Boolean = false
+ def parentBlockList: Option[BlockList0]
+ def firstBasicBlock: BasicBlock
+ def lastBasicBlock: BasicBlock
+// 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
+ } */
+ }
+ 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
+ }
+ }
+ override def lastBasicBlock: BasicBlock = {
+ 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 toString() = {
+ 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
+ }
+ }
+ override def lastBasicBlock: BasicBlock = {
+ if(blocks.isEmpty) null
+ else {
+ if (closed) blocks.last.lastBasicBlock
+ else blocks.head.lastBasicBlock
+ }
+ }
+/* override def getExceptionBlock(exh: ExceptionHandler): Option[ExceptionBlock] = {
+ 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
+ }
+ 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
+ }
+ override def toString() = {
+ var res = ""
+ res = res + TopBlock.indent + "BlockList0:\n"
+ TopBlock.indent = TopBlock.indent + " "
+ for(val 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
+ }
+ }
+ override def toString() = {
+ var res = ""
+ res = res + TopBlock.indent + "BlockList:\n"
+ res = res + super.toString()
+ res
+ }
+ }
+ case class ExceptionBlock(parent: Block, handler: ExceptionHandler) extends Block {
+ var tryBlock: BlockList = new BlockList(this)
+ var catchBlocks: List[CatchBlock] = Nil
+ var finallyBlock: BlockList = new BlockList(this)
+ override def 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
+ }
+ }
+ 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
+ }
+ }
+/* 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)
+ }
+ }
+*/
+ 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
+ }
+ 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(val 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
+ }
+ override def toString() = {
+ 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
+ }
+ }
+
+ // for every basic block, a list of ExHInstructions to be executed:
+ // - Begin_ are executed before the block
+ // - EndExceptionBlock is executed after the block
+ val bb2exHInstructions: HashMap[BasicBlock, List[ExHInstruction]] = new HashMap()
+ // at the end of a try, catch or finally block, the jumps must not be emitted,
+ // the automatically generated leave (or endfinally) will do the job.
+ val omitJumpBlocks: HashSet[BasicBlock] = new HashSet()
+
+ // suposes that finalizers are the same for different handlers
+ // covering the same blocks
+ def orderBlocksForExh(blocks: List[BasicBlock], exH: List[ExceptionHandler]): List[BasicBlock] = {
+
+ var blocksToPut: List[BasicBlock] = blocks
+ var nextBlock: BasicBlock = null
+ var untreatedHandlers: List[ExceptionHandler] = exH
+ 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): Pair[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[Pair[BasicBlock, List[BasicBlock]]] = {
+ for {val b <- blocks
+ val t = outsideTargets(b, blocks)
+ t.length != 0 } yield {b, t}
+ }
+
+ def replaceOutJumps(blocks: List[BasicBlock], leaving: List[Pair[BasicBlock, List[BasicBlock]]], exh: ExceptionHandler):Pair[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)
+ // 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)
+ })
+ addBlocks(blocks)
+
+ TopBlock.close()
+
+ if (settings.debug.value) log("TopBlock tree is: ")
+ if (settings.debug.value) Console.println(TopBlock)
+
+ bb2exHInstructions.clear
+ def addExHInstruction(b: BasicBlock, ehi: ExHInstruction) = {
+ if (settings.debug.value)
+ log("adding exhinstr: " + b + " -> " + ehi)
+
+ if (bb2exHInstructions.contains(b)){
+ bb2exHInstructions(b) = ehi :: bb2exHInstructions(b)
+ } else {
+ bb2exHInstructions(b) = List(ehi)
+ }
+ }
+ omitJumpBlocks.clear
+ def omitJump(blk: BasicBlock) = {
+ omitJumpBlocks += blk
+ }
+ var orderedBlocks: List[BasicBlock] = Nil
+ def flatten(block: Block): Unit = {
+ if (block == TopBlock) {
+ for (val b <- TopBlock.blocks) flatten(b)
+ } else block match {
+ case cb: CodeBlock =>
+ orderedBlocks = orderedBlocks ::: cb.basicBlocks
+ case bl: BlockList =>
+ for (val b <- bl.blocks) flatten(b)
+ case cb: CatchBlock =>
+ for (val 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(val 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)
+ // remove catch blocks from empty handlers (finally-blocks remain)
+ untreatedHandlers.foreach((h) => {
+ 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]))
+ })
+
+
+ if (settings.debug.value){
+ log("after: " + orderedBlocks)
+ log(" exhInstr: " + bb2exHInstructions)
+ }
+
+ orderedBlocks
+ }
+
+ var currentBlock: BasicBlock = _
+ 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)
+ }
+
+
+ var ignoreNextDup: Boolean = false
+ val excResultLocals: Stack[LocalBuilder] = new Stack()
+
+ def genBlock(b: BasicBlock): Unit = {
+ // 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)
+ }
+ }
+
+ 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)
+ })
+ }
+
+ mcode.MarkLabel(labels(b))
+ if (settings.debug.value)
+ log("Generating code for block: " + b)
+
+ var lastLineNr: Int = 0
+
+ b traverse ( instr => {
+
+ needAdditionalRet = false
+
+ var currentLineNr = try { clasz.cunit.position(instr.pos).line } catch {
+ case _: Error =>
+ log("Warning: wrong position in: " + method)
+ lastLineNr
+ } // if getting line number fails
+
+ if (currentLineNr != lastLineNr) {
+ mcode.setPosition(currentLineNr)
+ lastLineNr = currentLineNr
+ }
+
+ instr match {
+ case THIS(clasz) =>
+ mcode.Emit(OpCodes.Ldarg_0)
+
+ case CONSTANT(const) =>
+ const.tag match {
+ case UnitTag => ()
+ case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1
+ else OpCodes.Ldc_I4_0)
+ case ByteTag => loadI4(const.byteValue, mcode)
+ case ShortTag => loadI4(const.shortValue, mcode)
+ case CharTag => loadI4(const.charValue, mcode)
+ case IntTag => loadI4(const.intValue, mcode)
+ case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue)
+ case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue)
+ case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue)
+ case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue)
+ case NullTag => mcode.Emit(OpCodes.Ldnull)
+ case ClassTag =>
+ mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue))
+ mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE)
+ case _ => abort("Unknown constant value: " + const)
+ }
+
+ case LOAD_ARRAY_ITEM(kind) =>
+ kind 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 (isArg) {
+ 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))
+
+ 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)
+
+
+ case LOAD_MODULE(module) =>
+ if (settings.debug.value)
+ log("genearting LOAD_MODULE for: " + showsym(module))
+ mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module))
+
+ case STORE_ARRAY_ITEM(kind) =>
+ kind 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)
+
+ // there are some locals defined by the compiler that
+ // are isArg and are need to be stored.
+ if (isArg) {
+ if (i >= -128 && i <= 127)
+ mcode.Emit(OpCodes.Starg_S, i)
+ else
+ mcode.Emit(OpCodes.Starg, i)
+ } else {
+ i match {
+ case 0 => mcode.Emit(OpCodes.Stloc_0)
+ case 1 => mcode.Emit(OpCodes.Stloc_1)
+ case 2 => mcode.Emit(OpCodes.Stloc_2)
+ case 3 => mcode.Emit(OpCodes.Stloc_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ mcode.Emit(OpCodes.Stloc_S, localBuilders(local))
+ else
+ mcode.Emit(OpCodes.Stloc, localBuilders(local))
+ }
+ }
+
+ case STORE_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
+ fInfo
+ }
+ mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo)
+
+
+ case CALL_PRIMITIVE(primitive) =>
+ genPrimitive(primitive, instr.pos)
+
+
+ case CALL_METHOD(msym, style) =>
+ if (msym.isClassConstructor) {
+ val constructorInfo: ConstructorInfo = getConstructor(msym)
+ style 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 {
+ case Some(typ) if (typ.IsEnum) => {
+ def negBool = {
+ mcode.Emit(OpCodes.Ldc_I4_0)
+ mcode.Emit(OpCodes.Ceq)
+ }
+ doEmit = false
+ val name = msym.name
+ if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) }
+ else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool }
+ else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) }
+ else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool }
+ else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) }
+ else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool }
+ else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) }
+ else if (name eq nme.AND) { mcode.Emit(OpCodes.And) }
+ else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) }
+ else
+ doEmit = true
+ }
+ case _ => ()
+ }
+
+ // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType
+ val {isDelegateView, paramType, resType} = atPhase(currentRun.typerPhase){
+ msym.tpe match {
+ case MethodType(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)
+ }
+ }
+ }
+
+ case BOX(boxType) => emitBox(mcode, boxType) //mcode.Emit(OpCodes.Box, msilType(boxType))
+
+ case UNBOX(boxType) => emitUnbox(mcode, boxType)
+
+ case NEW(REFERENCE(cls)) =>
+ ignoreNextDup = true
+
+ // works also for arrays and reference-types
+ case CREATE_ARRAY(elem) => mcode.Emit(OpCodes.Newarr, msilType(elem))
+
+ // works for arrays and reference-types
+ case IS_INSTANCE(tpe) =>
+ mcode.Emit(OpCodes.Isinst, msilType(tpe))
+ mcode.Emit(OpCodes.Ldnull)
+ mcode.Emit(OpCodes.Ceq)
+ mcode.Emit(OpCodes.Ldc_I4_0)
+ mcode.Emit(OpCodes.Ceq)
+
+
+ // works for arrays and reference-types
+ // part from the scala reference: "S <: T does not imply
+ // Array[S] <: Array[T] in Scala. However, it is possible
+ // to cast an array of S to an array of T if such a cast
+ // is permitted in the host environment."
+ case CHECK_CAST(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 => ...")
+ 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(val l <- tags) {
+ var targetLabel = labels(branches(i))
+ for(val i <- l) {
+ mcode.Emit(OpCodes.Ldloc, switchLocal)
+ loadI4(i, mcode)
+ mcode.Emit(OpCodes.Beq, targetLabel)
+ }
+ i = i + 1
+ }
+ val defaultTarget = labels(branches(i))
+ if (nextBlock != defaultTarget && !omitJumpBlocks.contains(currentBlock))
+ mcode.Emit(OpCodes.Br, defaultTarget)
+
+
+ case JUMP(where) =>
+ if (nextBlock != where && !omitJumpBlocks.contains(currentBlock))
+ 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))
+ }
+ }
+
+ case CZJUMP(success, failure, cond, kind) =>
+ kind 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)
+
+ case THROW() =>
+ mcode.Emit(OpCodes.Throw)
+
+ case DROP(kind) =>
+ mcode.Emit(OpCodes.Pop)
+
+ case DUP(kind) =>
+ // needed to create new instances
+ if (!ignoreNextDup) {
+ mcode.Emit(OpCodes.Dup)
+ } else {
+ ignoreNextDup = false
+ }
+
+
+ case MONITOR_ENTER() =>
+ mcode.Emit(OpCodes.Call, MMONITOR_ENTER)
+
+ case MONITOR_EXIT() =>
+ mcode.Emit(OpCodes.Call, MMONITOR_EXIT)
+ }
+
+ }) // end b traverse instr => { .. }
+
+ 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)
+ })
+ }
+
+ } // end genBlock
+
+ def genPrimitive(primitive: Primitive, pos: Int): Unit = {
+ primitive match {
+ case Negation(kind) =>
+ kind match {
+ // CHECK: is ist possible to get this for BOOL? in this case, verify.
+ case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE =>
+ mcode.Emit(OpCodes.Neg)
+
+ case _ => abort("Impossible to negate a " + kind)
+ }
+
+ case Arithmetic(op, kind) =>
+ op match {
+ case ADD => mcode.Emit(OpCodes.Add)
+ case SUB => mcode.Emit(OpCodes.Sub)
+ case MUL => mcode.Emit(OpCodes.Mul)
+ case DIV => mcode.Emit(OpCodes.Div)
+ case REM => mcode.Emit(OpCodes.Rem)
+ case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement)
+ case _ => abort("Unknown arithmetic primitive " + primitive )
+ }
+
+ case Logical(op, kind) => op match {
+ case AND => mcode.Emit(OpCodes.And)
+ case OR => mcode.Emit(OpCodes.Or)
+ case XOR => mcode.Emit(OpCodes.Xor)
+ }
+
+
+ case Shift(op, kind) => op match {
+ case LSL => mcode.Emit(OpCodes.Shl)
+ case ASR => mcode.Emit(OpCodes.Shr)
+ case LSR => mcode.Emit(OpCodes.Shr_Un)
+ }
+
+
+ case Conversion(src, dst) =>
+ 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 + ":" +
+ Position.line(clasz.cunit.source, pos))
+ }
+
+ case ArrayLength(_) =>
+ mcode.Emit(OpCodes.Ldlen)
+
+ case StartConcat =>
+ mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR)
+
+
+ case StringConcat(el) =>
+ val elemType : MsilType = el match {
+ case REFERENCE(_) | ARRAY(_) => MOBJECT
+ case _ => msilType(el)
+ }
+
+ val argTypes:Array[MsilType] = Array(elemType)
+ val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes )
+ mcode.Emit(OpCodes.Callvirt, stringBuilderAppend)
+
+ case EndConcat =>
+ mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING)
+
+ case _ => abort("Unimplemented primitive " + primitive)
+ }
+ }
+
+
+ ////////////////////// loading ///////////////////////
+
+ def loadI4(value: Int, code: ILGenerator):Unit = value match {
+ case -1 => code.Emit(OpCodes.Ldc_I4_M1)
+ case 0 => code.Emit(OpCodes.Ldc_I4_0)
+ case 1 => code.Emit(OpCodes.Ldc_I4_1)
+ case 2 => code.Emit(OpCodes.Ldc_I4_2)
+ case 3 => code.Emit(OpCodes.Ldc_I4_3)
+ case 4 => code.Emit(OpCodes.Ldc_I4_4)
+ case 5 => code.Emit(OpCodes.Ldc_I4_5)
+ case 6 => code.Emit(OpCodes.Ldc_I4_6)
+ case 7 => code.Emit(OpCodes.Ldc_I4_7)
+ case 8 => code.Emit(OpCodes.Ldc_I4_8)
+ case _ =>
+ if (value >= -128 && value <= 127)
+ code.Emit(OpCodes.Ldc_I4_S, value)
+ else
+ code.Emit(OpCodes.Ldc_I4, value)
+ }
+
+ def loadArg(code: ILGenerator)(i: Int) = i match {
+ case 0 => code.Emit(OpCodes.Ldarg_0)
+ case 1 => code.Emit(OpCodes.Ldarg_1)
+ case 2 => code.Emit(OpCodes.Ldarg_2)
+ case 3 => code.Emit(OpCodes.Ldarg_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldarg_S, i)
+ else
+ code.Emit(OpCodes.Ldarg, i)
+ }
+
+ def loadLocal(i: Int, local: Local, code: ILGenerator) = i match {
+ case 0 => code.Emit(OpCodes.Ldloc_0)
+ case 1 => code.Emit(OpCodes.Ldloc_1)
+ case 2 => code.Emit(OpCodes.Ldloc_2)
+ case 3 => code.Emit(OpCodes.Ldloc_3)
+ case _ =>
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldloc_S, localBuilders(local))
+ else
+ code.Emit(OpCodes.Ldloc, localBuilders(local))
+ }
+
+ ////////////////////// labels ///////////////////////
+
+
+ val labels: HashMap[BasicBlock, Label] = new HashMap() // labels for branches
+
+ def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) = {
+ condition match {
+ case EQ => mcode.Emit(OpCodes.Beq, dest)
+ case NE => mcode.Emit(OpCodes.Bne_Un, dest)
+ case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest)
+ case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest)
+ case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest)
+ case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest)
+ }
+ }
+
+ def emitBrBool(cond: TestOp, dest: Label) = {
+ cond match {
+ // EQ -> Brfalse, NE -> Brtrue; this is because we come from
+ // a CZJUMP. If the value on the stack is 0 (e.g. a 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]) = {
+ if (settings.debug.value)
+ log("Making labels for: " + method)
+ for (val bb <- bs) labels(bb) = mcode.DefineLabel()
+ }
+
+ ////////////////////// local vars ///////////////////////
+
+ /**
+ * Compute the indexes of each local variable of the given
+ * method.
+ */
+ def computeLocalVarsIndex(m: IMethod): Unit = {
+ val params = m.params
+ var idx = 1
+ if (isStaticSymbol(m.symbol))
+ idx = 0
+
+ for (val l <- params) {
+ if (settings.debug.value)
+ log("Index value for parameter " + l + ": " + idx)
+ l.index = idx
+ idx = idx + 1 // sizeOf(l.kind)
+ }
+
+ val locvars = m.locals.diff(params)
+ idx = 0
+
+ for (val l <- locvars) {
+ if (settings.debug.value)
+ log("Index value for local variable " + l + ": " + idx)
+ l.index = idx
+ idx = idx + 1 // sizeOf(l.kind)
+ }
+
+ }
+
+ ////////////////////// Utilities ////////////////////////
+
+ /** Return the a name of this symbol that can be used on the .NET
+ * platform. It removes spaces from names.
+ *
+ * Special handling: scala.All and scala.AllRef are 'erased' to
+ * scala.All$ and scala.AllRef$. This is needed because they are
+ * not real classes, and they mean 'abrupt termination upon evaluation
+ * of that expression' or 'null' respectively. This handling is
+ * done already in GenICode, but here we need to remove references
+ * from method signatures to these types, because such classes can
+ * not exist in the classpath: the type checker will be very confused.
+ */
+ def msilName(sym: Symbol): String = {
+ val suffix: String = if (sym.hasFlag(Flags.MODULE) && !sym.isMethod &&
+ !sym.isImplClass &&
+ !sym.hasFlag(Flags.JAVA)) "$" else ""
+ // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class)
+
+ if (sym == definitions.AllClass)
+ return "scala.All$"
+ else if (sym == definitions.AllRefClass)
+ return "scala.AllRef$"
+
+ (if (sym.isClass || (sym.isModule && !sym.isMethod))
+ sym.fullNameString
+ else
+ sym.simpleName.toString().trim()) + suffix
+ }
+
+
+ ////////////////////// flags ///////////////////////
+
+ def msilTypeFlags(sym: Symbol): Int = {
+ var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass
+
+ mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public)
+ mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0)
+ mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class)
+ mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0)
+
+ sym.attributes foreach { a => a match {
+ case AttrInfo(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
+ // static: not possible (or?)
+ }
+
+ 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)
+
+ if (!sym.isClassConstructor) {
+ if (isStaticSymbol(sym))
+ 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.toShort
+ }
+
+ def msilFieldFlags(sym: Symbol): Short = {
+ var mf: Int =
+ if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private
+ else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem
+ else FieldAttributes.Public
+
+ if (sym hasFlag Flags.FINAL)
+ mf = mf | FieldAttributes.InitOnly
+
+ if (isStaticSymbol(sym))
+ 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 AttrInfo(TransientAtt, _, _) =>
+ mf = mf | FieldAttributes.NotSerialized
+ case _ => ()
+ })
+
+ mf.toShort
+ }
+
+
+ def isStaticSymbol(s: Symbol): Boolean =
+ s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass
+
+
+ ////////////////////// builders, types ///////////////////////
+
+ var entryPoint: Symbol = _
+
+ val notInitializedModules: HashSet[Symbol] = new HashSet()
+
+ // TODO: create fields also in def createType, and not in genClass,
+ // add a getField method (it only works as it is because fields never
+ // accessed from outside a class)
+
+ val localBuilders: HashMap[Local, LocalBuilder] = new HashMap()
+
+ 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 _ => ()
+ }
+ }
+ false
+ }
+
+ for (val m <- cls.methods) {
+ 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
+ }
+
+ // #####################################################################
+ // get and create types
+
+ private def msilType(t: TypeKind): MsilType = t match {
+ case UNIT => MVOID
+ case BOOL => MBOOL
+ case BYTE => MBYTE
+ case SHORT => MSHORT
+ case CHAR => MCHAR
+ case INT => MINT
+ case LONG => MLONG
+ case FLOAT => MFLOAT
+ case DOUBLE => MDOUBLE
+ case REFERENCE(cls) => getType(cls)
+ case ARRAY(elem) => clrTypes.mkArrayType(msilType(elem))
+ }
+
+ private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe))
+
+ private def msilParamTypes(sym: Symbol): Array[MsilType] = {
+ sym.tpe.paramTypes.map(msilType).toArray
+ }
+
+ def getType(sym: Symbol): MsilType = types.get(sym) match {
+ case Some(typ) => typ
+ case None =>
+ val name = if (sym.isModuleClass && !sym.isTrait) sym.fullNameString + "$"
+ else sym.fullNameString
+ val typ = clrTypes.getType(name)
+ if (typ == null)
+ throw new Error(showsym(sym) + " with name " + name)
+ else {
+ clrTypes.types(sym) = typ
+ typ
+ }
+ }
+
+ def mapType(sym: Symbol, mType: MsilType) = {
+ assert(mType != null, showsym(sym))
+ types(sym) = mType
+ }
+
+ def createTypeBuilder(iclass: IClass): Unit = {
+ def getMsilType(tpe: Type): MsilType = {
+ val sym = tpe.symbol
+ types.get(sym) match {
+ case Some(mtype) => mtype
+ case None => createTypeBuilder(classes(sym)); types(sym)
+ }
+ }
+
+ val sym = iclass.symbol
+ if (types contains sym) return
+
+ def isInterface(s: Symbol) = s.isTrait && !s.isImplClass
+ val parents: List[Type] =
+ if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe)
+ else sym.info.parents.removeDuplicates
+
+ val superType = if (isInterface(sym)) null else getMsilType(parents.head)
+ if (settings.debug.value)
+ 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(val i <- Iterator.range(0, interfaces.length)){
+ log(" type: " + parents(i + 1).symbol + ", msil type: " + interfaces(i))
+ }
+ }
+ }
+
+ //TODO here: if the class is not top-level, use DefineNestedType?
+ val tBuilder =
+ mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces)
+ 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 createClassMembers0(iclass: IClass): Unit = {
+ val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder]
+ for (val ifield <- iclass.fields) {
+ val sym = ifield.symbol
+ if (settings.debug.value)
+ log("Adding field: " + sym.fullNameString)
+
+ var attributes = msilFieldFlags(sym)
+ val fBuilder = mtype.DefineField(msilName(sym), msilType(sym.tpe), attributes)
+ fields(sym) = fBuilder
+ addAttributes(fBuilder, sym.attributes)
+ }
+
+ if (iclass.symbol != definitions.ArrayClass)
+ for (val m: IMethod <- iclass.methods) {
+ val sym = m.symbol
+ if (settings.debug.value)
+ log("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " +
+ sym.owner.fullNameString + "::" + sym.name)
+
+ val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder]
+ assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType)
+ var paramTypes = msilParamTypes(sym)
+ val attr = msilMethodFlags(sym)
+
+ if (m.symbol.isClassConstructor) {
+ val constr =
+ ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes)
+ for (val i <- Iterator.range(0, paramTypes.length)) {
+ 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 =
+ ownerType.DefineMethod(getMethodName(sym), attr, resType, paramTypes)
+ for (val i <- Iterator.range(0, paramTypes.length)){
+ method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym))
+ }
+ if (!methods.contains(sym))
+ 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)
+ }
+
+ } // createClassMembers
+
+ private def isTopLevelModule(sym: Symbol): Boolean =
+ atPhase (currentRun.refchecksPhase) {
+ sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass
+ }
+
+ private def isStaticModule(sym: Symbol): Boolean = {
+ sym.isModuleClass && !sym.isImplClass && !sym.hasFlag(Flags.LIFTED)
+ }
+
+ private def isCloneable(sym: Symbol): Boolean = {
+ !sym.attributes.forall( a => a match {
+ case AttrInfo(CloneableAttr, _, _) => false
+ case _ => true
+ })
+ }
+
+ private def addModuleInstanceField(sym: Symbol): Unit = {
+ if (settings.debug.value)
+ 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)
+ fields(sym) = fb
+ }
+
+
+ // the symbol may be a object-symbol (module-symbol), or a module-class-symbol
+ private def getModuleInstanceField(sym: Symbol): FieldInfo = {
+ assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym))
+
+ // when called by LOAD_MODULE, the corresponding type maybe doesn't
+ // exist yet -> make a getType
+ val moduleClassSym = if (sym.isModule) sym.moduleClass else sym
+
+ // TODO: get module field for modules not defined in the
+ // source currently compiling (e.g. Console)
+
+ fields get moduleClassSym match {
+ case Some(sym) => sym
+ case None =>
+ //val mclass = types(moduleClassSym)
+ val mClass = clrTypes.getType(moduleClassSym.fullNameString + "$")
+ val mfield = mClass.GetField("MODULE$")
+ assert(mfield ne null, "module not found " + showsym(moduleClassSym))
+ fields(moduleClassSym) = mfield
+ mfield
+ }
+
+ //fields(moduleClassSym)
+ }
+
+ private def addStaticInit(sym: Symbol): Unit = {
+ val tBuilder = getType(sym).asInstanceOf[TypeBuilder]
+
+ val staticInit = tBuilder.DefineConstructor(
+ (MethodAttributes.Static | MethodAttributes.Public).toShort,
+ CallingConventions.Standard,
+ MsilType.EmptyTypes)
+
+ val sicode = staticInit.GetILGenerator()
+
+ val instanceConstructor = constructors(sym.primaryConstructor)
+
+ sicode.Emit(OpCodes.Newobj, instanceConstructor)
+ // the stsfld is done in the instance constructor, just after the super call.
+ sicode.Emit(OpCodes.Pop)
+
+ sicode.Emit(OpCodes.Ret)
+ }
+
+
+ private def dumpMirrorClass(sym: Symbol): Unit = {
+ val tBuilder = getType(sym)
+ assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym)
+ if (settings.debug.value)
+ log("Dumping mirror class for object: " + sym)
+ val moduleName = msilName(sym)
+ val mirrorName = moduleName.substring(0, moduleName.length() - 1)
+ val mirrorTypeBuilder = mmodule.DefineType(mirrorName,
+ TypeAttributes.Class |
+ TypeAttributes.Public |
+ TypeAttributes.Sealed,
+ //FIXME: an object may have a super-type (a class, not an object) -> not in mirror class?
+ MOBJECT,
+ MsilType.EmptyTypes)
+
+ for (val m <- sym.tpe.nonPrivateMembers;
+ m.owner != definitions.ObjectClass && !m.hasFlag(Flags.PROTECTED) &&
+ m.isMethod && !m.isClassConstructor && !isStaticSymbol(m) && !m.hasFlag(Flags.CASE))
+ {
+ if (settings.debug.value)
+ log(" Mirroring method: " + m)
+ val paramTypes = msilParamTypes(m)
+ val paramNames: Array[String] = new Array[String](paramTypes.length)
+ for (val i <- Iterator.range(0, 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))
+ Iterator.range(0, paramTypes.length) foreach loadArg(mirrorCode)
+
+ mirrorCode.Emit(OpCodes.Call, getMethod(m))
+ mirrorCode.Emit(OpCodes.Ret)
+ }
+
+ addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder)
+
+ mirrorTypeBuilder.CreateType()
+ }
+
+
+ // #####################################################################
+ // delegate callers
+
+ var delegateCallers: TypeBuilder = _
+ var nbDelegateCallers: Int = 0
+
+ private def initDelegateCallers() = {
+ delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public |
+ TypeAttributes.Sealed)
+ }
+
+ private def createDelegateCaller(functionType: Type, delegateType: Type) = {
+ if (delegateCallers == null)
+ initDelegateCallers()
+ // create a field an store the function-object
+ val mFunctionType: MsilType = msilType(functionType)
+ val anonfunField: FieldBuilder = delegateCallers.DefineField(
+ "$anonfunField$$" + nbDelegateCallers, mFunctionType,
+ FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static)
+ 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)
+ }
+ val caller: MethodBuilder = delegateCallers.DefineMethod(
+ "$delegateCaller$$" + nbDelegateCallers,
+ MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static,
+ msilType(returnType), paramTypes.map(msilType).toArray)
+ for(val i <- Iterator.range(0, paramTypes.length))
+ 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)
+ mcode.Emit(OpCodes.Newobj, delegCtor)
+
+
+ // create the static caller method body
+ val functionApply: MethodInfo = getMethod(functionType.member(nme.apply))
+ val dcode: ILGenerator = caller.GetILGenerator()
+ dcode.Emit(OpCodes.Ldsfld, anonfunField)
+ for(val i <- Iterator.range(0, paramTypes.length)) {
+ loadArg(dcode)(i)
+ emitBox(dcode, toTypeKind(paramTypes(i)))
+ }
+ dcode.Emit(OpCodes.Callvirt, functionApply)
+ emitUnbox(dcode, toTypeKind(returnType))
+ dcode.Emit(OpCodes.Ret)
+
+ nbDelegateCallers = nbDelegateCallers + 1
+
+ } //def createDelegateCaller
+
+ def emitBox(code: ILGenerator, boxType: TypeKind) = boxType match {
+ // doesn't make sense, unit as parameter..
+ case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit)
+ case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE =>
+ code.Emit(OpCodes.Box, msilType(boxType))
+ case REFERENCE(cls) if (definitions.unboxMethod.contains(cls)) =>
+ code.Emit(OpCodes.Box, (msilType(boxType)))
+ case REFERENCE(_) | ARRAY(_) => ()
+ }
+
+// def emitUnbox(code: ILGenerator, boxType: Type) = toTypeKind(boxType) match {
+// case UNIT => code.Emit(OpCodes.Pop)
+// case BOOL => code.Emit(OpCodes.Unbox, MBOOL); code.Emit(OpCodes.Ldind_I1)
+// case BYTE => code.Emit(OpCodes.Unbox, MBYTE); code.Emit(OpCodes.Ldind_U1)
+// case SHORT => code.Emit(OpCodes.Unbox, MSHORT); code.Emit(OpCodes.Ldind_I2)
+// case CHAR => code.Emit(OpCodes.Unbox, MCHAR); code.Emit(OpCodes.Ldind_U2)
+// case INT => code.Emit(OpCodes.Unbox, MINT); code.Emit(OpCodes.Ldind_I4)
+// case LONG => code.Emit(OpCodes.Unbox, MLONG); code.Emit(OpCodes.Ldind_I8)
+// case FLOAT => code.Emit(OpCodes.Unbox, MFLOAT); code.Emit(OpCodes.Ldind_R4)
+// case DOUBLE => code.Emit(OpCodes.Unbox, MDOUBLE); code.Emit(OpCodes.Ldind_R8)
+// case REFERENCE(typ) => () ///code.Emit(OpCode.Unbox, msilType(typ)); code.Emit(OpCodes.Ldobj, msilType(typ))
+// case ARRAY(_) => ()
+// }
+
+ def emitUnbox(code: ILGenerator, boxType: TypeKind) = boxType match {
+ case UNIT => code.Emit(OpCodes.Pop)
+ case BOOL => code.Emit(OpCodes.Unbox, MBOOL); code.Emit(OpCodes.Ldind_I1)
+ case BYTE => code.Emit(OpCodes.Call, toByte)
+ case SHORT => code.Emit(OpCodes.Call, toShort)
+ case CHAR => code.Emit(OpCodes.Call, toChar)
+ case INT => code.Emit(OpCodes.Call, toInt)
+ case LONG => code.Emit(OpCodes.Call, toLong)
+ case FLOAT => code.Emit(OpCodes.Call, toFloat)
+ case DOUBLE => code.Emit(OpCodes.Call, toDouble)
+ case REFERENCE(cls) if (definitions.unboxMethod.contains(cls)) =>
+ code.Emit(OpCodes.Unbox, msilType(boxType))
+ code.Emit(OpCodes.Ldobj, msilType(boxType))
+ case REFERENCE(_) | ARRAY(_) => ()
+ }
+
+ // #####################################################################
+ // get and create methods / constructors
+
+ def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match {
+ case Some(constr) => constr
+ case None =>
+ val mClass = getType(sym.owner)
+ val constr = mClass.GetConstructor(msilParamTypes(sym))
+ if (constr eq null) {
+ System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name)
+ System.out.println("scope = " + sym.owner.tpe.decls)
+ throw new Error(sym.fullNameString)
+ }
+ else {
+ mapConstructor(sym, constr)
+ constr
+ }
+ }
+
+ def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = {
+ constructors(sym) = cInfo
+ }
+
+ private def getMethod(sym: Symbol): MethodInfo = {
+ //private def getMethod(sym: Symbol): MethodInfo = sym match {
+// case SRToInt => toInt
+// case SRToDouble => toDouble
+// case SRToLong => toLong
+// case SRToChar => toChar
+// case SRToFloat => toFloat
+// case SRToBool => toBool
+// case SRToByte => toByte
+// case SRToShort => toShort
+// case _ =>
+
+ methods.get(sym) match {
+ case Some(method) => method
+ case None =>
+ val mClass = getType(sym.owner)
+ try {
+ val method = mClass.GetMethod(getMethodName(sym), msilParamTypes(sym),
+ msilType(sym.tpe.resultType))
+ if (method eq null) {
+ System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym))
+ System.out.println("scope = " + sym.owner.tpe.decls)
+ throw new Error(sym.fullNameString)
+ }
+ else {
+ mapMethod(sym, method)
+ method
+ }
+ }
+ catch {
+ case e: Exception =>
+ Console.println("While looking up " + mClass + "::" + sym.nameString)
+ Console.println("\t" + showsym(sym))
+ throw e
+ }
+ }
+ }
+
+ /*
+ * add a mapping between sym and mInfo
+ */
+ private def mapMethod(sym: Symbol, mInfo: MethodInfo):Unit = {
+ assert (mInfo != null, mInfo)
+ methods(sym) = mInfo
+ }
+
+ /*
+ * add mapping between sym and method with newName, paramTypes of newClass
+ */
+ private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]): Unit = {
+ val methodInfo = newClass.GetMethod(newName, paramTypes)
+ assert(methodInfo != null, "Can't find mapping for " + sym + " -> " +
+ newName + "(" + paramTypes + ")")
+ mapMethod(sym, methodInfo)
+ if (methodInfo.IsStatic)
+ dynToStatMapped += sym
+ }
+
+ /*
+ * add mapping between method with name and paramTypes of clazz to
+ * method with newName and newParamTypes of newClass (used for instance
+ * for "wait")
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name, paramTypes: Array[Type],
+ newClass: MsilType, newName: String, newParamTypes: Array[MsilType]):Unit = {
+ val methodSym = lookupMethod(clazz, name, paramTypes)
+ assert(methodSym != null, "cannot find method " + name + "(" +
+ paramTypes + ")" + " in class " + clazz)
+ mapMethod(methodSym, newClass, newName, newParamTypes)
+ }
+
+ /*
+ * add maping for member with name and paramTypes to member
+ * newName of newClass (same parameters)
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name, paramTypes: Array[Type],
+ newClass: MsilType, newName: String):Unit = {
+ mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType)
+ }
+
+ /*
+ * add mapping for all methods with name of clazz to the corresponding
+ * method (same parameters) with newName of newClass
+ */
+ private def mapMethod(
+ clazz: Symbol, name: Name,
+ newClass: MsilType, newName: String):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)))
+
+ // paramTypes: List[Type], resType: Type
+ case MethodType(paramTypes, resType) =>
+ mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym))
+
+ case _ => abort("member not found: " + clazz + ", " + name)
+ }
+ }
+
+
+ /*
+ * find the method in clazz with name and paramTypes
+ */
+ private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]):Symbol = {
+ val memberSym = clazz.tpe.member(name)
+ memberSym.tpe match {
+ case OverloadedType(_, alternatives) =>
+ alternatives.find(s => {
+ var i: Int = 0
+ var typesOK: Boolean = true
+ if (paramTypes.length == s.tpe.paramTypes.length){
+ while(i < paramTypes.length){
+ if (paramTypes(i) != s.tpe.paramTypes(i))
+ typesOK = false
+ i = 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)
+ }
+ }
+
+ def getMethodName(methodSym: Symbol): String = {
+ val name = methodSym.name
+ val params = methodSym.tpe.paramTypes
+ if (name == nme.finalize_ && params.length == 0)
+ "Finalize"
+ else if (name == nme.toString_ && params.length == 0)
+ "ToString"
+ else if (name == nme.hashCode_ && params.length == 0)
+ "GetHashCode"
+ else if (name == nme.equals_ && params.length == 1 &&
+ params(0) == definitions.ObjectClass.tpe)
+ "Equals"
+ // FIXME: why is there no nme.clone_ ?
+ else if (name.toString() == "clone" && params.length == 0)
+ "Clone"
+ else
+ msilName(methodSym)
+ }
+
+ private def showsym(sym: Symbol): String = (sym.toString +
+ "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym +
+ "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner
+ )
+
+ } // class BytecodeGenerator
+
+} // class GenMSIL
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 0b05696ee2..f2ed6bb6e1 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -41,6 +41,13 @@ trait Definitions requires SymbolTable {
var NullPointerExceptionClass: Symbol = _
var NonLocalReturnExceptionClass: Symbol = _
+ var ValueTypeClass: Symbol = _ // System.ValueType
+ var DelegateClass: Symbol = _ // System.MulticastDelegate
+ var Delegate_scalaCallers: List[Symbol] = List()
+ // Symbol -> (Symbol, Type): scalaCaller -> (scalaMethodSym, DelegateType)
+ // var Delegate_scalaCallerInfos: HashMap[Symbol, Pair[Symbol, Type]] = _
+ var Delegate_scalaCallerTargets: HashMap[Symbol, Symbol] = _
+
// the scala value classes
var UnitClass: Symbol = _
var BooleanClass: Symbol = _
@@ -269,6 +276,32 @@ trait Definitions requires SymbolTable {
case _ =>
false
}
+
+ def isCorrespondingDelegate(delegateType: Type, functionType: Type): boolean = {
+ var isCD: Boolean = false;
+ if (DelegateClass != null && delegateType != null &&
+ isSubType(delegateType, DelegateClass.tpe))
+ {
+ val meth: Symbol = delegateType.member(nme.apply)
+ meth.tpe match {
+ case MethodType(delegateParams, delegateReturn) =>
+ val delegateParamsO = delegateParams.map(pt => {if (pt == definitions.AnyClass.tpe) definitions.ObjectClass.tpe else pt});
+ if(isFunctionType(functionType))
+ functionType match {
+ case TypeRef(_, _, args) =>
+ if(delegateParamsO == args.dropRight(1) &&
+ delegateReturn == args.last)
+ isCD = true;
+
+ case _ => ();
+ }
+
+ case _ => ()
+ }
+ }
+ isCD
+ }
+
/* val RemoteFunctionClass: Array[Symbol] = new Array(MaxFunctionArity + 1)
def remoteFunctionApply(n: Int) = getMember(RemoteFunctionClass(n), nme.apply)
def remoteFunctionType(formals: List[Type], restpe: Type) =
@@ -428,7 +461,17 @@ trait Definitions requires SymbolTable {
private def newValueClass(name: Name, tag: char): Symbol = {
def boxedName: String =
- "scala.runtime.Boxed" + name
+ if (!forMSIL) "scala.runtime.Boxed" + name
+ else "System." + (name match {
+ case nme.Boolean => "Boolean"
+ case nme.Byte => "Byte"
+ case nme.Char => "Char"
+ case nme.Short => "Int16"
+ case nme.Int => "Int32"
+ case nme.Long => "Int64"
+ case nme.Float => "Single"
+ case nme.Double => "Double"
+ })
val clazz =
newClass(ScalaPackageClass, name, List(AnyValClass.typeConstructor))
.setFlag(ABSTRACT /* SEALED */) // bq: SEALED is interesting for case class descendants, only
@@ -606,9 +649,12 @@ trait Definitions requires SymbolTable {
def isNumericValueClass(sym: Symbol): boolean =
(sym ne BooleanClass) && (boxedClass contains sym)
+ def isValueType(sym: Symbol) =
+ isValueClass(sym) || unboxMethod.contains(sym)
+
/** Is symbol a value or array class? */
def isUnboxedClass(sym: Symbol): boolean =
- isValueClass(sym) || sym == ArrayClass
+ isValueType(sym) || sym == ArrayClass
def signature(tp: Type): String = {
def erasure(tp: Type): Type = tp match {
@@ -650,7 +696,7 @@ trait Definitions requires SymbolTable {
RootClass.info.decls.enter(EmptyPackage)
RootClass.info.decls.enter(RootPackage)
- JavaLangPackage = getModule("java.lang")
+ JavaLangPackage = getModule(if (forMSIL) "System" else "java.lang")
ScalaPackage = getModule("scala")
assert(ScalaPackage ne null, "Scala package is null")
ScalaPackageClass = ScalaPackage.tpe.symbol
@@ -662,7 +708,7 @@ trait Definitions requires SymbolTable {
AnyValClass = newClass(ScalaPackageClass, nme.AnyVal, anyparam)
.setFlag(FINAL | SEALED)
- ObjectClass = getClass("java.lang.Object")
+ ObjectClass = getClass(if (forMSIL) "System.Object" else "java.lang.Object")
AnyRefClass =
newAlias(ScalaPackageClass, nme.AnyRef, ObjectClass.typeConstructor)
@@ -675,13 +721,17 @@ trait Definitions requires SymbolTable {
AllClass = newClass(ScalaPackageClass, nme.Nothing, anyparam)
.setFlag(ABSTRACT | TRAIT | FINAL)
- StringClass = getClass("java.lang.String")
+ StringClass = getClass(if (forMSIL) "System.String" else "java.lang.String")
- ClassClass = getClass("java.lang.Class")
- ThrowableClass = getClass("java.lang.Throwable")
- NullPointerExceptionClass = getClass("java.lang.NullPointerException")
+ ClassClass = getClass(if (forMSIL) "System.Type" else "java.lang.Class")
+ ThrowableClass = getClass(if (forMSIL) "System.Exception" else "java.lang.Throwable")
+ NullPointerExceptionClass = getClass(if (forMSIL) "System.NullReferenceException"
+ else "java.lang.NullPointerException")
NonLocalReturnExceptionClass = getClass("scala.runtime.NonLocalReturnException")
+ ValueTypeClass = if (forMSIL) getClass("System.ValueType") else null
+ DelegateClass = if (forMSIL) getClass("System.MulticastDelegate") else null
+
UnitClass =
newClass(ScalaPackageClass, nme.Unit, List(AnyValClass.typeConstructor))
abbrvTag(UnitClass) = 'V'
@@ -704,7 +754,7 @@ trait Definitions requires SymbolTable {
StaticAttributeClass = getClass("scala.StaticAttribute")
//ChannelClass = getClass("scala.distributed.Channel")
//RemoteRefClass = getClass("scala.distributed.RemoteRef")
- if (!forCLDC) {
+ if (!forCLDC && ! forMSIL) {
CodeClass = getClass("scala.reflect.Code")
CodeModule = getModule("scala.reflect.Code")
}
@@ -716,12 +766,14 @@ trait Definitions requires SymbolTable {
ListClass = getClass("scala.List")
ListModule = getModule("scala.List")
ArrayClass = getClass("scala.Array")
- SerializableClass = if (forCLDC) null else getClass("java.io.Serializable")
+ SerializableClass = if (forMSIL || forCLDC) null else getClass("java.io.Serializable")
PredefModule = getModule("scala.Predef")
ConsoleModule = getModule("scala.Console")
MatchErrorClass = getClass("scala.MatchError")
MatchErrorModule = getModule("scala.MatchError")
- IndexOutOfBoundsExceptionClass = getClass("java.lang.IndexOutOfBoundsException")
+ IndexOutOfBoundsExceptionClass =
+ getClass(if (forMSIL) "System.IndexOutOfRangeException"
+ else "java.lang.IndexOutOfBoundsException")
//RemoteExecutionModule = getModule("scala.distributed.RemoteExecution")
ScalaRunTimeModule = getModule("scala.runtime.ScalaRunTime")
RepeatedParamClass = newCovariantPolyClass(
@@ -792,12 +844,85 @@ trait Definitions requires SymbolTable {
BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
ObjectRefClass = getClass("scala.runtime.ObjectRef")
+ if (forMSIL) {
+ val intType = IntClass.typeConstructor;
+ val intParam = List(intType);
+ val longType = LongClass.typeConstructor;
+ val charType = CharClass.typeConstructor;
+ val unitType = UnitClass.typeConstructor;
+ val stringType = StringClass.typeConstructor;
+ val stringParam = List(stringType);
+
+ // additional methods of Object
+ newMethod(ObjectClass, "clone", List(), AnyRefClass.typeConstructor);
+ newMethod(ObjectClass, "wait", List(), unitType);
+ newMethod(ObjectClass, "wait", List(longType), unitType);
+ newMethod(ObjectClass, "wait", List(longType, intType), unitType);
+ newMethod(ObjectClass, "notify", List(), unitType);
+ newMethod(ObjectClass, "notifyAll", List(), unitType);
+
+ // additional methods of String
+ newMethod(StringClass, "length", List(), intType);
+ newMethod(StringClass, "compareTo", stringParam, intType);
+ newMethod(StringClass, "charAt", intParam, charType);
+ newMethod(StringClass, "concat", stringParam, stringType);
+ newMethod(StringClass, "indexOf", intParam, intType);
+ newMethod(StringClass, "indexOf", List(intType, intType), intType);
+ newMethod(StringClass, "indexOf", stringParam, intType);
+ newMethod(StringClass, "indexOf", List(stringType, intType), intType);
+ newMethod(StringClass, "lastIndexOf", intParam, intType);
+ newMethod(StringClass, "lastIndexOf", List(intType, intType), intType);
+ newMethod(StringClass, "lastIndexOf", stringParam, intType);
+ newMethod(StringClass, "lastIndexOf", List(stringType, intType), intType);
+ newMethod(StringClass, "toLowerCase", List(), stringType);
+ newMethod(StringClass, "toUpperCase", List(), stringType);
+ newMethod(StringClass, "startsWith", stringParam, booltype);
+ newMethod(StringClass, "endsWith", stringParam, booltype);
+ newMethod(StringClass, "substring", intParam, stringType);
+ newMethod(StringClass, "substring", List(intType, intType), stringType);
+ newMethod(StringClass, "trim", List(), stringType);
+ newMethod(StringClass, "intern", List(), stringType);
+ newMethod(StringClass, "replace", List(charType, charType), stringType);
+ newMethod(StringClass, "toCharArray", List(),
+ appliedType(ArrayClass.typeConstructor, List(charType)));
+
+ // Delegate_scalaCallerInfos = new HashMap()
+ Delegate_scalaCallerTargets = new HashMap()
+ }
+
AnnotationDefaultAttr = newClass(RootClass,
nme.AnnotationDefaultATTR,
List(AttributeClass.typeConstructor))
SerializableAttr = getClass("scala.serializable")
+ BeanPropertyAttr = if (forCLDC || forMSIL) null else getClass("scala.reflect.BeanProperty")
DeprecatedAttr = getClass("scala.deprecated")
- BeanPropertyAttr = if (forCLDC) null else getClass("scala.reflect.BeanProperty")
+ }
+
+ var nbScalaCallers: Int = 0
+ def newScalaCaller(delegateType: Type): Symbol = {
+ assert(forMSIL, "scalaCallers can only be created if target is .NET")
+ // object: reference to object on which to call (scala-)metod
+ val paramTypes: List[Type] = List(ObjectClass.tpe)
+ val name: String = "$scalaCaller$$" + nbScalaCallers
+ // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the
+ // type parameter =-> a MethodType in this case
+ // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam
+ val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType) setFlag (FINAL | STATIC)
+ // val newCaller = newPolyMethod(DelegateClass, name,
+ // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC)
+ Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller)
+ nbScalaCallers = nbScalaCallers + 1
+ newCaller
+ }
+
+ // def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol, delType: Type) = {
+ // assert(Delegate_scalaCallers contains scalaCaller)
+ // Delegate_scalaCallerInfos += scalaCaller -> Pair(methSym, delType)
+ // }
+
+ def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol) = {
+ assert(Delegate_scalaCallers contains scalaCaller)
+ Delegate_scalaCallerTargets += scalaCaller -> methSym
}
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 0659ad808d..b92d5af56a 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -257,7 +257,7 @@ trait StdNames requires SymbolTable {
val filter = newTermName("filter")
val finalize_ = newTermName("finalize")
val flatMap = newTermName("flatMap")
- val forName = newTermName("forName")
+ val forName = newTermName(if (forMSIL) "GetType" else "forName")
val foreach = newTermName("foreach")
val get = newTermName("get")
val getClass_ = newTermName("getClass")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 699dc0909e..178c6155fa 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -8,12 +8,12 @@ package scala.tools.nsc.symtab
import compat.Platform.currentTime
import java.io.{File, IOException}
-
-import scala.collection.mutable.HashMap
+import scala.collection.mutable.{HashMap, HashSet}
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.{ClassPath, NameTransformer, Position}
import classfile.{ClassfileParser, SymblfileParser}
import Flags._
+import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute};
/** This class ...
*
@@ -57,8 +57,8 @@ abstract class SymbolLoaders {
phase = currentphase
def source = kindString + " " + sourceString
informTime("loaded " + source, start)
- if (root.rawInfo == this && root.linkedSym.rawInfo == this)
- throw new TypeError(source + " does not define " + root)
+ //if (root.rawInfo == this && root.linkedSym.rawInfo == this)
+ // throw new TypeError(source + " does not define " + root)
ok = true
} catch {
case ex: IOException =>
@@ -88,12 +88,50 @@ abstract class SymbolLoaders {
/** Load contents of a package
*/
class PackageLoader(directory: global.classPath0.Context) extends SymbolLoader {
- // System.err.println("PACKAGE LOADER: " + directory)
protected def sourceString = directory.toString()
+ protected def kindString: String = "directory path"
+
+ protected def newPackageLoader(dir: global.classPath0.Context): PackageLoader =
+ new PackageLoader(dir)
+
+ protected def checkSource(name: String, source: AbstractFile): Boolean = true;
+
+ protected var root: Symbol = _
+
+ def enterPackage(name: String, completer: SymbolLoader): unit = {
+ val pkg = root.newPackage(NoPos, newTermName(name))
+ pkg.moduleClass.setInfo(completer)
+ pkg.setInfo(pkg.moduleClass.tpe)
+ root.info.decls.enter(pkg)
+ }
+
+ // @return - the symbol of the class
+ def enterClassAndModule(name: String, completer: SymbolLoader): Symbol = {
+ val owner = if (root.isRoot) definitions.EmptyPackageClass else root
+ val className = newTermName(name)
+ assert(owner.info.decls.lookup(name) == NoSymbol, owner.fullNameString + "." + name)
+ val clazz = owner.newClass(NoPos, name.toTypeName)
+ val module = owner.newModule(NoPos, name)
+ clazz.setInfo(completer)
+ module.setInfo(completer)
+ module.moduleClass.setInfo(moduleClassLoader)
+ owner.info.decls.enter(clazz)
+ owner.info.decls.enter(module)
+// if (completer.sourceFile != null) {
+// clazz.sourceFile = completer.sourceFile;
+// module.moduleClass.sourceFile = completer.sourceFile
+// }
+ assert(clazz.linkedModuleOfClass == module, module)
+ assert(module.linkedClassOfModule == clazz, clazz)
+ //System.out.println("Added class " + clazz.fullNameString);
+ clazz
+ }
+
protected def doComplete(root: Symbol): unit = {
assert(root.isPackageClass, root)
+ this.root = root
val scope = newScope
root.setInfo(new PackageClassInfoType(scope, root))
@@ -102,40 +140,13 @@ abstract class SymbolLoaders {
name.length() > 0 && (settings.XbytecodeRead.value ||
(!name.endsWith("$class") && name.indexOf("$anon") == -1));
- def enterPackage(str: String, completer: SymbolLoader): unit = {
- val pkg = root.newPackage(NoPos, newTermName(str))
- pkg.moduleClass.setInfo(completer)
- pkg.setInfo(pkg.moduleClass.tpe)
- root.info.decls.enter(pkg)
- }
-
- def enterClassAndModule(str: String, completer: SymbolLoader): unit = {
- val owner = if (root.isRoot) definitions.EmptyPackageClass else root
- val name = newTermName(str)
- val clazz = owner.newClass(NoPos, name.toTypeName)
- val module = owner.newModule(NoPos, name)
- clazz.setInfo(completer)
- module.setInfo(completer)
- module.moduleClass.setInfo(moduleClassLoader)
- owner.info.decls.enter(clazz)
- owner.info.decls.enter(module)
-/*
- if (completer.sourceFile ne null) {
- clazz.sourceFile = completer.sourceFile;
- module.moduleClass.sourceFile = completer.sourceFile
- }
-*/
- assert(clazz.linkedModuleOfClass == module, module)
- assert(module.linkedClassOfModule == clazz, clazz)
- }
-
val classes = new HashMap[String, global.classPath0.Context]
val packages = new HashMap[String, global.classPath0.Context]
for (val dir <- directory.entries) if (dir.location ne null) {
for (val file <- dir.location) {
if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name))
packages(file.name) = directory.find(file.name, true);
- else if (!file.isDirectory && file.name.endsWith(".class")) {
+ else if (!global.forMSIL && !file.isDirectory && file.name.endsWith(".class")) {
val name = file.name.substring(0, file.name.length() - (".class").length());
if (isValid(name) && !classes.isDefinedAt(name)) {
val clazz = directory.find(name, false)
@@ -147,33 +158,35 @@ abstract class SymbolLoaders {
for (val dir <- directory.entries) if (dir.source ne null) {
for (val file <- dir.source.location) {
if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name))
- packages(file.name) = directory.find(file.name, true);
+ packages(file.name) = directory.find(file.name, true)
else if (dir.source.compile && !file.isDirectory && file.name.endsWith(".scala")) {
- val name = file.name.substring(0, file.name.length() - (".scala").length());
+ val name = file.name.substring(0, file.name.length() - (".scala").length())
if (isValid(name) && !classes.isDefinedAt(name)) {
val source = directory.find(name, false)
- if (source ne null) classes(name) = source
+ if ((source ne null) && (source.sourceFile ne null))
+ if (checkSource(name, source.sourceFile))
+ classes(name) = source
+ else if (settings.debug.value)
+ Console.println("Skipping source file " + source.sourceFile)
}
}
}
}
- //if (!packages.isEmpty) System.err.println("COMPLETE: " + packages)
- //if (! classes.isEmpty) System.err.println("COMPLETE: " + classes)
- // do classes first
+ // do classes first
for (val {name, file} <- classes.elements) {
val loader = if (!file.isSourceFile) {
- new ClassfileLoader(file.classFile, file.sourceFile, file.sourcePath);
+ new ClassfileLoader(file.classFile, file.sourceFile, file.sourcePath)
} else {
assert(file.sourceFile ne null)
new SourcefileLoader(file.sourceFile)
}
enterClassAndModule(name, loader)
}
+
for (val {name, file} <- packages.elements)
- enterPackage(name, new PackageLoader(file))
+ enterPackage(name, newPackageLoader(file))
}
- protected def kindString: String = "directory path"
}
/*
@@ -182,7 +195,68 @@ abstract class SymbolLoaders {
}
*/
+ class NamespaceLoader(directory: global.classPath0.Context) extends PackageLoader(directory) {
+
+ override protected def kindString: String = "namespace " + namespace
+
+ override protected def sourceString = "";
+
+ override def newPackageLoader(dir: global.classPath0.Context): PackageLoader =
+ new NamespaceLoader(dir);
+
+ val types = new HashMap[String,MSILType]();
+
+ val namespaces = new HashSet[String]();
+
+ def namespace: String = if (root.isRoot) "" else root.fullNameString;
+
+ // TODO: Add check whether the source is newer than the assembly
+ override protected def checkSource(name: String, source: AbstractFile): Boolean = {
+ !types.contains(name)
+ }
+
+ override protected def doComplete(root: Symbol): Unit = {
+ clrTypes.collectMembers(root, types, namespaces);
+
+ super.doComplete(root);
+
+ for (val namespace <- namespaces.elements) {
+ val oldPkg = root.info.decls.lookup(newTermName(namespace));
+ if (oldPkg == NoSymbol)
+ enterPackage(namespace, new NamespaceLoader(new classPath0.Context(List())));
+ //else System.out.println("PackageLoader: package already in scope: " + oldPkg.fullNameString);
+ }
+
+ // import the CLR types contained in the package (namespace)
+ for (val Pair(name, typ) <- types.elements) {
+ assert(namespace == typ.Namespace, typ.FullName);
+
+ if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {
+ val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false);
+ assert (attrs.length == 1, attrs.length);
+ val a = attrs(0).asInstanceOf[MSILAttribute];
+ if (a.getConstructor() == clrTypes.SYMTAB_CONSTR)
+ enterClassAndModule(name, new MSILTypeLoader(typ));
+ }
+ else
+ enterClassAndModule(name, new MSILTypeLoader(typ));
+ }
+ }
+ } // NamespaceLoader
+
+ class MSILTypeLoader(typ: MSILType) extends SymbolLoader {
+ private object typeParser extends clr.TypeParser {
+ val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
+ }
+ protected def doComplete(root: Symbol): Unit = {
+ typeParser.parse(typ, root);
+ }
+ protected def kindString: String = typ.FullName;
+ protected def sourceString = typ.Assembly.FullName;
+ }
+
class ClassfileLoader(classFile: AbstractFile, override val sourceFile: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader {
+ //throw new Error("classfile = " + classFile + "; sourcefile = " + sourceFile + "; sourcepath = " + sourcePath0)
private object classfileParser extends ClassfileParser {
val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global
override def sourcePath = sourcePath0 /* could be null */
@@ -215,4 +289,10 @@ abstract class SymbolLoaders {
protected def kindString: String = "";
protected def sourceString = "";
}
+
+ object clrTypes extends clr.CLRTypes {
+ val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
+ if (global.forMSIL) init();
+ }
+
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 85e0f95bec..60c795920e 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -23,6 +23,9 @@ abstract class SymbolTable extends Names
/** Are we compiling for the J2ME CLDC platform? */
def forCLDC: Boolean
+ /** Are we compiling for .NET*/
+ def forMSIL: Boolean
+
/** A period is an ordinal number for a phase in a run.
* Phases in later runs have higher periods than phases in earlier runs.
* Later phases have higher periods than earlier phases in the same run.
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala
new file mode 100644
index 0000000000..f90f6d6624
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala
@@ -0,0 +1,254 @@
+/* NSC -- new scala compiler
+ * Copyright 2004-2006 LAMP/EPFL
+ */
+
+// $Id: CLRTypes.scala 9524 2006-12-14 17:54:07Z mihaylov $
+
+package scala.tools.nsc.symtab.clr;
+
+import scala.tools.nsc.util.Position;
+
+import scala.collection.mutable.{ListBuffer, Map, HashMap, Set, HashSet};
+import java.util.{Arrays, Comparator, StringTokenizer};
+
+import java.io.File;
+
+import ch.epfl.lamp.compiler.msil._;
+
+/**
+ * Collects all types from all reference assemblies.
+ */
+abstract class CLRTypes {
+
+ val global: Global;
+ import global.Symbol;
+ import global.definitions;
+
+ //##########################################################################
+
+ var BYTE: Type = _;
+ var UBYTE: Type = _;
+ var SHORT: Type = _;
+ var USHORT: Type = _;
+ var CHAR: Type = _;
+ var INT: Type = _;
+ var UINT: Type = _;
+ var LONG: Type = _;
+ var ULONG: Type = _;
+ var FLOAT: Type = _;
+ var DOUBLE: Type = _;
+ var BOOLEAN: Type = _;
+ var VOID: Type = _;
+ var ENUM: Type = _;
+ var DELEGATE: Type = _;
+
+ var OBJECT: Type = _;
+ var STRING: Type = _;
+ var STRING_ARRAY: Type = _;
+
+ var VALUE_TYPE: Type = _;
+
+ var SCALA_SYMTAB_ATTR: Type = _;
+ var SYMTAB_CONSTR: ConstructorInfo = _;
+ var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _;
+
+ var DELEGATE_COMBINE: MethodInfo = _;
+ var DELEGATE_REMOVE: MethodInfo = _;
+
+ val types: Map[Symbol,Type] = new HashMap;
+ val constructors: Map[Symbol,ConstructorInfo] = new HashMap;
+ val methods: Map[Symbol,MethodInfo] = new HashMap;
+ val fields: Map[Symbol, FieldInfo] = new HashMap;
+ val sym2type: Map[Type,Symbol] = new HashMap;
+
+ private var alltypes: Array[Type] = _;
+
+ def init(): Unit = { // initialize
+
+ val assems = new StringTokenizer(global.settings.assemrefs.value, File.pathSeparator);
+ while (assems.hasMoreTokens()) {
+ assemrefs += new File(assems.nextToken());
+ }
+
+ val mscorlib = findAssembly("mscorlib.dll");
+ Type.initMSCORLIB(mscorlib);
+ findAssembly("scalaruntime.dll");
+ findAllAssemblies();
+
+ BYTE = getTypeSafe("System.SByte");
+ UBYTE = getTypeSafe("System.Byte");
+ CHAR = getTypeSafe("System.Char");
+ SHORT = getTypeSafe("System.Int16");
+ USHORT = getTypeSafe("System.UInt16");
+ INT = getTypeSafe("System.Int32");
+ UINT = getTypeSafe("System.UInt32");
+ LONG = getTypeSafe("System.Int64");
+ ULONG = getTypeSafe("System.UInt64");
+ FLOAT = getTypeSafe("System.Single");
+ DOUBLE = getTypeSafe("System.Double");
+ BOOLEAN = getTypeSafe("System.Boolean");
+ VOID = getTypeSafe("System.Void");
+ ENUM = getTypeSafe("System.Enum");
+ DELEGATE = getTypeSafe("System.MulticastDelegate");
+
+ OBJECT = getTypeSafe("System.Object");
+ STRING = getTypeSafe("System.String");
+ STRING_ARRAY = getTypeSafe("System.String[]");
+ VALUE_TYPE = getTypeSafe("System.ValueType");
+
+ SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute");
+ val bytearray: Array[Type] = Array( Type.GetType("System.Byte[]") );
+ SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray);
+ SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes);
+
+ //assert(SCALA_SYMTAB_ATTR != null);
+
+ val delegate: Type = getTypeSafe("System.Delegate");
+ val dargs: Array[Type] = Array(delegate, delegate);
+ DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs);
+ DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs);
+ //assert(DELEGATE_COMBINE != null);
+ //assert(DELEGATE_REMOVE != null);
+
+
+ var alltypes: Array[Type] = Type.EmptyTypes;
+ for (val assem <- assemblies) {
+ val atypes = assem.GetTypes().filter((typ: Type) => typ.DeclaringType == null);
+ alltypes = Array.concat(alltypes, atypes);
+ }
+
+ val typeNameComparator: Comparator =
+ new Comparator() {
+ def compare(o1: Any, o2: Any): Int = {
+ val t1 = o1.asInstanceOf[Type];
+ val t2 = o2.asInstanceOf[Type];
+ t1.FullName.compareTo(t2.FullName);
+ }
+ };
+
+ Arrays.sort(alltypes.asInstanceOf[Array[Object]], typeNameComparator);
+ this.alltypes = alltypes;
+ }
+
+ //##########################################################################
+ // type mapping and lookup
+
+// private class MyHashMap[A, B <: AnyRef] extends HashMap[A, B] {
+// override def default(key: A): B = null;
+// }
+
+ def getType(name: String): Type = Type.GetType(name);
+
+ def getTypeSafe(name: String): Type = {
+ val t = Type.GetType(name);
+ assert(t != null, name);
+ t;
+ }
+
+ def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]");
+
+ def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE }
+
+ //##########################################################################
+ // assembly loading methods
+
+ // a list of all loaded assemblies
+ private var assemblies: ListBuffer[Assembly] = new ListBuffer();
+
+ // a set of all directories and assembly files
+ private var assemrefs: Set[File] = new HashSet();
+
+ /** Load the assembly with the given name
+ */
+ private def findAssembly(name: String): Assembly = {
+ // see if the assembly is referenced directly
+ for (val file <- assemrefs.elements; file.getName() == name) {
+ val assem = Assembly.LoadFrom(file.getPath());
+ if (assem != null) {
+ assemrefs -= file;
+ assemblies += assem;
+ return assem;
+ }
+ }
+ // look in directories specified with the '-r' option
+ for (val dir <- assemrefs.elements; dir.isDirectory()) {
+ val file = new File(dir, name);
+ if (file.exists()) {
+ val assem = Assembly.LoadFrom(file.getPath());
+ if (assem != null) {
+ assemblies += assem;
+ return assem;
+ }
+ }
+ }
+ // try in the current directory
+ val file = new File(".", name);
+ if (file.exists()) {
+ val assem = Assembly.LoadFrom(file.getPath());
+ if (assem != null) {
+ assemblies += assem;
+ return assem;
+ }
+ }
+ global.reporter.error(new Position(null, Position.NOPOS),
+ "cannot find assembly " + name + "; use the -r option to specify its location");
+ throw new Error();
+ }
+
+ /** Load the rest of the assemblies specified with the '-r' option
+ */
+ private def findAllAssemblies(): Unit = {
+ for (val file <- assemrefs.elements) {
+ if (file.isFile()) {
+ //System.out.println("Loading assembly " + file)
+ val assem = Assembly.LoadFrom(file.getPath());
+ if (assem != null) {
+ assemblies += assem;
+ }
+ }
+ assemrefs -= file;
+ }
+ assert(assemrefs.isEmpty, assemrefs.toString());
+ }
+
+ //##########################################################################
+ // collect the members contained in a given namespace
+
+ /** Find the position of the first type whose name starts with
+ * the given prefix; return the length of the types array if no match
+ * is found so the result can be used to terminate loop conditions
+ */
+ private def findFirst(prefix: String): Int = {
+ var m = 0;
+ var n = alltypes.length - 1;
+ while (m < n) {
+ val l = (m + n) / 2;
+ val res = alltypes(l).FullName.compareTo(prefix);
+ if (res < 0) m = l + 1;
+ else n = l;
+ }
+ if (alltypes(m).FullName.startsWith(prefix)) m else alltypes.length;
+ }
+
+ /** Collects the members contained in the given Scala package (namespace)
+ */
+ def collectMembers(pakage: Symbol, typesMap: Map[String,Type], namespacesSet: Set[String]) = {
+ val namespace = if (pakage.isRoot) "" else pakage.fullNameString + ".";
+ val nl = namespace.length();
+ var i = findFirst(namespace);
+ while (i < alltypes.length && alltypes(i).FullName.startsWith(namespace)) {
+ val typ = alltypes(i);
+ if (typ.FullName != "java.lang.Object" && typ.FullName != "java.lang.String") {
+ val k = typ.FullName.indexOf(".", nl);
+ if (k < 0) {
+ typesMap.update(typ.Name, typ);
+ } else {
+ namespacesSet += (typ.Namespace.substring(nl, k));
+ }
+ }
+ i = i + 1;
+ }
+ }
+
+ //##########################################################################
+} // CLRTypes
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
new file mode 100644
index 0000000000..2331ca9977
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
@@ -0,0 +1,506 @@
+/* NSC -- new scala compiler
+ * Copyright 2004-2006 LAMP/EPFL
+ */
+
+// $Id: TypeParser.scala 8734 2006-09-21 14:56:02Z mihaylov $
+
+package scala.tools.nsc.symtab.clr;
+
+import scala.tools.nsc.util.Position;
+import classfile.UnPickler;
+import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _};
+
+import scala.collection.mutable.{HashMap, HashSet};
+import java.io.IOException;
+
+abstract class TypeParser {
+
+ val global: Global;
+
+ import global._;
+ import loaders.clrTypes;
+
+ //##########################################################################
+
+ private var clazz: Symbol = _;
+ private var instanceDefs: Scope = _; // was members
+ private var staticModule: Symbol = _; // was staticsClass
+ private var staticDefs: Scope = _; // was statics
+
+ protected def statics: Symbol = staticModule.moduleClass
+
+ protected var busy: boolean = false // lock to detect recursive reads
+
+ private object unpickler extends UnPickler {
+ val global: TypeParser.this.global.type = TypeParser.this.global
+ }
+
+
+ def parse(typ: MSILType, root: Symbol): Unit = {
+
+ def handleError(e: Exception) = {
+ if (settings.debug.value) e.printStackTrace(); //debug
+ throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")")
+ }
+ assert(!busy)
+ busy = true
+
+ if (root.isModule) {
+ this.clazz = root.linkedClassOfModule
+ this.staticModule = root
+ } else {
+ this.clazz = root
+ this.staticModule = root.linkedModuleOfClass
+ }
+ try {
+ parseClass(typ)
+ } catch {
+ case e: FatalError => handleError(e)
+ case e: RuntimeException => handleError(e)
+ }
+ busy = false
+ }
+
+ private def parseClass(typ: MSILType): Unit = {
+
+ clrTypes.types(clazz) = typ;
+ clrTypes.sym2type(typ) = clazz;
+
+ if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {
+ val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false);
+ assert (attrs.length == 1, attrs.length);
+ val a = attrs(0).asInstanceOf[MSILAttribute];
+ assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR);
+ val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]]
+ unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName);
+ val mClass = clrTypes.getType(typ.FullName + "$");
+ if (mClass != null) {
+ clrTypes.types(statics) = mClass;
+ val moduleInstance = mClass.GetField("MODULE$");
+ assert (moduleInstance != null, mClass);
+ clrTypes.fields(statics) = moduleInstance;
+ }
+ return;
+ }
+ val flags = translateAttributes(typ);
+ val ifaces: Array[MSILType] = typ.getInterfaces();
+ val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType())
+ else if (typ.IsInterface()) definitions.ObjectClass.tpe
+ else definitions.AnyClass.tpe; // this is System.Object
+ val parents = superType :: ifaces.map(getCLRType).toList;
+ instanceDefs = newScope;
+ staticDefs = newScope;
+
+ val classInfo = ClassInfoType(parents, instanceDefs, clazz);
+ val staticInfo = ClassInfoType(List(), staticDefs, statics);
+
+ clazz.setFlag(flags);
+ clazz.setInfo(classInfo);
+ statics.setFlag(Flags.JAVA);
+ statics.setInfo(staticInfo);
+ staticModule.setFlag(Flags.JAVA);
+ staticModule.setInfo(statics.tpe);
+
+ // import nested types
+ for (val ntype <- typ.getNestedTypes(); (!(ntype.IsNestedPrivate
+ || ntype.IsNestedAssembly
+ || ntype.IsNestedFamANDAssem)
+ || ntype.IsInterface) )
+ {
+ val loader = new loaders.MSILTypeLoader(ntype)
+ val nclazz = statics.newClass(NoPos, ntype.Name.toTypeName)
+ val nmodule = statics.newModule(NoPos, ntype.Name)
+ nclazz.setInfo(loader)
+ nmodule.setInfo(loader)
+ staticDefs.enter(nclazz)
+ staticDefs.enter(nmodule)
+
+ assert(nclazz.linkedModuleOfClass == nmodule, nmodule);
+ assert(nmodule.linkedClassOfModule == nclazz, nclazz);
+ }
+
+ val fields = typ.getFields();
+ for (val field <- fields; !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly)) {
+ val flags = translateAttributes(field);
+ val name = newTermName(field.Name);
+ val fieldType =
+ if (field.IsLiteral && !field.FieldType.IsEnum)
+ ConstantType(getConstant(getCLRType(field.FieldType), field.getValue))
+ else getCLRType(field.FieldType);
+ val owner = if (field.IsStatic()) statics else clazz;
+ val sym = owner.newValue(NoPos, name).setFlag(flags).setInfo(fieldType);
+ // TODO: set private within!!! -> look at typechecker/Namers.scala
+ (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym);
+ clrTypes.fields(sym) = field;
+ }
+
+ for (val constr <- typ.getConstructors(); !constr.IsStatic() && !constr.IsPrivate() &&
+ !constr.IsAssembly() && !constr.IsFamilyAndAssembly())
+ createMethod(constr);
+
+ // initially also contains getters an setters of properties.
+ val methodsSet = new HashSet[MethodInfo]();
+ methodsSet ++= typ.getMethods();
+
+ for (val prop <- typ.getProperties) {
+ val propType: Type = getCLSType(prop.PropertyType);
+ if (propType != null) {
+ val getter: MethodInfo = prop.GetGetMethod(true);
+ val setter: MethodInfo = prop.GetSetMethod(true);
+ var gparamsLength: Int = -1;
+ if (!(getter == null || getter.IsPrivate || getter.IsAssembly
+ || getter.IsFamilyAndAssembly))
+ {
+ assert(prop.PropertyType == getter.ReturnType);
+ val gparams: Array[ParameterInfo] = getter.GetParameters();
+ gparamsLength = gparams.length;
+ val name: Name = if (gparamsLength == 0) prop.Name else nme.apply;
+ val flags = translateAttributes(getter);
+ val mtype: Type = if (gparamsLength == 0) PolyType(List(), propType)
+ else methodType(getter, getter.ReturnType);
+ val owner: Symbol = if (getter.IsStatic) statics else clazz;
+ val methodSym = owner.newMethod(NoPos, name).setFlag(flags).setInfo(mtype);
+ methodSym.setFlag(Flags.ACCESSOR);
+ (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym)
+ clrTypes.methods(methodSym) = getter;
+ methodsSet -= getter;
+ }
+ if (!(setter == null || setter.IsPrivate || setter.IsAssembly
+ || setter.IsFamilyAndAssembly))
+ {
+ val sparams: Array[ParameterInfo] = setter.GetParameters()
+ if(getter != null)
+ assert(getter.IsStatic == setter.IsStatic);
+ assert(setter.ReturnType == clrTypes.VOID);
+ if(getter != null)
+ assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter);
+
+ val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name)
+ else nme.update;
+ val flags = translateAttributes(setter);
+ val mtype: Type = methodType(setter, definitions.UnitClass.tpe);
+ val owner: Symbol = if (setter.IsStatic) statics else clazz;
+ val methodSym = owner.newMethod(NoPos, name).setFlag(flags).setInfo(mtype);
+ methodSym.setFlag(Flags.ACCESSOR);
+ (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym);
+ clrTypes.methods(methodSym) = setter;
+ methodsSet -= setter;
+ }
+ }
+ }
+
+/* for (val event <- typ.GetEvents) {
+ // adding += and -= methods to add delegates to an event.
+ // raising the event ist not possible from outside the class (this is so
+ // generally in .net world)
+ val adder: MethodInfo = event.GetAddMethod();
+ val remover: MethodInfo = event.GetRemoveMethod();
+ if (!(adder == null || adder.IsPrivate || adder.IsAssembly
+ || adder.IsFamilyAndAssembly))
+ {
+ assert(adder.ReturnType == clrTypes.VOID);
+ assert(adder.GetParameters().map(.ParameterType).toList == List(event.EventHandlerType));
+ val name = encode("+=");
+ val flags = translateAttributes(adder);
+ val mtype: Type = methodType(adder, adder.ReturnType);
+ createMethod(name, flags, mtype, adder, adder.IsStatic)
+ methodsSet -= adder;
+ }
+ if (!(remover == null || remover.IsPrivate || remover.IsAssembly
+ || remover.IsFamilyAndAssembly))
+ {
+ assert(remover.ReturnType == clrTypes.VOID);
+ assert(remover.GetParameters().map(.ParameterType).toList == List(event.EventHandlerType));
+ val name = encode("-=");
+ val flags = translateAttributes(remover);
+ val mtype: Type = methodType(remover, remover.ReturnType);
+ createMethod(name, flags, mtype, remover, remover.IsStatic)
+ methodsSet -= remover;
+ }
+ } */
+
+ for (val method <- methodsSet.elements)
+ if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly())
+ createMethod(method);
+
+
+ // Create methods and views for delegate support
+ if (clrTypes.isDelegateType(typ)) {
+ createDelegateView(typ);
+ createDelegateChainers(typ);
+ }
+
+ // create the box/unbox methods for value types
+ if (typ.IsValueType) {
+ val box = statics.newMethod(NoPos, nme.box).
+ setInfo(MethodType(List(clazz.tpe), definitions.ObjectClass.tpe));
+ definitions.isBox += box;
+ definitions.boxMethod(clazz) = box;
+ val unbox = statics.newMethod(NoPos, nme.unbox).
+ setInfo(MethodType(List(definitions.ObjectClass.tpe), clazz.tpe));
+ definitions.isUnbox += unbox;
+ definitions.unboxMethod(clazz) = unbox;
+ //Console.println(typ.FullName + " : " + parents);
+ }
+
+ // for enumerations introduce comparison and bitwise logical operations;
+ // the backend should recognize and replace them with comparison or
+ // bitwise logical operations on the primitive underlying type
+
+ if (typ.IsEnum) {
+ val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE);
+ val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR);
+
+ val flags = Flags.JAVA | Flags.FINAL;
+ for (val cmpName <- ENUM_CMP_NAMES) {
+ val enumCmpType: Type = JavaMethodType(List(clazz.tpe), definitions.BooleanClass.tpe);
+ val enumCmp: Symbol = clazz.newMethod(NoPos, cmpName);
+ enumCmp.setFlag(flags).setInfo(enumCmpType)
+ instanceDefs.enter(enumCmp);
+ }
+
+ for (val bitLogName <- ENUM_BIT_LOG_NAMES) {
+ val enumBitLogType = JavaMethodType(List(clazz.tpe), classInfo);
+ val enumBitLog = clazz.newMethod(NoPos, bitLogName);
+ enumBitLog.setFlag(flags).setInfo(enumBitLogType);
+ instanceDefs.enter(enumBitLog);
+ }
+ }
+
+ } // parseClass
+
+ private def createMethod(method: MethodBase): Unit = {
+ val rettype = if (method.IsConstructor()) clazz.tpe
+ else getCLSType(method.asInstanceOf[MethodInfo].ReturnType);
+ if (rettype == null) return;
+ val mtype = methodType(method, rettype);
+ if (mtype == null) return;
+ val flags = translateAttributes(method);
+ val owner = if (method.IsStatic()) statics else clazz;
+ val methodSym = owner.newMethod(NoPos, getName(method)).setFlag(flags).
+ setInfo(mtype);
+ (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym);
+ if (method.IsConstructor())
+ clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo]
+ else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo];
+ }
+
+ private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = {
+ val mtype: Type = methodType(args, getCLSType(retType));
+ assert(mtype != null);
+ createMethod(name, flags, mtype, method, statik)
+ }
+
+ private def createMethod(name: Name, flags: Long, mtype: Type, method: MethodInfo, statik: Boolean): Symbol = {
+ val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPos, name);
+ methodSym.setFlag(flags).setInfo(mtype);
+ (if (statik) staticDefs else instanceDefs).enter(methodSym);
+ if (method != null)
+ clrTypes.methods(methodSym) = method;
+ methodSym
+ }
+
+ private def createDelegateView(typ: MSILType) = {
+ val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo];
+ val invokeRetType: Type = getCLRType(invoke.ReturnType);
+ val invokeParamTypes: List[Type] =invoke.GetParameters().map(.ParameterType).map(getCLSType).toList;
+ val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType);
+
+ val typClrType: Type = getCLRType(typ);
+ val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed
+
+ // create the forward view: delegate => function
+ val delegateParamTypes: List[Type] = List(typClrType);
+ // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods)
+ val forwardViewMethodType = JavaMethodType(delegateParamTypes, funType);
+ val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true);
+
+ // create the backward view: function => delegate
+ val functionParamTypes: List[Type] = List(funType);
+ val backwardViewMethodType = JavaMethodType(functionParamTypes, typClrType);
+ val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true);
+ }
+
+ private def createDelegateChainers(typ: MSILType) = {
+ val flags: Long = Flags.JAVA | Flags.FINAL;
+ val args: Array[MSILType] = Array(typ);
+
+ var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false);
+ s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false);
+
+ s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false);
+ s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false);
+ }
+
+ private def getName(method: MethodBase): Name = {
+ if (method.IsConstructor()) return nme.CONSTRUCTOR;
+ val name = method.Name;
+ if (method.IsStatic()) return newTermName(name);
+ val params = method.GetParameters();
+ name match {
+ case "GetHashCode" if (params.length == 0) => nme.hashCode_;
+ case "ToString" if (params.length == 0) => nme.toString_;
+ case "Finalize" if (params.length == 0) => nme.finalize_;
+ case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) =>
+ nme.equals_;
+ case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply;
+ case _ => newTermName(name);
+ }
+ }
+
+ //##########################################################################
+
+ private def methodType(method: MethodBase, rettype: MSILType): Type = {
+ val rtype = getCLSType(rettype);
+ if (rtype == null) null else methodType(method, rtype);
+ }
+
+ /** Return a method type for the given method. */
+ private def methodType(method: MethodBase, rettype: Type): Type =
+ methodType(method.GetParameters().map(.ParameterType), rettype);
+
+ /** Return a method type for the provided argument types and return type. */
+ private def methodType(argtypes: Array[MSILType], rettype: Type): Type = {
+ def paramType(typ: MSILType): Type =
+ if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe
+ else getCLSType(typ);
+ val ptypes = argtypes.map(paramType).toList;
+ if (ptypes.contains(null)) null
+ else JavaMethodType(ptypes, rettype);
+ }
+
+ //##########################################################################
+
+ private def getClassType(typ: MSILType): Type = {
+ assert(typ != null);
+ val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe;
+ //if (res.isError())
+ // global.reporter.error("unknown class reference " + type.FullName);
+ res
+ }
+
+ private def getCLSType(typ: MSILType): Type = {
+ if (/*type == clrTypes.BYTE ||*/ typ == clrTypes.USHORT
+ || typ == clrTypes.UINT || typ == clrTypes.ULONG
+ || typ.IsNotPublic() || typ.IsNestedPrivate()
+ || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()
+ || typ.IsPointer()
+ || (typ.IsArray() && getCLSType(typ.GetElementType()) == null))
+ null;
+ //Symbol s = clrTypes.getSymbol(type);
+ //scalac.symtab.Type t = s != null ? make.classType(s) : getCLRType(type);
+ else
+ getCLRType(typ)
+ }
+
+ private def getCLRType(typ: MSILType): Type =
+ if (typ == clrTypes.OBJECT)
+ definitions.ObjectClass.tpe;
+ else if (typ == clrTypes.VALUE_TYPE)
+ definitions.AnyValClass.tpe
+ else if (typ == clrTypes.STRING)
+ definitions.StringClass.tpe;
+ else if (typ == clrTypes.VOID)
+ definitions.UnitClass.tpe
+ else if (typ == clrTypes.BOOLEAN)
+ definitions.BooleanClass.tpe
+ else if (typ == clrTypes.CHAR)
+ definitions.CharClass.tpe
+ else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE)
+ definitions.ByteClass.tpe
+ else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT)
+ definitions.ShortClass.tpe
+ else if (typ == clrTypes.INT || typ == clrTypes.UINT)
+ definitions.IntClass.tpe
+ else if (typ == clrTypes.LONG || typ == clrTypes.ULONG)
+ definitions.LongClass.tpe
+ else if (typ == clrTypes.FLOAT)
+ definitions.FloatClass.tpe
+ else if (typ == clrTypes.DOUBLE)
+ definitions.DoubleClass.tpe
+ else if (typ.IsArray())
+ appliedType(definitions.ArrayClass.tpe,
+ List(getCLRType(typ.GetElementType())));
+ else {
+ val res = clrTypes.sym2type.get (typ) match {
+ case Some(sym) => sym.tpe
+ case None => getClassType(typ);
+ }
+ assert (res != null, typ)
+ res
+ }
+
+ // the values are Java-Box-Classes (e.g. Integer, Boolean, Character)
+ // java.lang.Number to get the value (if a number, not for boolean, character)
+ // see ch.epfl.lamp.compiler.msil.util.PEStream.java
+ def getConstant(constType: Type, value: Object): Constant = {
+ val typeClass = constType.symbol
+ if (typeClass == definitions.BooleanClass)
+ Constant(value.asInstanceOf[java.lang.Boolean].booleanValue)
+ else if (typeClass == definitions.ByteClass)
+ Constant(value.asInstanceOf[java.lang.Number].byteValue)
+ else if (typeClass == definitions.ShortClass)
+ Constant(value.asInstanceOf[java.lang.Number].shortValue)
+ else if (typeClass == definitions.CharClass)
+ Constant(value.asInstanceOf[java.lang.Character].charValue)
+ else if (typeClass == definitions.IntClass)
+ Constant(value.asInstanceOf[java.lang.Number].intValue)
+ else if (typeClass == definitions.LongClass)
+ Constant(value.asInstanceOf[java.lang.Number].longValue)
+ else if (typeClass == definitions.FloatClass)
+ Constant(value.asInstanceOf[java.lang.Number].floatValue)
+ else if (typeClass == definitions.DoubleClass)
+ Constant(value.asInstanceOf[java.lang.Number].doubleValue)
+ else if (typeClass == definitions.StringClass)
+ Constant(value.asInstanceOf[java.lang.String])
+ else
+ abort("illegal value: " + value + ", class-symbol: " + typeClass)
+ }
+
+ private def translateAttributes(typ: MSILType): Long = {
+ var flags: Long = Flags.JAVA;
+ if (typ.IsNotPublic() || typ.IsNestedPrivate()
+ || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem())
+ flags = flags | Flags.PRIVATE;
+ else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem())
+ flags = flags | Flags.PROTECTED;
+ if (typ.IsAbstract())
+ flags = flags | Flags.ABSTRACT;
+ if (typ.IsSealed())
+ flags = flags | Flags.FINAL;
+ if (typ.IsInterface())
+ flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT;
+
+ flags
+ }
+
+ private def translateAttributes(field: FieldInfo): Long = {
+ var flags: Long = Flags.JAVA;
+ if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly())
+ flags = flags | Flags.PRIVATE;
+ else if (field.IsFamily() || field.IsFamilyOrAssembly())
+ flags = flags | Flags.PROTECTED;
+ if (field.IsInitOnly())
+ flags = flags | Flags.FINAL;
+ else
+ flags = flags | Flags.MUTABLE;
+ if (field.IsStatic)
+ flags = flags | Flags.STATIC
+
+ flags
+ }
+
+ private def translateAttributes(method: MethodBase): Long = {
+ var flags: Long = Flags.JAVA;
+ if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly())
+ flags = flags | Flags.PRIVATE;
+ else if (method.IsFamily() || method.IsFamilyOrAssembly())
+ flags = flags | Flags.PROTECTED;
+ if (method.IsAbstract())
+ flags = flags | Flags.DEFERRED;
+ if (method.IsStatic)
+ flags = flags | Flags.STATIC
+
+ flags
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index afb97969e7..52070f7083 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -69,7 +69,7 @@ abstract class CleanUp extends Transform {
}
override def transformUnit(unit: CompilationUnit) =
- if (settings.target.value != "jvm-1.5") {
+ if (settings.target.value != "jvm-1.5" && !forMSIL) {
unit.body = transform(unit.body)
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index c0dcd5b896..e10fdaf406 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -85,7 +85,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
else apply(parents.head)
case ClassInfoType(parents, decls, clazz) =>
ClassInfoType(
- if ((clazz == ObjectClass) || (isValueClass(clazz))) List()
+ if ((clazz == ObjectClass) || (isValueType(clazz))) List()
else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
else removeDoubleObject(parents map this),
decls, clazz)
@@ -330,7 +330,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
*/
private def adaptToType(tree: Tree, pt: Type): Tree = {
if (settings.debug.value && pt != WildcardType)
- log("adapting " + tree + ":" + tree.tpe + " to " + pt)//debug
+ log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug
if (tree.tpe <:< pt)
tree
else if (isUnboxedClass(tree.tpe.symbol) && !isUnboxedClass(pt.symbol))
@@ -403,6 +403,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
* </ul>
*/
private def adaptMember(tree: Tree): Tree = {
+ //Console.println("adaptMember: " + tree);
tree match {
case Apply(Select(New(tpt), name), args) if (tpt.tpe.symbol == BoxedArrayClass) =>
assert(name == nme.CONSTRUCTOR);
@@ -417,7 +418,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
if (isNumericValueClass(qualClass) && isNumericValueClass(targClass))
// convert numeric type casts
atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))
- else if (isValueClass(targClass) ||
+ else if (isValueType(targClass) ||
(targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass)))
unbox(qual1, targ.tpe)
else if (targClass == ArrayClass && qualClass == ObjectClass)
@@ -435,10 +436,10 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
else {
var qual1 = typedQualifier(qual);
- if ((isValueClass(qual1.tpe.symbol) && !isUnboxedValueMember(tree.symbol)) ||
+ if ((isValueType(qual1.tpe.symbol) && !isUnboxedValueMember(tree.symbol)) ||
(qual1.tpe.symbol == ArrayClass && !isUnboxedArrayMember(tree.symbol)))
qual1 = box(qual1);
- else if (!isValueClass(qual1.tpe.symbol) && isUnboxedValueMember(tree.symbol))
+ else if (!isValueType(qual1.tpe.symbol) && isUnboxedValueMember(tree.symbol))
qual1 = unbox(qual1, tree.symbol.owner.tpe)
else if (tree.symbol.owner == ArrayClass && qual1.tpe.symbol == ObjectClass)
qual1 = cast(qual1, BoxedArrayClass.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 2f37c57306..9bd64801d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -243,7 +243,7 @@ trait SyntheticMethods requires Analyzer {
// jw-04-2003/jw-0425-designpatterns_p.html)
if (!hasImplementation(nme.readResolve)) ts += readResolveMethod
}
- if (!forCLDC)
+ if (!forCLDC && !forMSIL)
for (val sym <- clazz.info.decls.toList)
if (!sym.getAttributes(BeanPropertyAttr).isEmpty)
if (sym.isGetter)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 4328a6b06e..42a3bd1831 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -639,6 +639,14 @@ trait Typers requires Analyzer {
// (13); the condition prevents chains of views
if (settings.debug.value) log("inferring view from "+tree.tpe+" to "+pt)
val coercion = inferView(tree.pos, tree.tpe, pt, true)
+ // convert forward views of delegate types into closures wrapped around
+ // the delegate's apply method (the "Invoke" method, which was translated into apply)
+ if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {
+ val meth: Symbol = tree.tpe.member(nme.apply)
+ if(settings.debug.value)
+ log("replacing forward delegate view with: " + meth + ":" + meth.tpe)
+ return typed(Select(tree, meth), mode, pt)
+ }
if (coercion != EmptyTree) {
if (settings.debug.value) log("inferred view from "+tree.tpe+" to "+pt+" = "+coercion+":"+coercion.tpe)
return typed(Apply(coercion, List(tree)) setPos tree.pos, mode, pt)
@@ -1187,7 +1195,7 @@ trait Typers requires Analyzer {
* @return ...
*/
def typedFunction(fun: Function, mode: int, pt: Type): Tree = {
- val codeExpected = !forCLDC && (pt.symbol isNonBottomSubClass CodeClass)
+ val codeExpected = !forCLDC && !forMSIL && (pt.symbol isNonBottomSubClass CodeClass)
def decompose(pt: Type): {Symbol, List[Type], Type} =
if (isFunctionType(pt)
@@ -1361,6 +1369,28 @@ trait Typers requires Analyzer {
case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp
case _ => tp
}
+
+ // Replace the Delegate-Chainer methods += and -= with corresponding
+ // + and - calls, which are translated in the code generator into
+ // Combine and Remove
+ if (forMSIL) {
+ fun match {
+ case Select(qual, name) =>
+ if (isSubType(qual.tpe, definitions.DelegateClass.tpe)
+ && (name == encode("+=") || name == encode("-=")))
+ {
+ val n = if (name == encode("+=")) nme.PLUS else nme.MINUS
+ val f = Select(qual, n)
+ // the compiler thinks, the PLUS method takes only one argument,
+ // but he thinks it's an instance method -> still two ref's on the stack
+ // -> translated by backend
+ val rhs = copy.Apply(tree, f, args)
+ return typed(Assign(qual, rhs))
+ }
+ case _ => ()
+ }
+ }
+
if (fun.symbol == List_apply && args.isEmpty) {
atPos(tree.pos) { gen.mkNil setType restpe }
} else if ((mode & CONSTmode) != 0 && fun.symbol.owner == PredefModule.tpe.symbol && fun.symbol.name == nme.Array) {
@@ -2007,7 +2037,23 @@ trait Typers requires Analyzer {
case PolyType(_, MethodType(formals, _)) =>
adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
case MethodType(formals, _) =>
- adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
+ expr1 match {
+ case Select(qual, name) =>
+ if(forMSIL && pt != WildcardType && pt != ErrorType && isSubType(pt, definitions.DelegateClass.tpe)) {
+ val scalaCaller = newScalaCaller(pt);
+ addScalaCallerInfo(scalaCaller, expr1.symbol)
+ val n: Name = scalaCaller.name
+ val del = Ident(DelegateClass) setType DelegateClass.tpe
+ val f = Select(del, n)
+ //val f1 = TypeApply(f, List(Ident(pt.symbol) setType pt))
+ val args: List[Tree] = if(expr1.symbol.isStatic) List(Literal(Constant(null)))
+ else List(qual) // where the scala-method is located
+ val rhs = Apply(f, args);
+ return typed(rhs)
+ }
+ case _ => ()
+ }
+ adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
case ErrorType =>
expr1
case _ =>
diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala
index 3c075e8193..488e091390 100644
--- a/src/library/scala/Console.scala
+++ b/src/library/scala/Console.scala
@@ -204,7 +204,7 @@ object Console {
*/
def readLine(text: String, args: Any*): String = {
format(text, args: _*)
- in.readLine()
+ readLine
}
@@ -212,7 +212,7 @@ object Console {
*
* @return the boolean value read from the terminal.
*/
- def readBoolean: Boolean = in.readLine().toLowerCase() match {
+ def readBoolean: Boolean = readLine.toLowerCase() match {
case "true" => true
case "t" => true
case "yes" => true
@@ -252,7 +252,7 @@ object Console {
* @return a list of all extracted values.
*/
def readf(format: String): List[Any] =
- textComponents(new MessageFormat(format).parse(in.readLine()))
+ textComponents(new MessageFormat(format).parse(readLine))
/** Read in some structured input, specified by a format specifier.
* Opposed to <code>readf</code>, this function only returns the
diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala
index cff1c41238..bdd2846272 100644
--- a/src/library/scala/Enumeration.scala
+++ b/src/library/scala/Enumeration.scala
@@ -45,7 +45,7 @@ abstract class Enumeration(initial: Int, names: String*) {
def this(names: String*) = this(0, names: _*)
def name = {
- val cname = compat.Platform.getClassName(this)
+ val cname = this.getClass().getName()
if (cname.endsWith("$"))
cname.substring(0, cname.length() - 1)
else if (cname.endsWith("$class"))
diff --git a/src/library/scala/compat/Platform.scala b/src/library/scala/compat/Platform.scala
index 028c9c8ab2..11e90a0789 100644
--- a/src/library/scala/compat/Platform.scala
+++ b/src/library/scala/compat/Platform.scala
@@ -26,15 +26,12 @@ object Platform {
def createArray(elemClass: Class, length: Int): AnyRef =
java.lang.reflect.Array.newInstance(elemClass, length)
- def getClass(obj: AnyRef) = obj.getClass()
- def getClassName(obj: AnyRef) = obj.getClass().getName()
- def getName(cls: Class) = cls.getName()
- def getElementClass(obj: AnyRef) = obj.getClass().getComponentType()
def getClassForName(name: String): Class = java.lang.Class.forName(name)
val EOL = System.getProperty("line.separator", "\n")
def currentTime: Long = System.currentTimeMillis()
+
def collectGarbage: Unit = System.gc()
}
diff --git a/src/library/scala/runtime/BoxedObjectArray.scala b/src/library/scala/runtime/BoxedObjectArray.scala
index 98f58ea92c..e60cf7f585 100644
--- a/src/library/scala/runtime/BoxedObjectArray.scala
+++ b/src/library/scala/runtime/BoxedObjectArray.scala
@@ -13,7 +13,7 @@ package scala.runtime
import Predef.Class
-import compat.Platform.{createArray, getElementClass}
+import compat.Platform.createArray
[serializable]
final class BoxedObjectArray(val value: Array[AnyRef]) extends BoxedArray {
@@ -36,7 +36,7 @@ final class BoxedObjectArray(val value: Array[AnyRef]) extends BoxedArray {
override def hashCode(): Int = value.hashCode()
private def create(length: Int): Array[AnyRef] = {
- createArray(getElementClass(value), length).asInstanceOf[Array[AnyRef]]
+ createArray(value.getClass().getComponentType(), length).asInstanceOf[Array[AnyRef]]
}
override def subArray(start: Int, end: Int): Array[AnyRef] = {
diff --git a/src/library/scala/util/automata/BaseBerrySethi.scala b/src/library/scala/util/automata/BaseBerrySethi.scala
index 7a7a6c642f..2d590a0edf 100644
--- a/src/library/scala/util/automata/BaseBerrySethi.scala
+++ b/src/library/scala/util/automata/BaseBerrySethi.scala
@@ -16,7 +16,6 @@ import scala.util.regexp.Base
import scala.collection.mutable
import scala.collection.immutable
-import compat.Platform
/** this turns a regexp over A into a NondetWorkAutom over A using the
* celebrated position automata construction (also called Berry-Sethi or
@@ -64,7 +63,7 @@ abstract class BaseBerrySethi {
tmp
case Star(t) => compFirst(t)
case _ =>
- throw new IllegalArgumentException("unexpected pattern " + Platform.getClass(r))
+ throw new IllegalArgumentException("unexpected pattern " + r.getClass())
}
/** computes last( r ) for the regexp r */
@@ -89,7 +88,7 @@ abstract class BaseBerrySethi {
tmp
case Star(t) => compLast(t)
case _ =>
- throw new IllegalArgumentException("unexpected pattern " + Platform.getClass(r))
+ throw new IllegalArgumentException("unexpected pattern " + r.getClass())
}
/** Starts from the right-to-left
@@ -170,7 +169,7 @@ abstract class BaseBerrySethi {
first
case _ =>
- throw new IllegalArgumentException("unexpected pattern: " + Platform.getClass(r))
+ throw new IllegalArgumentException("unexpected pattern: " + r.getClass())
}
}
@@ -193,7 +192,7 @@ abstract class BaseBerrySethi {
case Star(t) =>
traverse(t)
case _ =>
- throw new IllegalArgumentException("unexp pattern " + Platform.getClass(r))
+ throw new IllegalArgumentException("unexp pattern " + r.getClass())
}
}
diff --git a/test/files/run/bug560bis.check b/test/files/jvm/bug560bis.check
index 91eb4c19a2..91eb4c19a2 100644
--- a/test/files/run/bug560bis.check
+++ b/test/files/jvm/bug560bis.check
diff --git a/test/files/run/bug560bis.scala b/test/files/jvm/bug560bis.scala
index 13bf4b1ae0..13bf4b1ae0 100644
--- a/test/files/run/bug560bis.scala
+++ b/test/files/jvm/bug560bis.scala
diff --git a/test/files/run/Course-2002-03.scala b/test/files/run/Course-2002-03.scala
index 7933514f9a..5a470a3561 100644
--- a/test/files/run/Course-2002-03.scala
+++ b/test/files/run/Course-2002-03.scala
@@ -3,6 +3,8 @@
//############################################################################
// $Id$
+import scala.compat.StringBuilder;
+
object M0 {
class Rational(x: Int, y: Int) {
def numer = x;
@@ -230,10 +232,10 @@ object M8 {
def intersect2(that: IntSet): IntSet = filter(x => that.contains(x));
def filter(f: Int => Boolean): IntSet = filter0(f, new Empty);
- def printOn(out: java.io.PrintStream) = foreach(out.println);
+ def print() = foreach(Console.println);
override def toString(): String = {
- val buffer: java.lang.StringBuffer = new java.lang.StringBuffer();
+ val buffer: StringBuilder = new StringBuilder();
buffer.append('[');
foreach(i => {
if (buffer.length() > 1) {buffer.append(','); ()}; // !!! ; ()
@@ -312,7 +314,7 @@ object M8 {
Console.println;
Console.println("set4 contains the following elements:");
- set4.printOn(java.lang.System.out);
+ set4.print();
Console.println;
Console.println("2 <- set2: " + (set2 contains 2));
diff --git a/test/files/run/bugs.scala b/test/files/run/bugs.scala
index 0f77bd5f34..ae23dc6b91 100644
--- a/test/files/run/bugs.scala
+++ b/test/files/run/bugs.scala
@@ -359,9 +359,9 @@ trait Bug266BB extends Bug266BA {
val in = 3;
}
-object Bug266BTest extends Application {
+object Bug266BTest {
val a: Bug266BA1 = new Bug266BA1 with Bug266BB;
- a.mkP.f(a.in);
+ def test(args: Array[String]): Unit = a.mkP.f(a.in);
}
// main
@@ -369,7 +369,7 @@ object Bug266BTest extends Application {
object Bug266Test {
def test(args: Array[String]): Unit = {
Bug266ATest.test(args);
- Bug266BTest;
+ Bug266BTest.test(args);
}
}
@@ -412,9 +412,9 @@ trait Bug396C extends Bug396A {
override def run = { super.run; Console.println("C"); }
}
}
-object Bug396Test extends Application with Bug396B with Bug396C {
+object Bug396Test extends Bug396B with Bug396C {
class I2 extends super[Bug396B].I with super[Bug396C].I;
- (new I2).run
+ def test(args: Array[String]): Unit = (new I2).run
}
//############################################################################
@@ -478,7 +478,7 @@ object Test {
test(266, Bug266Test.test(args));
test(316, Bug316Test.test(args));
test(328, Bug328Test.test(args));
- test(396, Bug396Test);
+ test(396, Bug396Test.test(args));
test(399, Bug399Test.test(args));
if (errors > 0) {
diff --git a/test/files/run/richs-msil.check b/test/files/run/richs-msil.check
new file mode 100644
index 0000000000..e628ad3998
--- /dev/null
+++ b/test/files/run/richs-msil.check
@@ -0,0 +1,66 @@
+
+RichCharTest1:
+True
+True
+True
+False
+
+RichIntTest:
+10
+11
+12
+13
+0
+0
+
+RichStringTest1:
+s1: abc
+s2: abc\txyz\n
+s3: abc
+ xyz
+s4: abc
+ |xyz
+s5: abc
+ #xyz
+
+RichStringTest2:
+s1: abc
+s2: abc\txyz\n
+s3: abc
+ xyz
+s4: abc
+ |xyz
+s5: abc
+ #xyz
+
+RichStringTest3:
+s1: abc
+s2: abc\txyz\n
+s3: abc
+ xyz
+s4: abc
+ |xyz
+s5: abc
+ #xyz
+
+RichStringTest4:
+s1: abc
+s2: abc\txyz\n
+s3: abc
+ xyz
+s4: abc
+xyz
+s5: abc
+ #xyz
+
+RichStringTest5:
+s1: abc
+ xyz
+s2: abc
+ xyz
+s3: abc
+ xyz
+s4: abc
+ |xyz
+s5: abc
+xyz
diff --git a/test/files/run/richs.check b/test/files/run/richs.check
index 3b73f084a0..80b2ef3ef2 100644
--- a/test/files/run/richs.check
+++ b/test/files/run/richs.check
@@ -5,9 +5,6 @@ true
true
true
-RichCharTest2:
-true
-
RichIntTest:
10
11
diff --git a/test/files/run/richs.scala b/test/files/run/richs.scala
index 90eb46d9ad..4df7bc3bf3 100644
--- a/test/files/run/richs.scala
+++ b/test/files/run/richs.scala
@@ -8,7 +8,7 @@ trait RichTest {
val s5 = """abc
#xyz"""
def getObjectName: String = {
- val cn = compat.Platform.getClassName(this)
+ val cn = this.getClass().getName()
cn.substring(0, cn.length-1)
}
def length[A](it: Iterator[A]) = it.toList length
@@ -23,24 +23,24 @@ object RichCharTest1 extends RichTest {
Console.println('A'.asDigit == 10)
}
}
-object RichCharTest2 extends RichTest {
- case class C(s: String) {
- private val it = s.elements
- private var c: Char = _
- def ch(): Char = c
- def nextch(): Unit = { c = if (it.hasNext) it.next else ';' }
- def err(msg: String) = Console.println(msg)
- nextch()
- }
- def run {
- Console.println("\n" + getObjectName + ":")
- val c1 = C("x4A;")
- val s1 = xml.Utility.parseCharRef(c1.ch, c1.nextch, c1.err)
- val c2 = C("74;")
- val s2 = xml.Utility.parseCharRef(c2.ch, c2.nextch, c2.err)
- Console.println(s1 == s2)
- }
-}
+// object RichCharTest2 extends RichTest {
+// case class C(s: String) {
+// private val it = s.elements
+// private var c: Char = _
+// def ch(): Char = c
+// def nextch(): Unit = { c = if (it.hasNext) it.next else ';' }
+// def err(msg: String) = Console.println(msg)
+// nextch()
+// }
+// def run {
+// Console.println("\n" + getObjectName + ":")
+// val c1 = C("x4A;")
+// val s1 = xml.Utility.parseCharRef(c1.ch, c1.nextch, c1.err)
+// val c2 = C("74;")
+// val s2 = xml.Utility.parseCharRef(c2.ch, c2.nextch, c2.err)
+// Console.println(s1 == s2)
+// }
+// }
object RichIntTest extends RichTest {
private val n = 10
private val m = -2
@@ -107,7 +107,7 @@ object RichStringTest5 extends RichTest {
object Test {
def main(args: Array[String]): Unit = {
RichCharTest1.run
- RichCharTest2.run
+ //RichCharTest2.run
RichIntTest.run
RichStringTest1.run
RichStringTest2.run
diff --git a/test/files/run/try.scala b/test/files/run/try.scala
index fca6bf5c55..934ebaa2e7 100644
--- a/test/files/run/try.scala
+++ b/test/files/run/try.scala
@@ -43,12 +43,12 @@ object Test extends AnyRef with Application {
def try4 = {
if (instance == null) {
instance = try {
- new String();
+ "" //new String();
} catch {
case _ =>
val cs = "aaa";
if (cs.length() > 0) {
- new String();
+ "" //new String();
} else {
throw new Error("fatal error");
null
diff --git a/test/scalatest b/test/scalatest
index a9dc13cc79..283cd5a56e 100755
--- a/test/scalatest
+++ b/test/scalatest
@@ -687,9 +687,9 @@ fi;
SCALA="${BIN_DIR}scala";
if [ "$USEFSC" = "true" ]; then
- SCALAC="${BIN_DIR}fsc -deprecation -encoding iso-8859-1";
+ SCALAC="${BIN_DIR}fsc -nowarn -deprecation -encoding iso-8859-1";
else
- SCALAC="${BIN_DIR}scalac -deprecation -encoding iso-8859-1";
+ SCALAC="${BIN_DIR}scalac -nowarn -deprecation -encoding iso-8859-1";
fi;
SCALAP="scalap";
ANT="ant";