Fix missing class initialization during instrumentation.

Static methods (except the <clinit>) all point to the resolution trampoline
to handle class initialization. When we enable instrumentation, we update the
entry point to the instrumentation stub. But doing so makes us miss the call
into the trampoline.

This CL fixes this issue by leaving the resolution trampoline. Once a method's
class is initialized, we update all its static methods' entry point. When
instrumentation is enabled, this entry point becomes the instrumentation entry
stub.

This also allows to post method enter events in the right order during static
invokes. First, we get into the trampoline which call the method's class
<clinit> method and post the corresponding "method enter" event. Then we get
into the instrumentation entry stub of the static method being called and post
the corresponding "method enter" event before getting into its code.

Bug: 11686442
Change-Id: I202db921225c8be0b2191074d09b0ba40f9248b2
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 0f4fa4e..77ed7b8 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -44,6 +44,8 @@
 
 namespace instrumentation {
 
+const bool kVerboseInstrumentation = false;
+
 // Do we want to deoptimize for method entry and exit listeners or just try to intercept
 // invocations? Deoptimization forces all code to run in the interpreter and considerably hurts the
 // application's performance.
@@ -57,10 +59,7 @@
 
 bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
   bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
-  ClassLinker* class_linker = NULL;
-  if (uninstall) {
-    class_linker = Runtime::Current()->GetClassLinker();
-  }
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   bool is_initialized = klass->IsInitialized();
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     mirror::ArtMethod* method = klass->GetDirectMethod(i);
@@ -76,7 +75,14 @@
         }
       } else {  // !uninstall
         if (!interpreter_stubs_installed_ || method->IsNative()) {
-          new_code = GetQuickInstrumentationEntryPoint();
+          // Do not overwrite resolution trampoline. When the trampoline initializes the method's
+          // class, all its static methods' code will be set to the instrumentation entry point.
+          // For more details, see ClassLinker::FixupStaticTrampolines.
+          if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
+            new_code = GetQuickInstrumentationEntryPoint();
+          } else {
+            new_code = GetResolutionTrampoline(class_linker);
+          }
         } else {
           new_code = GetCompiledCodeToInterpreterBridge();
         }
@@ -448,7 +454,14 @@
     method->SetEntryPointFromCompiledCode(code);
   } else {
     if (!interpreter_stubs_installed_ || method->IsNative()) {
-      method->SetEntryPointFromCompiledCode(GetQuickInstrumentationEntryPoint());
+      // Do not overwrite resolution trampoline. When the trampoline initializes the method's
+      // class, all its static methods' code will be set to the instrumentation entry point.
+      // For more details, see ClassLinker::FixupStaticTrampolines.
+      if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
+        method->SetEntryPointFromCompiledCode(code);
+      } else {
+        method->SetEntryPointFromCompiledCode(GetQuickInstrumentationEntryPoint());
+      }
     } else {
       method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge());
     }
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 25a4eec..5647c0e 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -36,8 +36,6 @@
 
 namespace instrumentation {
 
-const bool kVerboseInstrumentation = false;
-
 // Interpreter handler tables.
 enum InterpreterHandlerTable {
   kMainHandlerTable = 0,          // Main handler table: no suspend check, no instrumentation.