Improve performance of invokevirtual/invokeinterface with embedded imt/vtable

Add an embedded version of imt/vtable into class object. Both tables start at
fixed offset within class object so method/entry point can be loaded directly
from class object for invokeinterface/invokevirtual.

Bug: 8142917
Change-Id: I4240d58cfbe9250107c95c0708c036854c455968
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c6472c6..371e984 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -63,7 +63,8 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized();
   if (LIKELY(class_linker_initialized)) {
-    if (UNLIKELY(new_status <= old_status && new_status != kStatusError)) {
+    if (UNLIKELY(new_status <= old_status && new_status != kStatusError &&
+                 new_status != kStatusRetired)) {
       LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " "
           << old_status << " -> " << new_status;
     }
@@ -113,11 +114,27 @@
   } else {
     SetField32Volatile<false>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status);
   }
-  // Classes that are being resolved or initialized need to notify waiters that the class status
-  // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
-  if ((old_status >= kStatusResolved || new_status >= kStatusResolved) &&
-      class_linker_initialized) {
-    NotifyAll(self);
+
+  if (!class_linker_initialized) {
+    // When the class linker is being initialized its single threaded and by definition there can be
+    // no waiters. During initialization classes may appear temporary but won't be retired as their
+    // size was statically computed.
+  } else {
+    // Classes that are being resolved or initialized need to notify waiters that the class status
+    // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
+    if (IsTemp()) {
+      // Class is a temporary one, ensure that waiters for resolution get notified of retirement
+      // so that they can grab the new version of the class from the class linker's table.
+      CHECK_LT(new_status, kStatusResolved) << PrettyDescriptor(this);
+      if (new_status == kStatusRetired || new_status == kStatusError) {
+        NotifyAll(self);
+      }
+    } else {
+      CHECK_NE(new_status, kStatusRetired);
+      if (old_status >= kStatusResolved || new_status >= kStatusResolved) {
+        NotifyAll(self);
+      }
+    }
   }
 }
 
@@ -217,35 +234,39 @@
       os << StringPrintf("    %2zd: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl);
     }
   }
-  // After this point, this may have moved due to GetDirectInterface.
-  os << "  vtable (" << h_this->NumVirtualMethods() << " entries, "
-     << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
-  for (size_t i = 0; i < NumVirtualMethods(); ++i) {
-    os << StringPrintf("    %2zd: %s\n", i,
-                       PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str());
-  }
-  os << "  direct methods (" << h_this->NumDirectMethods() << " entries):\n";
-  for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) {
-    os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str());
-  }
-  if (h_this->NumStaticFields() > 0) {
-    os << "  static fields (" << h_this->NumStaticFields() << " entries):\n";
-    if (h_this->IsResolved() || h_this->IsErroneous()) {
-      for (size_t i = 0; i < h_this->NumStaticFields(); ++i) {
-        os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str());
-      }
-    } else {
-      os << "    <not yet available>";
+  if (!IsLoaded()) {
+    os << "  class not yet loaded";
+  } else {
+    // After this point, this may have moved due to GetDirectInterface.
+    os << "  vtable (" << h_this->NumVirtualMethods() << " entries, "
+        << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
+    for (size_t i = 0; i < NumVirtualMethods(); ++i) {
+      os << StringPrintf("    %2zd: %s\n", i,
+                         PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str());
     }
-  }
-  if (h_this->NumInstanceFields() > 0) {
-    os << "  instance fields (" << h_this->NumInstanceFields() << " entries):\n";
-    if (h_this->IsResolved() || h_this->IsErroneous()) {
-      for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) {
-        os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str());
+    os << "  direct methods (" << h_this->NumDirectMethods() << " entries):\n";
+    for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) {
+      os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str());
+    }
+    if (h_this->NumStaticFields() > 0) {
+      os << "  static fields (" << h_this->NumStaticFields() << " entries):\n";
+      if (h_this->IsResolved() || h_this->IsErroneous()) {
+        for (size_t i = 0; i < h_this->NumStaticFields(); ++i) {
+          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str());
+        }
+      } else {
+        os << "    <not yet available>";
       }
-    } else {
-      os << "    <not yet available>";
+    }
+    if (h_this->NumInstanceFields() > 0) {
+      os << "  instance fields (" << h_this->NumInstanceFields() << " entries):\n";
+      if (h_this->IsResolved() || h_this->IsErroneous()) {
+        for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) {
+          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str());
+        }
+      } else {
+        os << "    <not yet available>";
+      }
     }
   }
 }
@@ -721,9 +742,7 @@
   } else if (IsArrayClass()) {
     return 2;
   } else if (IsProxyClass()) {
-    mirror::SynthesizedProxyClass* proxy_class=
-        reinterpret_cast<mirror::SynthesizedProxyClass*>(this);
-    mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces();
+    mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces();
     return interfaces != nullptr ? interfaces->GetLength() : 0;
   } else {
     const DexFile::TypeList* interfaces = GetInterfaceTypeList();
@@ -753,9 +772,7 @@
       return class_linker->FindSystemClass(self, "Ljava/io/Serializable;");
     }
   } else if (klass->IsProxyClass()) {
-    mirror::SynthesizedProxyClass* proxy_class =
-        reinterpret_cast<mirror::SynthesizedProxyClass*>(klass.Get());
-    mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces();
+    mirror::ObjectArray<mirror::Class>* interfaces = klass.Get()->GetInterfaces();
     DCHECK(interfaces != nullptr);
     return interfaces->Get(idx);
   } else {
@@ -798,5 +815,49 @@
   return GetDexFile().GetInterfacesList(*class_def);
 }
 
+void Class::PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ObjectArray<ArtMethod>* table = GetImTable();
+  if (table != nullptr) {
+    for (uint32_t i = 0; i < kImtSize; i++) {
+      SetEmbeddedImTableEntry(i, table->Get(i));
+    }
+  }
+
+  table = GetVTableDuringLinking();
+  CHECK(table != nullptr);
+  for (int32_t i = 0; i < table->GetLength(); i++) {
+    SetEmbeddedVTableEntry(i, table->Get(i));
+  }
+}
+
+Class* Class::CopyOf(Thread* self, int32_t new_length) {
+  DCHECK_GE(new_length, static_cast<int32_t>(sizeof(Class)));
+  // We may get copied by a compacting GC.
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_this(hs.NewHandle(this));
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  InitializeClassVisitor visitor(new_length);
+
+  mirror::Object* new_class =
+      kMovingClasses ? heap->AllocObject<true>(self, java_lang_Class_, new_length, visitor)
+                     : heap->AllocNonMovableObject<true>(self, java_lang_Class_, new_length, visitor);
+  if (UNLIKELY(new_class == nullptr)) {
+    CHECK(self->IsExceptionPending());  // Expect an OOME.
+    return NULL;
+  }
+
+  mirror::Class* new_class_obj = new_class->AsClass();
+  memcpy(new_class_obj, h_this.Get(), sizeof(Class));
+
+  new_class_obj->SetStatus(kStatusResolving, self);
+  new_class_obj->PopulateEmbeddedImtAndVTable();
+  // Correct some fields.
+  new_class_obj->SetLockWord(LockWord(), false);
+  new_class_obj->SetClassSize(new_length);
+
+  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(new_class_obj);
+  return new_class_obj;
+}
+
 }  // namespace mirror
 }  // namespace art