Move dexCacheStrings from ArtMethod to Class
Adds one load for const strings which are not direct.
Saves >= 60KB of memory avg per app.
Image size: -350KB.
Bug: 17643507
Change-Id: I2d1a3253d9de09682be9bc6b420a29513d592cc8
(cherry picked from commit f521f423b66e952f746885dd9f6cf8ef2788955d)
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index c737ec9..7454cca 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -148,11 +148,11 @@
ADD_TEST_EQ(MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET,
art::mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())
-#define MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET_32 (44 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET_32 (40 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET_32,
art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset(4).Int32Value())
-#define MIRROR_ART_METHOD_QUICK_CODE_OFFSET_32 (40 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_ART_METHOD_QUICK_CODE_OFFSET_32 (36 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET_32,
art::mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value())
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index ead3fa5..5198769 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -58,9 +58,9 @@
inline mirror::String* ClassLinker::ResolveString(uint32_t string_idx,
mirror::ArtMethod* referrer) {
- mirror::String* resolved_string = referrer->GetDexCacheStrings()->Get(string_idx);
+ mirror::Class* declaring_class = referrer->GetDeclaringClass();
+ mirror::String* resolved_string = declaring_class->GetDexCacheStrings()->Get(string_idx);
if (UNLIKELY(resolved_string == NULL)) {
- mirror::Class* declaring_class = referrer->GetDeclaringClass();
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
const DexFile& dex_file = *dex_cache->GetDexFile();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 677fdc9..f092772 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2780,6 +2780,7 @@
klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
klass->SetDexTypeIndex(dex_class_def.class_idx_);
+ klass->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
if (class_data == nullptr) {
@@ -2935,7 +2936,6 @@
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
- dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
@@ -4063,7 +4063,6 @@
// The proxy method doesn't have its own dex cache or dex file and so it steals those of its
// interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
- CHECK_EQ(prototype->GetDexCacheStrings(), method->GetDexCacheStrings());
CHECK(prototype->HasSameDexCacheResolvedMethods(method.Get()));
CHECK(prototype->HasSameDexCacheResolvedTypes(method.Get()));
CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 0c86761..99d0746 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -164,11 +164,8 @@
EXPECT_TRUE(method->GetName() != nullptr);
EXPECT_TRUE(method->GetSignature() != Signature::NoSignature());
- EXPECT_TRUE(method->GetDexCacheStrings() != nullptr);
EXPECT_TRUE(method->HasDexCacheResolvedMethods());
EXPECT_TRUE(method->HasDexCacheResolvedTypes());
- EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetStrings(),
- method->GetDexCacheStrings());
EXPECT_TRUE(method->HasSameDexCacheResolvedMethods(
method->GetDeclaringClass()->GetDexCache()->GetResolvedMethods()));
EXPECT_TRUE(method->HasSameDexCacheResolvedTypes(
@@ -205,6 +202,8 @@
EXPECT_FALSE(klass->IsArrayClass());
EXPECT_TRUE(klass->GetComponentType() == nullptr);
EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
+ EXPECT_TRUE(klass->GetDexCacheStrings() != nullptr);
+ EXPECT_EQ(klass->GetDexCacheStrings(), klass->GetDexCache()->GetStrings());
std::string temp2;
EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor(&temp),
klass->GetDescriptor(&temp2)));
@@ -399,7 +398,8 @@
bool error = false;
- if (!klass->IsClassClass() && !is_static) {
+ // Art method have a different size due to the padding field.
+ if (!klass->IsArtMethodClass() && !klass->IsClassClass() && !is_static) {
size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize();
if (sizeof(T) != expected_size) {
LOG(ERROR) << "Class size mismatch:"
@@ -496,7 +496,6 @@
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_), "declaringClass"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_), "dexCacheResolvedMethods"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_), "dexCacheResolvedTypes"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_strings_), "dexCacheStrings"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex"));
@@ -511,6 +510,7 @@
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods"));
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 7f6303a..f88d56a 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -201,10 +201,11 @@
}
}
mirror::ArtMethod* method = shadow_frame.GetMethod();
- mirror::String* s = method->GetDexCacheStrings()->Get(string_idx);
+ mirror::Class* declaring_class = method->GetDeclaringClass();
+ mirror::String* s = declaring_class->GetDexCacheStrings()->Get(string_idx);
if (UNLIKELY(s == nullptr)) {
StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx,
dex_cache);
}
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 62ef6f8..22d55e2 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -82,11 +82,6 @@
return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_));
}
-inline ObjectArray<String>* ArtMethod::GetDexCacheStrings() {
- return GetFieldObject<ObjectArray<String>>(
- OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_));
-}
-
inline ObjectArray<ArtMethod>* ArtMethod::GetDexCacheResolvedMethods() {
return GetFieldObject<ObjectArray<ArtMethod>>(
OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_));
@@ -460,11 +455,6 @@
return interface_method;
}
-inline void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
- SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
- new_dex_cache_strings);
-}
-
inline void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
new_dex_cache_methods);
@@ -492,7 +482,11 @@
inline void ArtMethod::CheckObjectSizeEqualsMirrorSize() {
// Using the default, check the class object size to make sure it matches the size of the
// object.
- DCHECK_EQ(GetClass()->GetObjectSize(), sizeof(*this));
+ size_t this_size = sizeof(*this);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+ this_size += sizeof(void*) - sizeof(uint32_t);
+#endif
+ DCHECK_EQ(GetClass()->GetObjectSize(), this_size);
}
} // namespace mirror
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f5c1454..da494e0 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -42,6 +42,8 @@
typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper* mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
+#define ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+
// C++ mirror of java.lang.reflect.ArtMethod.
class MANAGED ArtMethod FINAL : public Object {
public:
@@ -208,14 +210,6 @@
SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx);
}
- ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- static MemberOffset DexCacheStringsOffset() {
- return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_);
- }
-
static MemberOffset DexCacheResolvedMethodsOffset() {
return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_);
}
@@ -278,7 +272,7 @@
}
ALWAYS_INLINE static MemberOffset EntryPointFromPortableCompiledCodeOffset(size_t pointer_size) {
- return MemberOffset(PtrSizedFieldsOffset() + OFFSETOF_MEMBER(
+ return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
PtrSizedFields, entry_point_from_portable_compiled_code_) / sizeof(void*) * pointer_size);
}
@@ -445,17 +439,17 @@
void UnregisterNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static MemberOffset EntryPointFromInterpreterOffset(size_t pointer_size) {
- return MemberOffset(PtrSizedFieldsOffset() + OFFSETOF_MEMBER(
+ return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
PtrSizedFields, entry_point_from_interpreter_) / sizeof(void*) * pointer_size);
}
static MemberOffset EntryPointFromJniOffset(size_t pointer_size) {
- return MemberOffset(PtrSizedFieldsOffset() + OFFSETOF_MEMBER(
+ return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
PtrSizedFields, entry_point_from_jni_) / sizeof(void*) * pointer_size);
}
static MemberOffset EntryPointFromQuickCompiledCodeOffset(size_t pointer_size) {
- return MemberOffset(PtrSizedFieldsOffset() + OFFSETOF_MEMBER(
+ return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
PtrSizedFields, entry_point_from_quick_compiled_code_) / sizeof(void*) * pointer_size);
}
@@ -581,13 +575,19 @@
ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static size_t SizeWithoutPointerFields() {
- return sizeof(ArtMethod) - sizeof(PtrSizedFields);
+ static size_t SizeWithoutPointerFields(size_t pointer_size) {
+ size_t total = sizeof(ArtMethod) - sizeof(PtrSizedFields);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+ // Add 4 bytes if 64 bit, otherwise 0.
+ total += pointer_size - sizeof(uint32_t);
+#endif
+ return total;
}
// Size of an instance of java.lang.reflect.ArtMethod not including its value array.
static size_t InstanceSize(size_t pointer_size) {
- return SizeWithoutPointerFields() + (sizeof(PtrSizedFields) / sizeof(void*)) * pointer_size;
+ return SizeWithoutPointerFields(pointer_size) +
+ (sizeof(PtrSizedFields) / sizeof(void*)) * pointer_size;
}
protected:
@@ -601,9 +601,6 @@
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
HeapReference<ObjectArray<Class>> dex_cache_resolved_types_;
- // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
- HeapReference<ObjectArray<String>> dex_cache_strings_;
-
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
@@ -622,7 +619,7 @@
// ifTable.
uint32_t method_index_;
- // Add alignment word here if necessary.
+ // Fake padding field gets inserted here.
// Must be the last fields in the method.
struct PACKED(4) PtrSizedFields {
@@ -653,8 +650,13 @@
ALWAYS_INLINE ObjectArray<Class>* GetDexCacheResolvedTypes()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static size_t PtrSizedFieldsOffset() {
- return OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_);
+ static size_t PtrSizedFieldsOffset(size_t pointer_size) {
+ size_t offset = OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+ // Add 4 bytes if 64 bit, otherwise 0.
+ offset += pointer_size - sizeof(uint32_t);
+#endif
+ return offset;
}
friend struct art::ArtMethodOffsets; // for verifying offset information
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index a69d37e..599f178 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -800,6 +800,14 @@
}
}
+inline void Class::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
+ SetFieldObject<false>(DexCacheStringsOffset(), new_dex_cache_strings);
+}
+
+inline ObjectArray<String>* Class::GetDexCacheStrings() {
+ return GetFieldObject<ObjectArray<String>>(DexCacheStringsOffset());
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 82425b5..a77972e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1020,6 +1020,13 @@
bool GetSlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetSlowPath(bool enabled) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static MemberOffset DexCacheStringsOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_);
+ }
+
// Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
// fence.
class InitializeClassVisitor {
@@ -1065,6 +1072,9 @@
// runtime such as arrays and primitive classes).
HeapReference<DexCache> dex_cache_;
+ // Short cuts to dex_cache_ member for fast compiled code access.
+ HeapReference<ObjectArray<String>> dex_cache_strings_;
+
// static, private, and <init> methods
HeapReference<ObjectArray<ArtMethod>> direct_methods_;
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 8a595ac..eab34f7 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -25,7 +25,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '5', '0', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '5', '1', '\0' };
static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
size_t estimate = 0U;