Force set resolved method for static invokes

For static invokes, we may dispatch to the static method in the
superclass but resolve using the subclass. To prevent getting slow
paths on each invoke, we force set the resolved method for the
super class dex method index if we are in the same dex file.

Added test.

Bug: 19175856
Change-Id: I26f8644a7f725f5c2dc2a94a8e9578f573792507
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 8ab90eb..a67ebca 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -930,6 +930,16 @@
           (caller->GetDexCacheResolvedMethod(update_dex_cache_method_index) != called)) {
         caller->SetDexCacheResolvedMethod(update_dex_cache_method_index, called);
       }
+    } else if (invoke_type == kStatic) {
+      const auto called_dex_method_idx = called->GetDexMethodIndex();
+      // For static invokes, we may dispatch to the static method in the superclass but resolve
+      // using the subclass. To prevent getting slow paths on each invoke, we force set the
+      // resolved method for the super class dex method index if we are in the same dex file.
+      // b/19175856
+      if (called->GetDexFile() == called_method.dex_file &&
+          called_method.dex_method_index != called_dex_method_idx) {
+        called->GetDexCache()->SetResolvedMethod(called_dex_method_idx, called);
+      }
     }
     // Ensure that the called method's class is initialized.
     StackHandleScope<1> hs(soa.Self());
diff --git a/test/133-static-invoke-super/expected.txt b/test/133-static-invoke-super/expected.txt
new file mode 100644
index 0000000..089d8e8
--- /dev/null
+++ b/test/133-static-invoke-super/expected.txt
@@ -0,0 +1,3 @@
+basis: performed 50000000 iterations
+test1: performed 50000000 iterations
+Timing is acceptable.
diff --git a/test/133-static-invoke-super/info.txt b/test/133-static-invoke-super/info.txt
new file mode 100644
index 0000000..606331b
--- /dev/null
+++ b/test/133-static-invoke-super/info.txt
@@ -0,0 +1,2 @@
+This is a performance test of invoking static methods in super class. To see the numbers, invoke
+this test with the "--timing" option.
diff --git a/test/133-static-invoke-super/run b/test/133-static-invoke-super/run
new file mode 100755
index 0000000..e27a622
--- /dev/null
+++ b/test/133-static-invoke-super/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 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.
+
+# As this is a performance test we always use the non-debug build.
+exec ${RUN} "${@/#libartd.so/libart.so}"
diff --git a/test/133-static-invoke-super/src/Main.java b/test/133-static-invoke-super/src/Main.java
new file mode 100644
index 0000000..7cfd099
--- /dev/null
+++ b/test/133-static-invoke-super/src/Main.java
@@ -0,0 +1,63 @@
+
+public class Main {
+    static class SuperClass {
+      protected static int getVar(int w) {
+          return w & 0xF;
+      }
+    }
+    static class SubClass extends SuperClass {
+      final int getVarDirect(int w) {
+        return w & 0xF;
+      }
+      public void testDirect(int max) {
+        for (int i = 0; i < max; ++i) {
+          getVarDirect(max);
+        }
+      }
+      public void testStatic(int max) {
+        for (int i = 0; i < max; ++i) {
+          getVar(max);
+        }
+      }
+    }
+
+    static public void main(String[] args) throws Exception {
+        boolean timing = (args.length >= 1) && args[0].equals("--timing");
+        run(timing);
+    }
+
+    static int testBasis(int interations) {
+      (new SubClass()).testDirect(interations);
+      return interations;
+    }
+
+    static int testStatic(int interations) {
+      (new SubClass()).testStatic(interations);
+      return interations;
+    }
+
+    static public void run(boolean timing) {
+        long time0 = System.nanoTime();
+        int count1 = testBasis(50000000);
+        long time1 = System.nanoTime();
+        int count2 = testStatic(50000000);
+        long time2 = System.nanoTime();
+
+        System.out.println("basis: performed " + count1 + " iterations");
+        System.out.println("test1: performed " + count2 + " iterations");
+
+        double basisMsec = (time1 - time0) / (double) count1 / 1000000;
+        double msec1 = (time2 - time1) / (double) count2 / 1000000;
+
+        if (msec1 < basisMsec * 5) {
+            System.out.println("Timing is acceptable.");
+        } else {
+            System.out.println("Iterations are taking too long!");
+            timing = true;
+        }
+        if (timing) {
+            System.out.printf("basis time: %.3g msec\n", basisMsec);
+            System.out.printf("test1: %.3g msec per iteration\n", msec1);
+        }
+    }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index b1e969d..2057cb9 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -166,7 +166,8 @@
 # Tests that are timing sensitive and flaky on heavily loaded systems.
 TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \
   053-wait-some \
-  055-enum-performance
+  055-enum-performance \
+  133-static-invoke-super
 
  # disable timing sensitive tests on "dist" builds.
 ifdef dist_goal