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-inl.h b/runtime/mirror/class-inl.h
index 2daa6e4..349d4a3 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -19,8 +19,8 @@
 
 #include "class.h"
 
-#include "art_field.h"
-#include "art_method.h"
+#include "art_field-inl.h"
+#include "art_method-inl.h"
 #include "class_linker-inl.h"
 #include "class_loader.h"
 #include "common_throws.h"
@@ -29,6 +29,7 @@
 #include "gc/heap-inl.h"
 #include "iftable.h"
 #include "object_array-inl.h"
+#include "read_barrier-inl.h"
 #include "runtime.h"
 #include "string.h"
 
@@ -148,6 +149,23 @@
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable);
 }
 
+inline ArtMethod* Class::GetEmbeddedImTableEntry(uint32_t i) {
+  uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
+  return GetFieldObject<mirror::ArtMethod>(MemberOffset(offset));
+}
+
+inline void Class::SetEmbeddedImTableEntry(uint32_t i, ArtMethod* method) {
+  uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
+  SetFieldObject<false>(MemberOffset(offset), method);
+  CHECK(method == GetImTable()->Get(i));
+}
+
+inline void Class::SetEmbeddedVTableEntry(uint32_t i, ArtMethod* method) {
+  uint32_t offset = EmbeddedVTableOffset().Uint32Value() + i * sizeof(VTableEntry);
+  SetFieldObject<false>(MemberOffset(offset), method);
+  CHECK(method == GetVTableDuringLinking()->Get(i));
+}
+
 inline bool Class::Implements(Class* klass) {
   DCHECK(klass != NULL);
   DCHECK(klass->IsInterface()) << PrettyClass(this);
@@ -373,7 +391,8 @@
 
 inline void Class::SetSFields(ObjectArray<ArtField>* new_sfields)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(NULL == GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)));
+  DCHECK((IsRetired() && new_sfields == nullptr) ||
+         (NULL == GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_))));
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields);
 }
 
@@ -435,9 +454,9 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline uint32_t Class::GetAccessFlags() {
-  // Check class is loaded or this is java.lang.String that has a
+  // Check class is loaded/retired or this is java.lang.String that has a
   // circularity issue during loading the names of its members
-  DCHECK(IsLoaded<kVerifyFlags>() ||
+  DCHECK(IsIdxLoaded<kVerifyFlags>() || IsRetired<kVerifyFlags>() ||
          IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() ||
          this == String::GetJavaLangString() ||
          this == ArtField::GetJavaLangReflectArtField() ||
@@ -503,12 +522,63 @@
   return Alloc<true>(self, Runtime::Current()->GetHeap()->GetCurrentNonMovingAllocator());
 }
 
+inline uint32_t Class::ComputeClassSize(bool has_embedded_tables,
+                                        uint32_t num_vtable_entries,
+                                        uint32_t num_32bit_static_fields,
+                                        uint32_t num_64bit_static_fields,
+                                        uint32_t num_ref_static_fields) {
+  // Space used by java.lang.Class and its instance fields.
+  uint32_t size = sizeof(Class);
+  // Space used by embedded tables.
+  if (has_embedded_tables) {
+    uint32_t embedded_imt_size = kImtSize * sizeof(ImTableEntry);
+    uint32_t embedded_vtable_size = num_vtable_entries * sizeof(VTableEntry);
+    size += embedded_imt_size + embedded_vtable_size;
+  }
+  // Space used by reference statics.
+  size +=  num_ref_static_fields * sizeof(HeapReference<Object>);
+  // Possible pad for alignment.
+  if (((size & 7) != 0) && (num_64bit_static_fields > 0) && (num_32bit_static_fields == 0)) {
+    size += sizeof(uint32_t);
+  }
+  // Space used for primitive static fields.
+  size += (num_32bit_static_fields * sizeof(uint32_t)) +
+      (num_64bit_static_fields * sizeof(uint64_t));
+  return size;
+}
+
 template <bool kVisitClass, typename Visitor>
 inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
   // Visit the static fields first so that we don't overwrite the SFields / IFields instance
   // fields.
-  VisitStaticFieldsReferences<kVisitClass>(this, visitor);
   VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
+  if (!IsTemp()) {
+    // Temp classes don't ever populate imt/vtable or static fields and they are not even
+    // allocated with the right size for those.
+    VisitStaticFieldsReferences<kVisitClass>(this, visitor);
+    if (ShouldHaveEmbeddedImtAndVTable()) {
+      VisitEmbeddedImtAndVTable(visitor);
+    }
+  }
+}
+
+template<typename Visitor>
+inline void Class::VisitEmbeddedImtAndVTable(const Visitor& visitor) {
+  uint32_t pos = sizeof(mirror::Class);
+
+  size_t count = kImtSize;
+  for (size_t i = 0; i < count; ++i) {
+    MemberOffset offset = MemberOffset(pos);
+    visitor(this, offset, true);
+    pos += sizeof(ImTableEntry);
+  }
+
+  count = ((GetVTable() != NULL) ? GetVTable()->GetLength() : 0);
+  for (size_t i = 0; i < count; ++i) {
+    MemberOffset offset = MemberOffset(pos);
+    visitor(this, offset, true);
+    pos += sizeof(VTableEntry);
+  }
 }
 
 template<ReadBarrierOption kReadBarrierOption>
@@ -554,6 +624,36 @@
   }
 }
 
+inline ObjectArray<Class>* Class::GetInterfaces() {
+  CHECK(IsProxyClass());
+  // First static field.
+  DCHECK(GetSFields()->Get(0)->IsArtField());
+  DCHECK_STREQ(GetSFields()->Get(0)->GetName(), "interfaces");
+  MemberOffset field_offset = GetSFields()->Get(0)->GetOffset();
+  return GetFieldObject<ObjectArray<Class>>(field_offset);
+}
+
+inline ObjectArray<ObjectArray<Class>>* Class::GetThrows() {
+  CHECK(IsProxyClass());
+  // Second static field.
+  DCHECK(GetSFields()->Get(1)->IsArtField());
+  DCHECK_STREQ(GetSFields()->Get(1)->GetName(), "throws");
+  MemberOffset field_offset = GetSFields()->Get(1)->GetOffset();
+  return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset);
+}
+
+inline void Class::InitializeClassVisitor::operator()(
+    mirror::Object* obj, size_t usable_size) const {
+  DCHECK_LE(class_size_, usable_size);
+  // Avoid AsClass as object is not yet in live bitmap or allocation stack.
+  mirror::Class* klass = down_cast<mirror::Class*>(obj);
+  // DCHECK(klass->IsClass());
+  klass->SetClassSize(class_size_);
+  klass->SetPrimitiveType(Primitive::kPrimNot);  // Default to not being primitive.
+  klass->SetDexClassDefIndex(DexFile::kDexNoIndex16);  // Default to no valid class def index.
+  klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
+}
+
 }  // namespace mirror
 }  // namespace art