summaryrefslogtreecommitdiff
path: root/test/junit
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-03-12 15:32:46 -0700
committerLukas Rytz <lukas.rytz@gmail.com>2015-03-12 16:34:21 -0700
commitc2ab768287cc02b5e01342ac993d6c2b6e7ee2aa (patch)
tree8f6eb1d2132585be7f869b488e195149b03bd461 /test/junit
parentba325127141e70e3464be80fddc699e23b638a3d (diff)
downloadscala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.tar.gz
scala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.tar.bz2
scala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.zip
Don't inline methods containing super calls into other classes
Method bodies that contain a super call cannot be inlined into other classes. The same goes for methods containing calls to private methods, but that was already ensured before by accessibility checks. The last case of `invokespecial` instructions is constructor calls. Those can be safely moved into different classes (as long as the constructor is accessible at the new location). Note that scalac never emits methods / constructors as private in bytecode.
Diffstat (limited to 'test/junit')
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala26
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala48
2 files changed, 61 insertions, 13 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
index 03d2f2f108..b4839dcec8 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala
@@ -59,7 +59,7 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
def check(classNode: ClassNode, test: Option[AbstractInsnNode] => Unit) = {
for (m <- methods)
- test(inliner.findIllegalAccess(m.instructions, classBTypeFromParsedClassfile(classNode.name)).map(_._1))
+ test(inliner.findIllegalAccess(m.instructions, classBTypeFromParsedClassfile(cClass.name), classBTypeFromParsedClassfile(classNode.name)).map(_._1))
}
check(cClass, assertEmpty)
@@ -152,8 +152,8 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
val List(rbD, rcD, rfD, rgD) = dCl.methods.asScala.toList.filter(_.name(0) == 'r').sortBy(_.name)
- def check(method: MethodNode, dest: ClassNode, test: Option[AbstractInsnNode] => Unit): Unit = {
- test(inliner.findIllegalAccess(method.instructions, classBTypeFromParsedClassfile(dest.name)).map(_._1))
+ def check(method: MethodNode, decl: ClassNode, dest: ClassNode, test: Option[AbstractInsnNode] => Unit): Unit = {
+ test(inliner.findIllegalAccess(method.instructions, classBTypeFromParsedClassfile(decl.name), classBTypeFromParsedClassfile(dest.name)).map(_._1))
}
val cOrDOwner = (_: Option[AbstractInsnNode] @unchecked) match {
@@ -164,35 +164,35 @@ class InlinerIllegalAccessTest extends ClearAfterClass {
// PUBLIC
// public methods allowed everywhere
- for (m <- Set(raC, reC); c <- allClasses) check(m, c, assertEmpty)
+ for (m <- Set(raC, reC); c <- allClasses) check(m, cCl, c, assertEmpty)
// DEFAULT ACCESS
// default access OK in same package
- for (m <- Set(rbC, rfC, rbD, rfD); c <- allClasses) {
- if (c.name startsWith "a/") check(m, c, assertEmpty)
- else check(m, c, cOrDOwner)
+ for ((m, declCls) <- Set((rbC, cCl), (rfC, cCl), (rbD, dCl), (rfD, dCl)); c <- allClasses) {
+ if (c.name startsWith "a/") check(m, declCls, c, assertEmpty)
+ else check(m, declCls, c, cOrDOwner)
}
// PROTECTED
// protected accessed in same class, or protected static accessed in subclass(rgD).
// can be inlined to subclasses, and classes in the same package (gCl)
- for (m <- Set(rcC, rgC, rgD); c <- Set(cCl, dCl, eCl, fCl, gCl, hCl)) check(m, c, assertEmpty)
+ for ((m, declCls) <- Set((rcC, cCl), (rgC, cCl), (rgD, dCl)); c <- Set(cCl, dCl, eCl, fCl, gCl, hCl)) check(m, declCls, c, assertEmpty)
// protected in non-subclass and different package
- for (m <- Set(rcC, rgC)) check(m, iCl, cOrDOwner)
+ for (m <- Set(rcC, rgC)) check(m, cCl, iCl, cOrDOwner)
// non-static protected accessed in subclass (rcD). can be inlined to related class, or classes in the same package
- for (c <- Set(cCl, dCl, eCl, fCl, gCl)) check(rcD, c, assertEmpty)
+ for (c <- Set(cCl, dCl, eCl, fCl, gCl)) check(rcD, dCl, c, assertEmpty)
// rcD cannot be inlined into non-related classes, if the declaration and destination are not in the same package
- for (c <- Set(hCl, iCl)) check(rcD, c, cOrDOwner)
+ for (c <- Set(hCl, iCl)) check(rcD, dCl, c, cOrDOwner)
// PRIVATE
// privated method accesses can only be inlined in the same class
- for (m <- Set(rdC, rhC)) check(m, cCl, assertEmpty)
- for (m <- Set(rdC, rhC); c <- allClasses.tail) check(m, c, cOrDOwner)
+ for (m <- Set(rdC, rhC)) check(m, cCl, cCl, assertEmpty)
+ for (m <- Set(rdC, rhC); c <- allClasses.tail) check(m, cCl, c, cOrDOwner)
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 0581bd24fe..39fb28570e 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -902,4 +902,52 @@ class InlinerTest extends ClearAfterClass {
allowMessage = i => {c += 1; i.msg contains warn})
assert(c == 1, c)
}
+
+ @Test
+ def inlineInvokeSpecial(): Unit = {
+ val code =
+ """class Aa {
+ | def f1 = 0
+ |}
+ |class B extends Aa {
+ | @inline final override def f1 = 1 + super.f1 // invokespecial Aa.f1
+ |
+ | private def f2m = 0 // public B$$f2m in bytecode
+ | @inline final def f2 = f2m // invokevirtual B.B$$f2m
+ |
+ | private def this(x: Int) = this() // public in bytecode
+ | @inline final def f3 = new B() // invokespecial B.<init>()
+ | @inline final def f4 = new B(1) // invokespecial B.<init>(I)
+ |
+ | def t1 = f1 // inlined
+ | def t2 = f2 // inlined
+ | def t3 = f3 // inlined
+ | def t4 = f4 // inlined
+ |}
+ |class T {
+ | def t1(b: B) = b.f1 // cannot inline: contains a super call
+ | def t2(b: B) = b.f2 // inlined
+ | def t3(b: B) = b.f3 // inlined
+ | def t4(b: B) = b.f4 // inlined
+ |}
+ """.stripMargin
+
+ val warn =
+ """B::f1()I is annotated @inline but could not be inlined:
+ |The callee B::f1()I contains the instruction INVOKESPECIAL Aa.f1 ()I
+ |that would cause an IllegalAccessError when inlined into class T.""".stripMargin
+ var c = 0
+ val List(a, b, t) = compile(code, allowMessage = i => {c += 1; i.msg contains warn})
+ assert(c == 1, c)
+
+ assertInvoke(getSingleMethod(b, "t1"), "Aa", "f1")
+ assertInvoke(getSingleMethod(b, "t2"), "B", "B$$f2m")
+ assertInvoke(getSingleMethod(b, "t3"), "B", "<init>")
+ assertInvoke(getSingleMethod(b, "t4"), "B", "<init>")
+
+ assertInvoke(getSingleMethod(t, "t1"), "B", "f1")
+ assertInvoke(getSingleMethod(t, "t2"), "B", "B$$f2m")
+ assertInvoke(getSingleMethod(t, "t3"), "B", "<init>")
+ assertInvoke(getSingleMethod(t, "t4"), "B", "<init>")
+ }
}