Merge "ART: Fix dependencies"
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 8d53dbf..6750554 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -640,28 +640,6 @@
INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64),
#undef INTRINSIC
-
-#define SPECIAL(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineSpecial, { d } } }
-
- SPECIAL(JavaLangString, Init, _V, kInlineStringInit, 0),
- SPECIAL(JavaLangString, Init, ByteArray_V, kInlineStringInit, 1),
- SPECIAL(JavaLangString, Init, ByteArrayI_V, kInlineStringInit, 2),
- SPECIAL(JavaLangString, Init, ByteArrayII_V, kInlineStringInit, 3),
- SPECIAL(JavaLangString, Init, ByteArrayIII_V, kInlineStringInit, 4),
- SPECIAL(JavaLangString, Init, ByteArrayIIString_V, kInlineStringInit, 5),
- SPECIAL(JavaLangString, Init, ByteArrayString_V, kInlineStringInit, 6),
- SPECIAL(JavaLangString, Init, ByteArrayIICharset_V, kInlineStringInit, 7),
- SPECIAL(JavaLangString, Init, ByteArrayCharset_V, kInlineStringInit, 8),
- SPECIAL(JavaLangString, Init, CharArray_V, kInlineStringInit, 9),
- SPECIAL(JavaLangString, Init, CharArrayII_V, kInlineStringInit, 10),
- SPECIAL(JavaLangString, Init, IICharArray_V, kInlineStringInit, 11),
- SPECIAL(JavaLangString, Init, IntArrayII_V, kInlineStringInit, 12),
- SPECIAL(JavaLangString, Init, String_V, kInlineStringInit, 13),
- SPECIAL(JavaLangString, Init, StringBuffer_V, kInlineStringInit, 14),
- SPECIAL(JavaLangString, Init, StringBuilder_V, kInlineStringInit, 15),
-
-#undef SPECIAL
};
DexFileMethodInliner::DexFileMethodInliner()
@@ -843,22 +821,4 @@
}
}
-uint32_t DexFileMethodInliner::GetOffsetForStringInit(uint32_t method_index,
- PointerSize pointer_size) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- if (it != inline_methods_.end() && (it->second.opcode == kInlineStringInit)) {
- uint32_t string_init_base_offset = Thread::QuickEntryPointOffsetWithSize(
- OFFSETOF_MEMBER(QuickEntryPoints, pNewEmptyString), pointer_size);
- return string_init_base_offset + it->second.d.data * static_cast<size_t>(pointer_size);
- }
- return 0;
-}
-
-bool DexFileMethodInliner::IsStringInitMethodIndex(uint32_t method_index) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- return (it != inline_methods_.end()) && (it->second.opcode == kInlineStringInit);
-}
-
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 43fc687..f4ae5a5 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -82,17 +82,6 @@
bool IsSpecial(uint32_t method_index) REQUIRES(!lock_);
/**
- * Gets the thread pointer entrypoint offset for a string init method index and pointer size.
- */
- uint32_t GetOffsetForStringInit(uint32_t method_index, PointerSize pointer_size)
- REQUIRES(!lock_);
-
- /**
- * Check whether a particular method index is a string init.
- */
- bool IsStringInitMethodIndex(uint32_t method_index) REQUIRES(!lock_);
-
- /**
* To avoid multiple lookups of a class by its descriptor, we cache its
* type index in the IndexCache. These are the indexes into the IndexCache
* class_indexes array.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 56a9962..f1d3116 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2794,18 +2794,6 @@
return oss.str();
}
-bool CompilerDriver::IsStringTypeIndex(uint16_t type_index, const DexFile* dex_file) {
- const char* type = dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_index));
- return strcmp(type, "Ljava/lang/String;") == 0;
-}
-
-bool CompilerDriver::IsStringInit(uint32_t method_index, const DexFile* dex_file, int32_t* offset) {
- DexFileMethodInliner* inliner = GetMethodInlinerMap()->GetMethodInliner(dex_file);
- const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
- *offset = inliner->GetOffsetForStringInit(method_index, pointer_size);
- return inliner->IsStringInitMethodIndex(method_index);
-}
-
bool CompilerDriver::MayInlineInternal(const DexFile* inlined_from,
const DexFile* inlined_into) const {
// We're not allowed to inline across dex files if we're the no-inline-from dex file.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1f4c3ac..41f0d36 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -432,9 +432,6 @@
// Get memory usage during compilation.
std::string GetMemoryUsageString(bool extended) const;
- bool IsStringTypeIndex(uint16_t type_index, const DexFile* dex_file);
- bool IsStringInit(uint32_t method_index, const DexFile* dex_file, int32_t* offset);
-
void SetHadHardVerifierFailure() {
had_hard_verifier_failure_ = true;
}
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 6be458c..55e1221 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6748,10 +6748,13 @@
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
+ uint32_t offset =
+ GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
// temp = thread->string_init_entrypoint
- __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
+ __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 7160607..a2a2e42 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3570,10 +3570,13 @@
// Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
+ uint32_t offset =
+ GetThreadOffset<kArm64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
// temp = thread->string_init_entrypoint
- __ Ldr(XRegisterFrom(temp), MemOperand(tr, invoke->GetStringInitOffset()));
+ __ Ldr(XRegisterFrom(temp), MemOperand(tr, offset));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f560207..5c0ca85 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -4396,13 +4396,16 @@
}
switch (method_load_kind) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
+ uint32_t offset =
+ GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
__ LoadFromOffset(kLoadWord,
temp.AsRegister<Register>(),
TR,
- invoke->GetStringInitOffset());
+ offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index a5e2351..02576bd 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3006,13 +3006,16 @@
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
+ uint32_t offset =
+ GetThreadOffset<kMips64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
__ LoadFromOffset(kLoadDoubleword,
temp.AsRegister<GpuRegister>(),
TR,
- invoke->GetStringInitOffset());
+ offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 47dfb2e..c300080 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4276,10 +4276,13 @@
Location temp) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
- __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
+ uint32_t offset =
+ GetThreadOffset<kX86PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
+ __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(offset));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 59c0ca4..f9a3e42 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -754,11 +754,13 @@
// All registers are assumed to be correctly set up.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
- __ gs()->movq(temp.AsRegister<CpuRegister>(),
- Address::Absolute(invoke->GetStringInitOffset(), /* no_rip */ true));
+ uint32_t offset =
+ GetThreadOffset<kX86_64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
+ __ gs()->movq(temp.AsRegister<CpuRegister>(), Address::Absolute(offset, /* no_rip */ true));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index f7dc237..139daa7 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -767,6 +767,11 @@
return resolved_method;
}
+static bool IsStringConstructor(ArtMethod* method) {
+ ScopedObjectAccess soa(Thread::Current());
+ return method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+}
+
bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
@@ -785,39 +790,6 @@
number_of_arguments++;
}
- // Special handling for string init.
- int32_t string_init_offset = 0;
- bool is_string_init = compiler_driver_->IsStringInit(method_idx,
- dex_file_,
- &string_init_offset);
- // Replace calls to String.<init> with StringFactory.
- if (is_string_init) {
- HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
- HInvokeStaticOrDirect::MethodLoadKind::kStringInit,
- HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
- dchecked_integral_cast<uint64_t>(string_init_offset),
- 0U
- };
- MethodReference target_method(dex_file_, method_idx);
- HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
- arena_,
- number_of_arguments - 1,
- Primitive::kPrimNot /*return_type */,
- dex_pc,
- method_idx,
- nullptr,
- dispatch_info,
- invoke_type,
- target_method,
- HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
- return HandleStringInit(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor);
- }
-
ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type);
if (UNLIKELY(resolved_method == nullptr)) {
@@ -838,6 +810,35 @@
true /* is_unresolved */);
}
+ // Replace calls to String.<init> with StringFactory.
+ if (IsStringConstructor(resolved_method)) {
+ uint32_t string_init_entry_point = WellKnownClasses::StringInitToEntryPoint(resolved_method);
+ HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
+ HInvokeStaticOrDirect::MethodLoadKind::kStringInit,
+ HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
+ dchecked_integral_cast<uint64_t>(string_init_entry_point),
+ 0U
+ };
+ MethodReference target_method(dex_file_, method_idx);
+ HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
+ arena_,
+ number_of_arguments - 1,
+ Primitive::kPrimNot /*return_type */,
+ dex_pc,
+ method_idx,
+ nullptr,
+ dispatch_info,
+ invoke_type,
+ target_method,
+ HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
+ return HandleStringInit(invoke,
+ number_of_vreg_arguments,
+ args,
+ register_index,
+ is_range,
+ descriptor);
+ }
+
// Potential class initialization check, in the case of a static method call.
HClinitCheck* clinit_check = nullptr;
HInvoke* invoke = nullptr;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 57ae555..4dc4c20 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4044,9 +4044,9 @@
}
bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; }
- int32_t GetStringInitOffset() const {
+ QuickEntrypointEnum GetStringInitEntryPoint() const {
DCHECK(IsStringInit());
- return dispatch_info_.method_load_data;
+ return static_cast<QuickEntrypointEnum>(dispatch_info_.method_load_data);
}
uint64_t GetMethodAddress() const {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 77c3f0f..5934f13 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -576,9 +576,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
&& called_method->IsConstructor())) {
- ScopedObjectAccessUnchecked soa(self);
- jmethodID mid = soa.EncodeMethod(called_method);
- called_method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ called_method = WellKnownClasses::StringInitToStringFactory(called_method);
string_init = true;
}
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 59b2b07..a11f9ab 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -619,7 +619,8 @@
}
if (c->IsStringClass()) {
// Replace calls to String.<init> with equivalent StringFactory call.
- jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
+ jmethodID sf_mid = soa.EncodeMethod(
+ WellKnownClasses::StringInitToStringFactory(soa.DecodeMethod(mid)));
return CallStaticObjectMethodV(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
}
mirror::Object* result = c->AllocObject(soa.Self());
@@ -644,7 +645,8 @@
}
if (c->IsStringClass()) {
// Replace calls to String.<init> with equivalent StringFactory call.
- jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
+ jmethodID sf_mid = soa.EncodeMethod(
+ WellKnownClasses::StringInitToStringFactory(soa.DecodeMethod(mid)));
return CallStaticObjectMethodA(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
}
mirror::Object* result = c->AllocObject(soa.Self());
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index c69e98c..30b10d8 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -455,7 +455,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
}
mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
@@ -486,7 +486,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
}
mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
@@ -518,7 +518,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
receiver = nullptr;
}
uint32_t shorty_len = 0;
@@ -550,7 +550,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
receiver = nullptr;
}
uint32_t shorty_len = 0;
@@ -596,8 +596,7 @@
if (!m->IsStatic()) {
// Replace calls to String.<init> with equivalent StringFactory call.
if (declaring_class->IsStringClass() && m->IsConstructor()) {
- jmethodID mid = soa.EncodeMethod(m);
- m = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ m = WellKnownClasses::StringInitToStringFactory(m);
CHECK(javaReceiver == nullptr);
} else {
// Check that the receiver is non-null and an instance of the field's declaring class.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 45a9be7..d0ea2d7 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -127,43 +127,6 @@
InitEntryPoints(&tlsPtr_.jni_entrypoints, &tlsPtr_.quick_entrypoints);
}
-void Thread::InitStringEntryPoints() {
- ScopedObjectAccess soa(this);
- QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
- qpoints->pNewEmptyString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newEmptyString));
- qpoints->pNewStringFromBytes_B = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B));
- qpoints->pNewStringFromBytes_BI = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BI));
- qpoints->pNewStringFromBytes_BII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BII));
- qpoints->pNewStringFromBytes_BIII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIII));
- qpoints->pNewStringFromBytes_BIIString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIIString));
- qpoints->pNewStringFromBytes_BString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BString));
- qpoints->pNewStringFromBytes_BIICharset = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIICharset));
- qpoints->pNewStringFromBytes_BCharset = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BCharset));
- qpoints->pNewStringFromChars_C = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_C));
- qpoints->pNewStringFromChars_CII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_CII));
- qpoints->pNewStringFromChars_IIC = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_IIC));
- qpoints->pNewStringFromCodePoints = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromCodePoints));
- qpoints->pNewStringFromString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromString));
- qpoints->pNewStringFromStringBuffer = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer));
- qpoints->pNewStringFromStringBuilder = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder));
-}
-
void Thread::ResetQuickAllocEntryPointsForThread() {
ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints);
}
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index eb5f68d..6b569f4 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -21,6 +21,7 @@
#include <sstream>
#include "base/logging.h"
+#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
#include "ScopedLocalRef.h"
@@ -89,38 +90,6 @@
jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
jmethodID WellKnownClasses::java_lang_Short_valueOf;
-jmethodID WellKnownClasses::java_lang_String_init;
-jmethodID WellKnownClasses::java_lang_String_init_B;
-jmethodID WellKnownClasses::java_lang_String_init_BI;
-jmethodID WellKnownClasses::java_lang_String_init_BII;
-jmethodID WellKnownClasses::java_lang_String_init_BIII;
-jmethodID WellKnownClasses::java_lang_String_init_BIIString;
-jmethodID WellKnownClasses::java_lang_String_init_BString;
-jmethodID WellKnownClasses::java_lang_String_init_BIICharset;
-jmethodID WellKnownClasses::java_lang_String_init_BCharset;
-jmethodID WellKnownClasses::java_lang_String_init_C;
-jmethodID WellKnownClasses::java_lang_String_init_CII;
-jmethodID WellKnownClasses::java_lang_String_init_IIC;
-jmethodID WellKnownClasses::java_lang_String_init_String;
-jmethodID WellKnownClasses::java_lang_String_init_StringBuffer;
-jmethodID WellKnownClasses::java_lang_String_init_III;
-jmethodID WellKnownClasses::java_lang_String_init_StringBuilder;
-jmethodID WellKnownClasses::java_lang_StringFactory_newEmptyString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BI;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIIString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIICharset;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BCharset;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_C;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_CII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_IIC;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromCodePoints;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder;
jmethodID WellKnownClasses::java_lang_System_runFinalization = nullptr;
jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException;
jmethodID WellKnownClasses::java_lang_Thread_init;
@@ -215,6 +184,76 @@
StringPrintf("(%c)L%s;", prim_name, boxed_name).c_str());
}
+#define STRING_INIT_LIST(V) \
+ V(java_lang_String_init, "()V", newEmptyString, "newEmptyString", "()Ljava/lang/String;", NewEmptyString) \
+ V(java_lang_String_init_B, "([B)V", newStringFromBytes_B, "newStringFromBytes", "([B)Ljava/lang/String;", NewStringFromBytes_B) \
+ V(java_lang_String_init_BI, "([BI)V", newStringFromBytes_BI, "newStringFromBytes", "([BI)Ljava/lang/String;", NewStringFromBytes_BI) \
+ V(java_lang_String_init_BII, "([BII)V", newStringFromBytes_BII, "newStringFromBytes", "([BII)Ljava/lang/String;", NewStringFromBytes_BII) \
+ V(java_lang_String_init_BIII, "([BIII)V", newStringFromBytes_BIII, "newStringFromBytes", "([BIII)Ljava/lang/String;", NewStringFromBytes_BIII) \
+ V(java_lang_String_init_BIIString, "([BIILjava/lang/String;)V", newStringFromBytes_BIIString, "newStringFromBytes", "([BIILjava/lang/String;)Ljava/lang/String;", NewStringFromBytes_BIIString) \
+ V(java_lang_String_init_BString, "([BLjava/lang/String;)V", newStringFromBytes_BString, "newStringFromBytes", "([BLjava/lang/String;)Ljava/lang/String;", NewStringFromBytes_BString) \
+ V(java_lang_String_init_BIICharset, "([BIILjava/nio/charset/Charset;)V", newStringFromBytes_BIICharset, "newStringFromBytes", "([BIILjava/nio/charset/Charset;)Ljava/lang/String;", NewStringFromBytes_BIICharset) \
+ V(java_lang_String_init_BCharset, "([BLjava/nio/charset/Charset;)V", newStringFromBytes_BCharset, "newStringFromBytes", "([BLjava/nio/charset/Charset;)Ljava/lang/String;", NewStringFromBytes_BCharset) \
+ V(java_lang_String_init_C, "([C)V", newStringFromChars_C, "newStringFromChars", "([C)Ljava/lang/String;", NewStringFromChars_C) \
+ V(java_lang_String_init_CII, "([CII)V", newStringFromChars_CII, "newStringFromChars", "([CII)Ljava/lang/String;", NewStringFromChars_CII) \
+ V(java_lang_String_init_IIC, "(II[C)V", newStringFromChars_IIC, "newStringFromChars", "(II[C)Ljava/lang/String;", NewStringFromChars_IIC) \
+ V(java_lang_String_init_String, "(Ljava/lang/String;)V", newStringFromString, "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;", NewStringFromString) \
+ V(java_lang_String_init_StringBuffer, "(Ljava/lang/StringBuffer;)V", newStringFromStringBuffer, "newStringFromStringBuffer", "(Ljava/lang/StringBuffer;)Ljava/lang/String;", NewStringFromStringBuffer) \
+ V(java_lang_String_init_III, "([III)V", newStringFromCodePoints, "newStringFromCodePoints", "([III)Ljava/lang/String;", NewStringFromCodePoints) \
+ V(java_lang_String_init_StringBuilder, "(Ljava/lang/StringBuilder;)V", newStringFromStringBuilder, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;", NewStringFromStringBuilder) \
+
+#define STATIC_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, ...) \
+ static ArtMethod* init_runtime_name; \
+ static ArtMethod* new_runtime_name;
+ STRING_INIT_LIST(STATIC_STRING_INIT)
+#undef STATIC_STRING_INIT
+
+void WellKnownClasses::InitStringInit(JNIEnv* env) {
+ ScopedObjectAccess soa(Thread::Current());
+ #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, ...) \
+ init_runtime_name = soa.DecodeMethod( \
+ CacheMethod(env, java_lang_String, false, "<init>", init_signature)); \
+ new_runtime_name = soa.DecodeMethod( \
+ CacheMethod(env, java_lang_StringFactory, true, new_java_name, new_signature));
+ STRING_INIT_LIST(LOAD_STRING_INIT)
+ #undef LOAD_STRING_INIT
+}
+
+void Thread::InitStringEntryPoints() {
+ QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
+ #define SET_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ qpoints->p ## entry_point_name = reinterpret_cast<void(*)()>(new_runtime_name);
+ STRING_INIT_LIST(SET_ENTRY_POINT)
+ #undef SET_ENTRY_POINT
+}
+
+ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) {
+ #define TO_STRING_FACTORY(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ if (string_init == init_runtime_name) { \
+ return new_runtime_name; \
+ }
+ STRING_INIT_LIST(TO_STRING_FACTORY)
+ #undef TO_STRING_FACTORY
+ LOG(FATAL) << "Could not find StringFactory method for String.<init>";
+ return nullptr;
+}
+
+uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
+ #define TO_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ if (string_init == init_runtime_name) { \
+ return kQuick ## entry_point_name; \
+ }
+ STRING_INIT_LIST(TO_ENTRY_POINT)
+ #undef TO_STRING_FACTORY
+ LOG(FATAL) << "Could not find StringFactory method for String.<init>";
+ return 0;
+}
+#undef STRING_INIT_LIST
+
void WellKnownClasses::Init(JNIEnv* env) {
com_android_dex_Dex = CacheClass(env, "com/android/dex/Dex");
dalvik_annotation_optimization_CriticalNative =
@@ -284,62 +323,6 @@
org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V");
org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
- java_lang_String_init = CacheMethod(env, java_lang_String, false, "<init>", "()V");
- java_lang_String_init_B = CacheMethod(env, java_lang_String, false, "<init>", "([B)V");
- java_lang_String_init_BI = CacheMethod(env, java_lang_String, false, "<init>", "([BI)V");
- java_lang_String_init_BII = CacheMethod(env, java_lang_String, false, "<init>", "([BII)V");
- java_lang_String_init_BIII = CacheMethod(env, java_lang_String, false, "<init>", "([BIII)V");
- java_lang_String_init_BIIString = CacheMethod(env, java_lang_String, false, "<init>",
- "([BIILjava/lang/String;)V");
- java_lang_String_init_BString = CacheMethod(env, java_lang_String, false, "<init>",
- "([BLjava/lang/String;)V");
- java_lang_String_init_BIICharset = CacheMethod(env, java_lang_String, false, "<init>",
- "([BIILjava/nio/charset/Charset;)V");
- java_lang_String_init_BCharset = CacheMethod(env, java_lang_String, false, "<init>",
- "([BLjava/nio/charset/Charset;)V");
- java_lang_String_init_C = CacheMethod(env, java_lang_String, false, "<init>", "([C)V");
- java_lang_String_init_CII = CacheMethod(env, java_lang_String, false, "<init>", "([CII)V");
- java_lang_String_init_IIC = CacheMethod(env, java_lang_String, false, "<init>", "(II[C)V");
- java_lang_String_init_String = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/String;)V");
- java_lang_String_init_StringBuffer = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/StringBuffer;)V");
- java_lang_String_init_III = CacheMethod(env, java_lang_String, false, "<init>", "([III)V");
- java_lang_String_init_StringBuilder = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/StringBuilder;)V");
- java_lang_StringFactory_newEmptyString = CacheMethod(env, java_lang_StringFactory, true,
- "newEmptyString", "()Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_B = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([B)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BI = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BI)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BIII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIIString = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BIILjava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BString = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BLjava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIICharset = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BIILjava/nio/charset/Charset;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BCharset = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BLjava/nio/charset/Charset;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_C = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "([C)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_CII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "([CII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_IIC = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "(II[C)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromString = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromStringBuffer = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromStringBuffer", "(Ljava/lang/StringBuffer;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromCodePoints = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromCodePoints", "([III)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromStringBuilder = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;");
-
dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "Ljava/lang/Object;");
dalvik_system_DexFile_fileName = CacheField(env, dalvik_system_DexFile, false, "mFileName", "Ljava/lang/String;");
dalvik_system_PathClassLoader_pathList = CacheField(env, dalvik_system_PathClassLoader, false, "pathList", "Ldalvik/system/DexPathList;");
@@ -384,6 +367,7 @@
java_lang_Long_valueOf = CachePrimitiveBoxingMethod(env, 'J', "java/lang/Long");
java_lang_Short_valueOf = CachePrimitiveBoxingMethod(env, 'S', "java/lang/Short");
+ InitStringInit(env);
Thread::Current()->InitStringEntryPoints();
}
@@ -399,43 +383,4 @@
return reinterpret_cast<mirror::Class*>(Thread::Current()->DecodeJObject(global_jclass));
}
-jmethodID WellKnownClasses::StringInitToStringFactoryMethodID(jmethodID string_init) {
- // TODO: Prioritize ordering.
- if (string_init == java_lang_String_init) {
- return java_lang_StringFactory_newEmptyString;
- } else if (string_init == java_lang_String_init_B) {
- return java_lang_StringFactory_newStringFromBytes_B;
- } else if (string_init == java_lang_String_init_BI) {
- return java_lang_StringFactory_newStringFromBytes_BI;
- } else if (string_init == java_lang_String_init_BII) {
- return java_lang_StringFactory_newStringFromBytes_BII;
- } else if (string_init == java_lang_String_init_BIII) {
- return java_lang_StringFactory_newStringFromBytes_BIII;
- } else if (string_init == java_lang_String_init_BIIString) {
- return java_lang_StringFactory_newStringFromBytes_BIIString;
- } else if (string_init == java_lang_String_init_BString) {
- return java_lang_StringFactory_newStringFromBytes_BString;
- } else if (string_init == java_lang_String_init_BIICharset) {
- return java_lang_StringFactory_newStringFromBytes_BIICharset;
- } else if (string_init == java_lang_String_init_BCharset) {
- return java_lang_StringFactory_newStringFromBytes_BCharset;
- } else if (string_init == java_lang_String_init_C) {
- return java_lang_StringFactory_newStringFromChars_C;
- } else if (string_init == java_lang_String_init_CII) {
- return java_lang_StringFactory_newStringFromChars_CII;
- } else if (string_init == java_lang_String_init_IIC) {
- return java_lang_StringFactory_newStringFromChars_IIC;
- } else if (string_init == java_lang_String_init_String) {
- return java_lang_StringFactory_newStringFromString;
- } else if (string_init == java_lang_String_init_StringBuffer) {
- return java_lang_StringFactory_newStringFromStringBuffer;
- } else if (string_init == java_lang_String_init_III) {
- return java_lang_StringFactory_newStringFromCodePoints;
- } else if (string_init == java_lang_String_init_StringBuilder) {
- return java_lang_StringFactory_newStringFromStringBuilder;
- }
- LOG(FATAL) << "Could not find StringFactory method for String.<init>";
- return nullptr;
-}
-
} // namespace art
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index b4d179c..c9110e6 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -21,6 +21,9 @@
#include "jni.h"
namespace art {
+
+class ArtMethod;
+
namespace mirror {
class Class;
} // namespace mirror
@@ -35,7 +38,8 @@
public:
static void Init(JNIEnv* env); // Run before native methods are registered.
static void LateInit(JNIEnv* env); // Run after native methods are registered.
- static jmethodID StringInitToStringFactoryMethodID(jmethodID string_init);
+ static ArtMethod* StringInitToStringFactory(ArtMethod* method);
+ static uint32_t StringInitToEntryPoint(ArtMethod* method);
static mirror::Class* ToClass(jclass global_jclass)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -100,38 +104,6 @@
static jmethodID java_lang_reflect_Proxy_invoke;
static jmethodID java_lang_Runtime_nativeLoad;
static jmethodID java_lang_Short_valueOf;
- static jmethodID java_lang_String_init;
- static jmethodID java_lang_String_init_B;
- static jmethodID java_lang_String_init_BI;
- static jmethodID java_lang_String_init_BII;
- static jmethodID java_lang_String_init_BIII;
- static jmethodID java_lang_String_init_BIIString;
- static jmethodID java_lang_String_init_BString;
- static jmethodID java_lang_String_init_BIICharset;
- static jmethodID java_lang_String_init_BCharset;
- static jmethodID java_lang_String_init_C;
- static jmethodID java_lang_String_init_CII;
- static jmethodID java_lang_String_init_IIC;
- static jmethodID java_lang_String_init_String;
- static jmethodID java_lang_String_init_StringBuffer;
- static jmethodID java_lang_String_init_III;
- static jmethodID java_lang_String_init_StringBuilder;
- static jmethodID java_lang_StringFactory_newEmptyString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_B;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BI;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BII;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIII;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIIString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIICharset;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BCharset;
- static jmethodID java_lang_StringFactory_newStringFromChars_C;
- static jmethodID java_lang_StringFactory_newStringFromChars_CII;
- static jmethodID java_lang_StringFactory_newStringFromChars_IIC;
- static jmethodID java_lang_StringFactory_newStringFromString;
- static jmethodID java_lang_StringFactory_newStringFromStringBuffer;
- static jmethodID java_lang_StringFactory_newStringFromCodePoints;
- static jmethodID java_lang_StringFactory_newStringFromStringBuilder;
static jmethodID java_lang_System_runFinalization;
static jmethodID java_lang_Thread_dispatchUncaughtException;
static jmethodID java_lang_Thread_init;
@@ -177,6 +149,9 @@
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_type;
+
+ private:
+ static void InitStringInit(JNIEnv* env);
};
} // namespace art
diff --git a/test/118-noimage-dex2oat/check b/test/118-noimage-dex2oat/check
index 57111bc..4f46083 100755
--- a/test/118-noimage-dex2oat/check
+++ b/test/118-noimage-dex2oat/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^dalvikvm.* E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 4003ee0..ebf087d 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -73,7 +73,7 @@
$(ART_HOST_EXECUTABLES) \
$(ART_HOST_SHARED_LIBRARY_DEPENDENCIES) \
$(HOST_OUT_EXECUTABLES)/art \
- $(HOST_CORE_IMG_OUT_BASE)-optimizing-pic$(CORE_IMG_SUFFIX)
+ $(HOST_CORE_IMG_OUT_BASE)$(CORE_IMG_SUFFIX)
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index ecf9e53..8604ff0 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -9,7 +9,6 @@
Serve pages on the given port. Defaults to 7100.
TODO:
- * Show GC Root paths.
* Have a way to diff two heap dumps.
* Add more tips to the help page.
@@ -76,6 +75,7 @@
Release History:
0.8 Pending
+ Show sample path from GC root with field names in place of dominator path.
0.7 Aug 16, 2016
Launch ahat server before processing the heap dump.
diff --git a/tools/ahat/src/HeapTable.java b/tools/ahat/src/HeapTable.java
index ed11d17..5b84048 100644
--- a/tools/ahat/src/HeapTable.java
+++ b/tools/ahat/src/HeapTable.java
@@ -84,10 +84,10 @@
for (Heap heap : heaps) {
long size = config.getSize(elem, heap);
total += size;
- vals.add(DocString.format("%,14d", size));
+ vals.add(size == 0 ? DocString.text("") : DocString.format("%,14d", size));
}
if (showTotal) {
- vals.add(DocString.format("%,14d", total));
+ vals.add(total == 0 ? DocString.text("") : DocString.format("%,14d", total));
}
for (ValueConfig<T> value : values) {
diff --git a/tools/ahat/src/InstanceUtils.java b/tools/ahat/src/InstanceUtils.java
index 8769d11..94934a2 100644
--- a/tools/ahat/src/InstanceUtils.java
+++ b/tools/ahat/src/InstanceUtils.java
@@ -19,11 +19,17 @@
import com.android.tools.perflib.heap.ArrayInstance;
import com.android.tools.perflib.heap.ClassInstance;
import com.android.tools.perflib.heap.ClassObj;
+import com.android.tools.perflib.heap.Field;
import com.android.tools.perflib.heap.Heap;
import com.android.tools.perflib.heap.Instance;
+import com.android.tools.perflib.heap.RootObj;
import com.android.tools.perflib.heap.Type;
import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
/**
* Utilities for extracting information from hprof instances.
@@ -179,7 +185,7 @@
* Read a reference field of an instance.
* Returns null if the field value is null, or if the field couldn't be read.
*/
- private static Instance getRefField(Instance inst, String fieldName) {
+ public static Instance getRefField(Instance inst, String fieldName) {
Object value = getField(inst, fieldName);
if (!(value instanceof Instance)) {
return null;
@@ -357,4 +363,90 @@
}
return new NativeAllocation(size, inst.getHeap(), pointer, referent);
}
+
+ public static class PathElement {
+ public final Instance instance;
+ public final String field;
+ public boolean isDominator;
+
+ public PathElement(Instance instance, String field) {
+ this.instance = instance;
+ this.field = field;
+ this.isDominator = false;
+ }
+ }
+
+ /**
+ * Returns a sample path from a GC root to this instance.
+ * The given instance is included as the last element of the path with an
+ * empty field description.
+ */
+ public static List<PathElement> getPathFromGcRoot(Instance inst) {
+ List<PathElement> path = new ArrayList<PathElement>();
+
+ Instance dom = inst;
+ for (PathElement elem = new PathElement(inst, ""); elem != null;
+ elem = getNextPathElementToGcRoot(elem.instance)) {
+ if (elem.instance == dom) {
+ elem.isDominator = true;
+ dom = dom.getImmediateDominator();
+ }
+ path.add(elem);
+ }
+ Collections.reverse(path);
+ return path;
+ }
+
+ /**
+ * Returns the next instance to GC root from this object and a string
+ * description of which field of that object refers to the given instance.
+ * Returns null if the given instance has no next instance to the gc root.
+ */
+ private static PathElement getNextPathElementToGcRoot(Instance inst) {
+ Instance parent = inst.getNextInstanceToGcRoot();
+ if (parent == null || parent instanceof RootObj) {
+ return null;
+ }
+
+ // Search the parent for the reference to the child.
+ // TODO: This seems terribly inefficient. Can we use data structures to
+ // help us here?
+ String description = ".???";
+ if (parent instanceof ArrayInstance) {
+ ArrayInstance array = (ArrayInstance)parent;
+ Object[] values = array.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] instanceof Instance) {
+ Instance ref = (Instance)values[i];
+ if (ref.getId() == inst.getId()) {
+ description = String.format("[%d]", i);
+ break;
+ }
+ }
+ }
+ } else if (parent instanceof ClassObj) {
+ ClassObj cls = (ClassObj)parent;
+ for (Map.Entry<Field, Object> entries : cls.getStaticFieldValues().entrySet()) {
+ if (entries.getValue() instanceof Instance) {
+ Instance ref = (Instance)entries.getValue();
+ if (ref.getId() == inst.getId()) {
+ description = "." + entries.getKey().getName();
+ break;
+ }
+ }
+ }
+ } else if (parent instanceof ClassInstance) {
+ ClassInstance obj = (ClassInstance)parent;
+ for (ClassInstance.FieldValue fields : obj.getValues()) {
+ if (fields.getValue() instanceof Instance) {
+ Instance ref = (Instance)fields.getValue();
+ if (ref.getId() == inst.getId()) {
+ description = "." + fields.getField().getName();
+ break;
+ }
+ }
+ }
+ }
+ return new PathElement(parent, description);
+ }
}
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index 4df1be5..78aac17 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -22,7 +22,6 @@
import com.android.tools.perflib.heap.Field;
import com.android.tools.perflib.heap.Heap;
import com.android.tools.perflib.heap.Instance;
-import com.android.tools.perflib.heap.RootObj;
import com.android.tools.perflib.heap.RootType;
import java.io.IOException;
import java.util.ArrayList;
@@ -32,6 +31,8 @@
import java.util.List;
import java.util.Map;
+import static com.android.ahat.InstanceUtils.PathElement;
+
class ObjectHandler implements AhatHandler {
private static final String ARRAY_ELEMENTS_ID = "elements";
@@ -62,7 +63,7 @@
doc.big(Value.render(mSnapshot, inst));
printAllocationSite(doc, query, inst);
- printDominatorPath(doc, query, inst);
+ printGcRootPath(doc, query, inst);
doc.section("Object Info");
ClassObj cls = inst.getClassObj();
@@ -202,43 +203,43 @@
}
}
- private void printDominatorPath(Doc doc, Query query, Instance inst) {
- doc.section("Dominator Path from Root");
- List<Instance> path = new ArrayList<Instance>();
- for (Instance parent = inst;
- parent != null && !(parent instanceof RootObj);
- parent = parent.getImmediateDominator()) {
- path.add(parent);
- }
+ private void printGcRootPath(Doc doc, Query query, Instance inst) {
+ doc.section("Sample Path from GC Root");
+ List<PathElement> path = InstanceUtils.getPathFromGcRoot(inst);
// Add 'null' as a marker for the root.
- path.add(null);
- Collections.reverse(path);
+ path.add(0, null);
- HeapTable.TableConfig<Instance> table = new HeapTable.TableConfig<Instance>() {
+ HeapTable.TableConfig<PathElement> table = new HeapTable.TableConfig<PathElement>() {
public String getHeapsDescription() {
- return "Bytes Retained by Heap";
+ return "Bytes Retained by Heap (Dominators Only)";
}
- public long getSize(Instance element, Heap heap) {
+ public long getSize(PathElement element, Heap heap) {
if (element == null) {
return mSnapshot.getHeapSize(heap);
}
- int index = mSnapshot.getHeapIndex(heap);
- return element.getRetainedSize(index);
+ if (element.isDominator) {
+ int index = mSnapshot.getHeapIndex(heap);
+ return element.instance.getRetainedSize(index);
+ }
+ return 0;
}
- public List<HeapTable.ValueConfig<Instance>> getValueConfigs() {
- HeapTable.ValueConfig<Instance> value = new HeapTable.ValueConfig<Instance>() {
+ public List<HeapTable.ValueConfig<PathElement>> getValueConfigs() {
+ HeapTable.ValueConfig<PathElement> value = new HeapTable.ValueConfig<PathElement>() {
public String getDescription() {
- return "Object";
+ return "Path Element";
}
- public DocString render(Instance element) {
+ public DocString render(PathElement element) {
if (element == null) {
return DocString.link(DocString.uri("rooted"), DocString.text("ROOT"));
} else {
- return DocString.text("→ ").append(Value.render(mSnapshot, element));
+ DocString label = DocString.text(" → ");
+ label.append(Value.render(mSnapshot, element.instance));
+ label.append(element.field);
+ return label;
}
}
};
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index 3936f29..e08df67 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -29,6 +29,16 @@
// collected before we take the heap dump.
public static DumpedStuff stuff;
+ public static class ObjectTree {
+ public ObjectTree left;
+ public ObjectTree right;
+
+ public ObjectTree(ObjectTree left, ObjectTree right) {
+ this.left = left;
+ this.right = right;
+ }
+ }
+
// We will take a heap dump that includes a single instance of this
// DumpedStuff class. Objects stored as fields in this class can be easily
// found in the hprof dump by searching for the instance of the DumpedStuff
@@ -42,6 +52,11 @@
public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
public byte[] bigArray;
+ public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
+ new ObjectTree(
+ new ObjectTree(null, new ObjectTree(null, null)),
+ new ObjectTree(null, null)),
+ null};
DumpedStuff() {
int N = 1000000;
@@ -53,6 +68,8 @@
NativeAllocationRegistry registry = new NativeAllocationRegistry(
Main.class.getClassLoader(), 0x12345, 42);
registry.registerNativeAllocation(anObject, 0xABCDABCD);
+
+ gcPathArray[2].right.left = gcPathArray[2].left.right;
}
}
diff --git a/tools/ahat/test/InstanceUtilsTest.java b/tools/ahat/test/InstanceUtilsTest.java
index 59b1c90..ec77e70 100644
--- a/tools/ahat/test/InstanceUtilsTest.java
+++ b/tools/ahat/test/InstanceUtilsTest.java
@@ -16,11 +16,16 @@
package com.android.ahat;
+import com.android.tools.perflib.heap.ArrayInstance;
+import com.android.tools.perflib.heap.ClassObj;
import com.android.tools.perflib.heap.Instance;
import java.io.IOException;
+import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class InstanceUtilsTest {
@@ -123,4 +128,55 @@
assertEquals(referent, InstanceUtils.getReferent(wref));
assertNull(InstanceUtils.getReferent(referent));
}
+
+ @Test
+ public void gcRootPath() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+
+ ClassObj main = dump.getAhatSnapshot().findClass("Main");
+ ArrayInstance gcPathArray = (ArrayInstance)dump.getDumpedThing("gcPathArray");
+ Object[] values = gcPathArray.getValues();
+ Instance base = (Instance)values[2];
+ Instance left = InstanceUtils.getRefField(base, "left");
+ Instance right = InstanceUtils.getRefField(base, "right");
+ Instance target = InstanceUtils.getRefField(left, "right");
+
+ List<InstanceUtils.PathElement> path = InstanceUtils.getPathFromGcRoot(target);
+ assertEquals(6, path.size());
+
+ assertEquals(main, path.get(0).instance);
+ assertEquals(".stuff", path.get(0).field);
+ assertTrue(path.get(0).isDominator);
+
+ assertEquals(".gcPathArray", path.get(1).field);
+ assertTrue(path.get(1).isDominator);
+
+ assertEquals(gcPathArray, path.get(2).instance);
+ assertEquals("[2]", path.get(2).field);
+ assertTrue(path.get(2).isDominator);
+
+ assertEquals(base, path.get(3).instance);
+ assertTrue(path.get(3).isDominator);
+
+ // There are two possible paths. Either it can go through the 'left' node,
+ // or the 'right' node.
+ if (path.get(3).field.equals(".left")) {
+ assertEquals(".left", path.get(3).field);
+
+ assertEquals(left, path.get(4).instance);
+ assertEquals(".right", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+
+ } else {
+ assertEquals(".right", path.get(3).field);
+
+ assertEquals(right, path.get(4).instance);
+ assertEquals(".left", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+ }
+
+ assertEquals(target, path.get(5).instance);
+ assertEquals("", path.get(5).field);
+ assertTrue(path.get(5).isDominator);
+ }
}