From 36ef60e68c03bc1c7fd2e910ae7d70d4ec32d3bf Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 16 Jan 2010 03:54:39 +0000 Subject: Exposed native Array clone() method. Review by dragos. --- .../scala/tools/nsc/backend/icode/GenICode.scala | 27 ++++++++++++++-------- .../scala/tools/nsc/backend/icode/Opcodes.scala | 17 ++++++++------ .../scala/tools/nsc/backend/jvm/GenJVM.scala | 6 +++++ .../scala/tools/nsc/symtab/Definitions.scala | 2 ++ .../scala/tools/nsc/transform/CleanUp.scala | 4 +++- .../scala/tools/nsc/transform/Erasure.scala | 11 --------- 6 files changed, 39 insertions(+), 28 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2f66f672d8..7f351293c5 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -730,16 +730,25 @@ abstract class GenICode extends SubComponent { else ctx ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1) - - val hostClass = fun match { - case Select(qualifier, _) - if (qualifier.tpe.typeSymbol != ArrayClass) => - qualifier.tpe.typeSymbol - case _ => sym.owner + val cm = CALL_METHOD(sym, invokeStyle) + + /** In a couple cases, squirrel away a little extra information in the + * CALL_METHOD for use by GenJVM. + */ + fun match { + case Select(qual, _) => + val qualSym = qual.tpe.typeSymbol + if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe) + else cm setHostClass qualSym + + if (settings.debug.value) log( + if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullNameString + else "Set more precise host class for " + sym.fullNameString + " host: " + qualSym + ) + case _ => } - if (settings.debug.value && hostClass != sym.owner) - log("Set more precise host class for " + sym.fullNameString + " host: " + hostClass); - ctx1.bb.emit(CALL_METHOD(sym, invokeStyle) setHostClass hostClass, tree.pos) + ctx1.bb.emit(cm, tree.pos) + if (sym == ctx1.method.symbol) { ctx1.method.recursive = true } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 9785279e80..f7baab286b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -325,17 +325,20 @@ trait Opcodes { self: ICodes => var hostClass: Symbol = method.owner; def setHostClass(cls: Symbol): this.type = { hostClass = cls; this } - override def consumed = { - var result = method.tpe.paramTypes.length; - result = result + (style match { + /** This is specifically for preserving the target native Array type long + * enough that clone() can generate the right call. + */ + var targetTypeKind: TypeKind = UNIT // the default should never be used, so UNIT should fail fast. + def setTargetTypeKind(tk: TypeKind) = targetTypeKind = tk + + override def consumed = method.tpe.paramTypes.length + ( + style match { case Dynamic | InvokeDynamic => 1 case Static(true) => 1 case Static(false) => 0 case SuperCall(_) => 1 - }); - - result; - } + } + ) override def consumedTypes = { val args = method.tpe.paramTypes map toTypeKind diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index d622edc8ab..7496107798 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -82,6 +82,7 @@ abstract class GenJVM extends SubComponent { val StringBuilderType = new JObjectType(StringBuilderClass) val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY) + val arrayCloneType = new JMethodType(JObjectType.JAVA_LANG_OBJECT, JType.EMPTY_ARRAY) val MethodTypeType = new JObjectType("java.dyn.MethodType") val JavaLangClassType = new JObjectType("java.lang.Class") val MethodHandleType = new JObjectType("java.dyn.MethodHandle") @@ -1087,6 +1088,11 @@ abstract class GenJVM extends SubComponent { case CALL_PRIMITIVE(primitive) => genPrimitive(primitive, instr.pos) + /** Special handling to access native Array.clone() */ + case call @ CALL_METHOD(definitions.Array_clone, Dynamic) => + val target: String = javaType(call.targetTypeKind).getSignature() + jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType) + case call @ CALL_METHOD(method, style) => val owner: String = javaName(method.owner) // reference the type of the receiver instead of the method owner (if not an interface!) diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index e14a7d796c..155f5332d8 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -154,6 +154,7 @@ trait Definitions { def arrayApplyMethod = getMember(ScalaRunTimeModule, "array_apply") def arrayUpdateMethod = getMember(ScalaRunTimeModule, "array_update") def arrayLengthMethod = getMember(ScalaRunTimeModule, "array_length") + def arrayCloneMethod = getMember(ScalaRunTimeModule, "array_clone") // classes with special meanings lazy val NotNullClass = getClass("scala.NotNull") @@ -215,6 +216,7 @@ trait Definitions { def Array_apply = getMember(ArrayClass, nme.apply) def Array_update = getMember(ArrayClass, nme.update) def Array_length = getMember(ArrayClass, nme.length) + lazy val Array_clone = getMember(ArrayClass, nme.clone_) lazy val ArrayModule = getModule("scala.Array") def ArrayModule_apply = getMember(ArrayModule, nme.apply) diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index c508400711..81fe911328 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -365,7 +365,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { def isArrayMethodSignature = (methSym.name == nme.length && params.isEmpty) || (methSym.name == nme.update && (structResType.typeSymbol eq UnitClass)) || - (methSym.name == nme.apply && params.size == 1) + (methSym.name == nme.apply && params.size == 1) || + (methSym.name == nme.clone_ && params.isEmpty) def isDefinitelyArray = isArrayMethodSignature && (qualSym == ArrayClass) def isMaybeArray = isArrayMethodSignature && (qualSym == ObjectClass) // precondition: !isDefinitelyArray @@ -374,6 +375,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case nme.length => REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args) case nme.update => REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2)) case nme.apply => REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1))) + case nme.clone_ => REF(arrayCloneMethod) APPLY List(args(0)) } def genArrayTest = { def oneTest(s: Symbol) = qual IS_OBJ arrayType(s.tpe) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index e92ba64469..7722939aaf 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -477,17 +477,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. private def cast(tree: Tree, pt: Type): Tree = tree AS_ATTR pt - /** Is symbol a member of unboxed arrays (which will be expanded directly - * later)? - * - * @param sym .. - * @return true if .. - */ - private def isUnboxedArrayMember(sym: Symbol) = sym.name match { - case nme.apply | nme.length | nme.update => true - case _ => sym.owner == ObjectClass - } - private def isUnboxedValueMember(sym: Symbol) = sym != NoSymbol && isValueClass(sym.owner) -- cgit v1.2.3