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());
+  }
+}