Implement invokesuper in optimizing.
- Ensure dex2oat is in PIC mode, as this will drive the decisions
made in the compiler driver, and optimizing only suppots PIC
anyway.
- Since invokesuper is sharpened into invoke-direct, also support
sharpening of invokeinterface and invokevirtual.
Change-Id: I0a1bd79a13dc1c9e67e3cb11d38f0cd4459968ae
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 16b491d..76a2be9 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -374,13 +374,12 @@
const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
HInvoke* invoke = nullptr;
- if (invoke_type == kVirtual || invoke_type == kInterface) {
+ if (invoke_type == kVirtual || invoke_type == kInterface || invoke_type == kSuper) {
MethodReference target_method(dex_file_, method_idx);
uintptr_t direct_code;
uintptr_t direct_method;
int table_index;
InvokeType optimized_invoke_type = invoke_type;
- // TODO: Add devirtualization support.
compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_offset, true, true,
&optimized_invoke_type, &target_method, &table_index,
&direct_code, &direct_method);
@@ -388,15 +387,21 @@
return false;
}
- if (invoke_type == kVirtual) {
+ if (optimized_invoke_type == kVirtual) {
invoke = new (arena_) HInvokeVirtual(
arena_, number_of_arguments, return_type, dex_offset, table_index);
- } else {
- DCHECK_EQ(invoke_type, kInterface);
+ } else if (optimized_invoke_type == kInterface) {
invoke = new (arena_) HInvokeInterface(
arena_, number_of_arguments, return_type, dex_offset, method_idx, table_index);
+ } else if (optimized_invoke_type == kDirect) {
+ // For this compiler, sharpening only works if we compile PIC.
+ DCHECK(compiler_driver_->GetCompilerOptions().GetCompilePic());
+ // Treat invoke-direct like static calls for now.
+ invoke = new (arena_) HInvokeStatic(
+ arena_, number_of_arguments, return_type, dex_offset, target_method.dex_method_index);
}
} else {
+ DCHECK(invoke_type == kDirect || invoke_type == kStatic);
// Treat invoke-direct like static calls for now.
invoke = new (arena_) HInvokeStatic(
arena_, number_of_arguments, return_type, dex_offset, method_idx);
@@ -890,10 +895,11 @@
break;
}
- case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_DIRECT:
- case Instruction::INVOKE_VIRTUAL:
- case Instruction::INVOKE_INTERFACE: {
+ case Instruction::INVOKE_INTERFACE:
+ case Instruction::INVOKE_STATIC:
+ case Instruction::INVOKE_SUPER:
+ case Instruction::INVOKE_VIRTUAL: {
uint32_t method_idx = instruction.VRegB_35c();
uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
uint32_t args[5];
@@ -905,10 +911,11 @@
break;
}
- case Instruction::INVOKE_STATIC_RANGE:
case Instruction::INVOKE_DIRECT_RANGE:
- case Instruction::INVOKE_VIRTUAL_RANGE:
- case Instruction::INVOKE_INTERFACE_RANGE: {
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ case Instruction::INVOKE_STATIC_RANGE:
+ case Instruction::INVOKE_SUPER_RANGE:
+ case Instruction::INVOKE_VIRTUAL_RANGE: {
uint32_t method_idx = instruction.VRegB_3rc();
uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
uint32_t register_index = instruction.VRegC();
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d87faeb..4951b1f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -583,6 +583,7 @@
compiler_kind_ = Compiler::kQuick;
} else if (backend_str == "Optimizing") {
compiler_kind_ = Compiler::kOptimizing;
+ compile_pic = true;
} else if (backend_str == "Portable") {
compiler_kind_ = Compiler::kPortable;
} else {
diff --git a/test/425-invoke-super/expected.txt b/test/425-invoke-super/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/425-invoke-super/expected.txt
diff --git a/test/425-invoke-super/info.txt b/test/425-invoke-super/info.txt
new file mode 100644
index 0000000..ad99030
--- /dev/null
+++ b/test/425-invoke-super/info.txt
@@ -0,0 +1 @@
+Tests the invoke-super opcode.
diff --git a/test/425-invoke-super/smali/invokesuper.smali b/test/425-invoke-super/smali/invokesuper.smali
new file mode 100644
index 0000000..ab13091
--- /dev/null
+++ b/test/425-invoke-super/smali/invokesuper.smali
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+.class public LInvokeSuper;
+.super LSuperClass;
+
+.method public constructor <init>()V
+.registers 1
+ invoke-direct {v0}, LSuperClass;-><init>()V
+ return-void
+.end method
+
+
+.method public run()I
+.registers 2
+ # Do an invoke super on a non-super class to force slow path.
+ invoke-super {v1}, LInvokeSuper;->returnInt()I
+ move-result v0
+ return v0
+.end method
+
+
+.method public returnInt()I
+.registers 2
+ const v0, 777
+ return v0
+.end method
diff --git a/test/425-invoke-super/smali/subclass.smali b/test/425-invoke-super/smali/subclass.smali
new file mode 100644
index 0000000..54e3474
--- /dev/null
+++ b/test/425-invoke-super/smali/subclass.smali
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LSubClass;
+.super LInvokeSuper;
+
+.method public constructor <init>()V
+.registers 1
+ invoke-direct {v0}, LInvokeSuper;-><init>()V
+ return-void
+.end method
+
+.method public returnInt()I
+.registers 2
+ const v0, 0
+ return v0
+.end method
diff --git a/test/425-invoke-super/smali/superclass.smali b/test/425-invoke-super/smali/superclass.smali
new file mode 100644
index 0000000..b366aa7
--- /dev/null
+++ b/test/425-invoke-super/smali/superclass.smali
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LSuperClass;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+ invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method public returnInt()I
+.registers 2
+ const v0, 42
+ return v0
+.end method
diff --git a/test/425-invoke-super/src/Main.java b/test/425-invoke-super/src/Main.java
new file mode 100644
index 0000000..1fb62d0
--- /dev/null
+++ b/test/425-invoke-super/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ static class A {
+ public int foo() { return 1; }
+ }
+
+ static class B extends A {
+ public int $opt$bar() { return super.foo(); }
+ }
+
+ static class C extends B {
+ public int foo() { return 42; }
+ }
+
+ static class D extends C {
+ }
+
+ static void assertEquals(int expected, int value) {
+ if (expected != value) {
+ throw new Error("Expected " + expected + ", got " + value);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ assertEquals(1, new B().$opt$bar());
+ assertEquals(1, new C().$opt$bar());
+ assertEquals(1, new D().$opt$bar());
+
+ Class<?> c = Class.forName("InvokeSuper");
+ Method m = c.getMethod("run");
+ assertEquals(42, ((Integer)m.invoke(c.newInstance(), new Object[0])).intValue());
+
+ c = Class.forName("SubClass");
+ assertEquals(42, ((Integer)m.invoke(c.newInstance(), new Object[0])).intValue());
+ }
+}