diff options
author | Miguel Garcia <magarcia@epfl.ch> | 2010-08-13 13:49:28 +0000 |
---|---|---|
committer | Miguel Garcia <magarcia@epfl.ch> | 2010-08-13 13:49:28 +0000 |
commit | 29f9d75674205eb8f3db63829eeb1ff7d781694c (patch) | |
tree | c656f19edef3fc3224c78a755ba15183934bc80b /src/compiler | |
parent | 4b9de7deb27682100e09e0b55780f029754e0b7e (diff) | |
download | scala-29f9d75674205eb8f3db63829eeb1ff7d781694c.tar.gz scala-29f9d75674205eb8f3db63829eeb1ff7d781694c.tar.bz2 scala-29f9d75674205eb8f3db63829eeb1ff7d781694c.zip |
for MSIL: Previous changesets were applied more...
for MSIL: Previous changesets were applied more-or-less incrementally to
scala-msil, this changeset brings them all together to scala trunk. Next
stop will be supporting CLR valuetypes (another big one). Afterwards
(once emitted .NET bytecode passes peverify) changesets will become more
manageable in size. Well, no, there's generics coming. But believe me,
soon MSIL changesets will get smaller in size.
Diffstat (limited to 'src/compiler')
5 files changed, 181 insertions, 54 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 174a1b778e..2bdf8a3a73 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -286,7 +286,7 @@ abstract class GenMSIL extends SubComponent { symtab(i) = (size & 0xff).toByte size = size >> 8 } - System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) + java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) @@ -461,7 +461,8 @@ abstract class GenMSIL extends SubComponent { if (settings.debug.value) log("Output path: " + filename) try { - massembly.Save(filename, srcPath.getPath()) + massembly.Save(filename + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */ + // massembly.Save(filename, srcPath.getPath()) /* use MultipleFilesILPrinterVisitor */ } catch { case e:IOException => abort("Could not write to " + filename + ": " + e.getMessage()) } @@ -545,10 +546,10 @@ abstract class GenMSIL extends SubComponent { 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 = " + + java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) + java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) + java.lang.System.out.println("mBuilder = " + mBuilder) + java.lang.System.out.println("mBuilder.DeclaringType = " + TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + "::" + mBuilder.DeclaringType) throw e @@ -947,7 +948,45 @@ abstract class GenMSIL extends SubComponent { fields(field) = fInfo fInfo } + if (!fieldInfo.IsLiteral) { mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) + } else { + /* We perform `field inlining' as required by CLR. + * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available + * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type + * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case, + * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */ + val value = fieldInfo.getValue() + if (value == null) { + mcode.Emit(OpCodes.Ldnull) + } else { + val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType + else fieldInfo.FieldType + if (typ == clrTypes.STRING) { + mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String]) + } else if (typ == clrTypes.BOOLEAN) { + mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1 + else OpCodes.Ldc_I4_0) + } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) { + loadI4(value.asInstanceOf[Byte], mcode) + } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) { + loadI4(value.asInstanceOf[Int], mcode) + } else if (typ == clrTypes.CHAR) { + loadI4(value.asInstanceOf[Char], mcode) + } else if (typ == clrTypes.INT || typ == clrTypes.UINT) { + loadI4(value.asInstanceOf[Int], mcode) + } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) { + mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long]) + } else if (typ == clrTypes.FLOAT) { + mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float]) + } else if (typ == clrTypes.DOUBLE) { + mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Double]) + } else { + /* TODO one more case is described in Partition II, 16.2: bytearray(...) */ + abort("Unknown type for static literal field: " + fieldInfo) + } + } + } case LOAD_MODULE(module) => if (settings.debug.value) @@ -1113,13 +1152,13 @@ abstract class GenMSIL extends SubComponent { case MethodType(_, retType) => retType case _ => abort("not a method type: " + msym.tpe) } - val method: MethodInfo = getMethod(methodSym) + val methodInfo: MethodInfo = getMethod(methodSym) val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) if (methodSym.isStatic) { - mcode.Emit(OpCodes.Ldftn, method) + mcode.Emit(OpCodes.Ldftn, methodInfo) } else { mcode.Emit(OpCodes.Dup) - mcode.Emit(OpCodes.Ldvirtftn, method) + mcode.Emit(OpCodes.Ldvirtftn, methodInfo) } mcode.Emit(OpCodes.Newobj, delegCtor) } @@ -1130,13 +1169,20 @@ abstract class GenMSIL extends SubComponent { case SuperCall(_) => mcode.Emit(OpCodes.Call, methodInfo) case Dynamic => - mcode.Emit(if (dynToStatMapped(msym)) OpCodes.Call else OpCodes.Callvirt, - methodInfo) - case Static(_) => + if (dynToStatMapped(msym)) { mcode.Emit(OpCodes.Call, methodInfo) + } else if ((methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType)) { + mcode.Emit(OpCodes.Call, methodInfo) + } else { + mcode.Emit(OpCodes.Callvirt, methodInfo) } + case Static(_) => + if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) { + mcode.Emit(OpCodes.Callvirt, methodInfo) + } else mcode.Emit(OpCodes.Call, methodInfo) } } + } case BOX(boxType) => emitBox(mcode, boxType) @@ -1253,7 +1299,7 @@ abstract class GenMSIL extends SubComponent { } } // end for (instr <- b) { .. } - } + } // end genBlock def genPrimitive(primitive: Primitive, pos: Position) { primitive match { @@ -1329,7 +1375,7 @@ abstract class GenMSIL extends SubComponent { case _ => abort("Unimplemented primitive " + primitive) } - } + } // end genPrimitive ////////////////////// loading /////////////////////// @@ -1379,8 +1425,8 @@ abstract class GenMSIL extends SubComponent { ////////////////////// branches /////////////////////// /** Returns a Triple (Boolean, Boolean, Option[Label]) - * - wether the jump leaves some exception block (try / catch / finally) - * - wether the it leaves a finally handler (finally block, but not it's try / catch) + * - whether the jump leaves some exception block (try / catch / finally) + * - whether it leaves a finally handler (finally block, but not it's try / catch) * - a label where to jump for leaving the finally handler * . None to leave directly using `endfinally` * . Some(label) to emit `leave label` (for try / catch inside a finally handler) @@ -1485,11 +1531,9 @@ abstract class GenMSIL extends SubComponent { * method. */ def computeLocalVarsIndex(m: IMethod) { - val params = m.params - var idx = 1 - if (m.symbol.isStaticMember) - idx = 0 + var idx = if (m.symbol.isStaticMember) 0 else 1 + val params = m.params for (l <- params) { if (settings.debug.value) log("Index value for parameter " + l + ": " + idx) @@ -1670,7 +1714,7 @@ abstract class GenMSIL extends SubComponent { msilType(elem) match { // For type builders, cannot call "clrTypes.mkArrayType" because this looks up // the type "tp" in the assembly (not in the HashMap "types" of the backend). - // This can fail for nested types because the biulders are not complete yet. + // This can fail for nested types because the builders are not complete yet. case tb: TypeBuilder => tb.MakeArrayType() case tp: MsilType => clrTypes.mkArrayType(tp) } @@ -1685,7 +1729,7 @@ abstract class GenMSIL extends SubComponent { def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym))) /** - * Get an MSIL type form a symbol. First look in the clrTypes.types map, then + * Get an MSIL type from a symbol. First look in the clrTypes.types map, then * lookup the name using clrTypes.getType */ def getTypeOpt(sym: Symbol): Option[MsilType] = types.get(sym) match { @@ -1713,31 +1757,40 @@ abstract class GenMSIL extends SubComponent { def createTypeBuilder(iclass: IClass) { /** - * First look in the clrTypes.types map, then see if it's a class we're - * currently compiling by looking at the icodes.classes map, then finally - * lookup the name using clrTypes.getType (by calling getType). + * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise + * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)). */ def msilTypeFromSym(sym: Symbol): MsilType = { types.get(sym).getOrElse { classes.get(sym) match { case Some(iclass) => - createTypeBuilder(iclass) - types (sym) + msilTypeBuilderFromSym(sym) case None => getType(sym) } } } + def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = { + if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){ + val iclass = classes(sym) + assert(iclass != null) + createTypeBuilder(iclass) + } + types(sym).asInstanceOf[TypeBuilder] + } + val sym = iclass.symbol - if (types contains sym) return + if (types contains sym) + if (types(sym).isInstanceOf[TypeBuilder]) + return def isInterface(s: Symbol) = s.isTrait && !s.isImplClass val parents: List[Type] = if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe) else sym.info.parents.distinct - val superType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) + val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) if (settings.debug.value) log("super type: " + parents(0).typeSymbol + ", msil type: " + superType) @@ -1752,16 +1805,13 @@ abstract class GenMSIL extends SubComponent { } } - if (sym.isNestedClass) { - val ownerT = msilTypeFromSym(sym.owner).asInstanceOf[TypeBuilder] - val tBuilder = - ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) - mapType(sym, tBuilder) + val tBuilder = if (sym.isNestedClass) { + val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder] + ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) } else { - val tBuilder = - mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) - mapType(sym, tBuilder) + mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) } + mapType(sym, tBuilder) } // createTypeBuilder def createClassMembers(iclass: IClass) { @@ -1770,8 +1820,8 @@ abstract class GenMSIL extends SubComponent { } catch { case e: Throwable => - System.err.println(showsym(iclass.symbol)) - System.err.println("with methods = " + iclass.methods) + java.lang.System.err.println(showsym(iclass.symbol)) + java.lang.System.err.println("with methods = " + iclass.methods) throw e } } @@ -1789,7 +1839,7 @@ abstract class GenMSIL extends SubComponent { addAttributes(fBuilder, sym.annotations) } - if (iclass.symbol != definitions.ArrayClass) + if (iclass.symbol != definitions.ArrayClass) { for (m: IMethod <- iclass.methods) { val sym = m.symbol if (settings.debug.value) @@ -1823,6 +1873,7 @@ abstract class GenMSIL extends SubComponent { log("\t created MethodBuilder " + method) } } + } // method builders created for non-array iclass if (isStaticModule(iclass.symbol)) { addModuleInstanceField(iclass.symbol) @@ -1830,7 +1881,7 @@ abstract class GenMSIL extends SubComponent { addStaticInit(iclass.symbol) } - } // createClassMembers + } // createClassMembers0 private def isTopLevelModule(sym: Symbol): Boolean = atPhase (currentRun.refchecksPhase) { @@ -2063,8 +2114,8 @@ abstract class GenMSIL extends SubComponent { 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) + java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name) + java.lang.System.out.println("scope = " + sym.owner.tpe.decls) abort(sym.fullName) } else { @@ -2097,8 +2148,8 @@ abstract class GenMSIL extends SubComponent { 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) + java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym)) + java.lang.System.out.println("scope = " + sym.owner.tpe.decls) abort(sym.fullName) } else { diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 198c225e8b..d9e453291f 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -108,8 +108,9 @@ trait Definitions extends reflect.generic.StandardDefinitions { lazy val IndexOutOfBoundsExceptionClass = getClass(sn.IOOBException) lazy val UninitializedErrorClass = getClass("scala.UninitializedFieldError") lazy val MatchErrorClass = getClass("scala.MatchError") + lazy val InvocationTargetExceptionClass = getClass(if (forMSIL) "System.Reflection.TargetInvocationException" + else "java.lang.reflect.InvocationTargetException") // java is hard coded because only used by structural values - lazy val InvocationTargetExceptionClass = getClass("java.lang.reflect.InvocationTargetException") lazy val NoSuchMethodExceptionClass = getClass("java.lang.NoSuchMethodException") // annotations diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 8c4078e91e..aa47441a1a 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -299,14 +299,15 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable => val forName = newTermName(if (forMSIL) "GetType" else "forName") val foreach = newTermName("foreach") val get = newTermName("get") - val getCause = newTermName("getCause") - val getClass_ = newTermName("getClass") - val getMethod_ = newTermName("getMethod") + val getCause = newTermName(if (forMSIL) "InnerException" /* System.Reflection.TargetInvocationException.InnerException */ + else "getCause") + val getClass_ = newTermName(if (forMSIL) "GetType" else "getClass") + val getMethod_ = newTermName(if (forMSIL) "GetMethod" else "getMethod") val hash_ = newTermName("hash") val hashCode_ = newTermName("hashCode") val hasNext = newTermName("hasNext") val head = newTermName("head") - val invoke_ = newTermName("invoke") + val invoke_ = newTermName(if (forMSIL) "Invoke" else "invoke") val isArray = newTermName("isArray") val isInstanceOf_ = newTermName("isInstanceOf") val isDefinedAt = newTermName("isDefinedAt") @@ -496,7 +497,7 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable => final val BoxedNumber = newTermName("System.IConvertible") final val BoxedCharacter = newTermName("System.IConvertible") final val BoxedBoolean = newTermName("System.IConvertible") - final val MethodAsObject = nme.NOSYMBOL // TODO: is there something like Method in MSIL? + final val MethodAsObject = newTermName("System.Reflection.MethodInfo") Boxed += (nme.Boolean -> newTermName("System.Boolean")) Boxed += (nme.Byte -> newTermName("System.Byte")) diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index a90fb8b66c..f661f7bb31 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -335,9 +335,80 @@ abstract class TypeParser { } private def getName(method: MethodBase): Name = { + + def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match { + case 1 => name match { + // PartitionI.10.3.1 + case "op_Decrement" => Some(encode("--")) + case "op_Increment" => Some(encode("++")) + case "op_UnaryNegation" => Some(nme.UNARY_-) + case "op_UnaryPlus" => Some(nme.UNARY_+) + case "op_LogicalNot" => Some(nme.UNARY_!) + case "op_OnesComplement" => Some(nme.UNARY_~) + /* op_True and op_False have no operator symbol assigned, + Other methods that will have to be written in full are: + op_AddressOf & (unary) + op_PointerDereference * (unary) */ + case _ => None + } + case 2 => name match { + // PartitionI.10.3.2 + case "op_Addition" => Some(nme.ADD) + case "op_Subtraction" => Some(nme.SUB) + case "op_Multiply" => Some(nme.MUL) + case "op_Division" => Some(nme.DIV) + case "op_Modulus" => Some(nme.MOD) + case "op_ExclusiveOr" => Some(nme.XOR) + case "op_BitwiseAnd" => Some(nme.AND) + case "op_BitwiseOr" => Some(nme.OR) + case "op_LogicalAnd" => Some(nme.ZAND) + case "op_LogicalOr" => Some(nme.ZOR) + case "op_LeftShift" => Some(nme.LSL) + case "op_RightShift" => Some(nme.ASR) + case "op_Equality" => Some(nme.EQ) + case "op_GreaterThan" => Some(nme.GT) + case "op_LessThan" => Some(nme.LT) + case "op_Inequality" => Some(nme.NE) + case "op_GreaterThanOrEqual" => Some(nme.GE) + case "op_LessThanOrEqual" => Some(nme.LE) + + /* op_MemberSelection is reserved in Scala */ + + /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift , + * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */ + + /* + The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full. + + op_RightShiftAssignment >>= + op_MultiplicationAssignment *= + op_PointerToMemberSelection ->* + op_SubtractionAssignment -= + op_ExclusiveOrAssignment ^= + op_LeftShiftAssignment <<= + op_ModulusAssignment %= + op_AdditionAssignment += + op_BitwiseAndAssignment &= + op_BitwiseOrAssignment |= + op_Comma , + op_DivisionAssignment /= + */ + case _ => None + } + case _ => None + } + if (method.IsConstructor()) return nme.CONSTRUCTOR; val name = method.Name; - if (method.IsStatic()) return newTermName(name); + if (method.IsStatic()) { + if(method.IsSpecialName) { + val paramsArity = method.GetParameters().size + // handle operator overload, otherwise handle as any static method + val operName = operatorOverload(name, paramsArity) + if (operName.isDefined) { return operName.get; } + } + return newTermName(name); + } val params = method.GetParameters(); name match { case "GetHashCode" if (params.length == 0) => nme.hashCode_; @@ -423,7 +494,10 @@ abstract class TypeParser { else if (typ.IsArray()) appliedType(definitions.ArrayClass.tpe, List(getCLRType(typ.GetElementType()))); - else { + else if (typ.isInstanceOf[ConstructedType]) { + val ct = typ.asInstanceOf[ConstructedType] + getCLRType(ct.instantiatedType) + } else { val res = clrTypes.sym2type.get (typ) match { case Some(sym) => sym.tpe case None => getClassType(typ); diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 9b569fa45e..d613124013 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -530,7 +530,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { newStaticInits.clear symbolsStoredAsStatic.clear val transformedTemplate: Template = - if (!forMSIL) { + if (!forMSIL || forMSIL) { var newBody = transformTrees(body) treeCopy.Template(tree, parents, self, transformTrees(newStaticMembers.toList) ::: newBody) |