summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-01-16 03:54:39 +0000
committerPaul Phillips <paulp@improving.org>2010-01-16 03:54:39 +0000
commit36ef60e68c03bc1c7fd2e910ae7d70d4ec32d3bf (patch)
treed663145af9c6e9f02bed79fbcd83549234c8727c /src/compiler
parent74c615c83567c930ce371833ff4b275312a4540f (diff)
downloadscala-36ef60e68c03bc1c7fd2e910ae7d70d4ec32d3bf.tar.gz
scala-36ef60e68c03bc1c7fd2e910ae7d70d4ec32d3bf.tar.bz2
scala-36ef60e68c03bc1c7fd2e910ae7d70d4ec32d3bf.zip
Exposed native Array clone() method.
Review by dragos.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala27
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala17
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala11
6 files changed, 39 insertions, 28 deletions
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 <code>true</code> 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)