summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/verification_results.cc2
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--compiler/driver/compiler_options.h8
-rw-r--r--dex2oat/dex2oat.cc19
-rw-r--r--runtime/class_linker.cc14
-rw-r--r--runtime/compiler_filter.cc21
-rw-r--r--runtime/compiler_filter.h16
-rw-r--r--runtime/debugger.cc2
-rw-r--r--runtime/instrumentation.cc15
-rw-r--r--runtime/instrumentation.h7
-rw-r--r--runtime/interpreter/interpreter.cc56
-rw-r--r--runtime/interpreter/interpreter_common.cc43
-rw-r--r--runtime/interpreter/interpreter_common.h6
-rw-r--r--runtime/jit/profile_saver.cc56
-rw-r--r--runtime/jit/profile_saver.h6
-rw-r--r--runtime/mirror/dex_cache-inl.h8
-rw-r--r--runtime/oat_file_assistant.cc4
-rw-r--r--runtime/oat_file_assistant_test.cc2
-rw-r--r--runtime/openjdkjvm/OpenjdkJvm.cc32
-rw-r--r--runtime/verifier/method_verifier.cc2
-rw-r--r--test/117-nopatchoat/nopatchoat.cc2
-rw-r--r--test/597-deopt-new-string/src/Main.java13
-rw-r--r--test/600-verifier-fails/expected.txt1
-rw-r--r--test/600-verifier-fails/info.txt4
-rw-r--r--test/600-verifier-fails/smali/sput.smali23
-rw-r--r--test/600-verifier-fails/src/Main.java30
26 files changed, 282 insertions, 114 deletions
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 606302bd78..03c94a45e3 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -104,7 +104,7 @@ bool VerificationResults::IsClassRejected(ClassReference ref) {
bool VerificationResults::IsCandidateForCompilation(MethodReference&,
const uint32_t access_flags) {
- if (!compiler_options_->IsCompilationEnabled()) {
+ if (!compiler_options_->IsBytecodeCompilationEnabled()) {
return false;
}
// Don't compile class initializers unless kEverything.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 4d622bdddf..4594e2cc42 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -553,8 +553,8 @@ static void CompileMethod(Thread* self,
MethodReference method_ref(&dex_file, method_idx);
if ((access_flags & kAccNative) != 0) {
- // Are we interpreting only and have support for generic JNI down calls?
- if (!driver->GetCompilerOptions().IsCompilationEnabled() &&
+ // Are we extracting only and have support for generic JNI down calls?
+ if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
// Leaving this empty will trigger the generic JNI version
} else {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index c67ab6ef14..6d4455e65c 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -89,8 +89,12 @@ class CompilerOptions FINAL {
return compiler_filter_ == CompilerFilter::kVerifyAtRuntime;
}
- bool IsCompilationEnabled() const {
- return CompilerFilter::IsCompilationEnabled(compiler_filter_);
+ bool IsBytecodeCompilationEnabled() const {
+ return CompilerFilter::IsBytecodeCompilationEnabled(compiler_filter_);
+ }
+
+ bool IsJniCompilationEnabled() const {
+ return CompilerFilter::IsJniCompilationEnabled(compiler_filter_);
}
bool IsVerificationEnabled() const {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index cb274dcc09..9f6f4530c7 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1450,25 +1450,6 @@ class Dex2Oat FINAL {
class_linker->RegisterDexFile(*dex_file, Runtime::Current()->GetLinearAlloc())));
}
- /*
- * If we're not in interpret-only or verify-none or verify-at-runtime or verify-profile mode,
- * go ahead and compile small applications. Don't bother to check if we're doing the image.
- */
- if (!IsBootImage() &&
- compiler_options_->IsCompilationEnabled() &&
- compiler_kind_ == Compiler::kQuick) {
- size_t num_methods = 0;
- for (size_t i = 0; i != dex_files_.size(); ++i) {
- const DexFile* dex_file = dex_files_[i];
- CHECK(dex_file != nullptr);
- num_methods += dex_file->NumMethodIds();
- }
- if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
- compiler_options_->SetCompilerFilter(CompilerFilter::kSpeed);
- VLOG(compiler) << "Below method threshold, compiling anyways";
- }
- }
-
return true;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 26885ac731..d2e23aac15 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1348,7 +1348,8 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
// The image space is not yet added to the heap, avoid read barriers.
mirror::Class* klass = types[j].Read();
- if (klass != nullptr) {
+ // There may also be boot image classes,
+ if (space->HasAddress(klass)) {
DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
// Update the class loader from the one in the image class loader to the one that loaded
// the app image.
@@ -1387,6 +1388,9 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
VLOG(image) << PrettyMethod(&m);
}
}
+ } else {
+ DCHECK(klass == nullptr || heap->ObjectIsInBootImageSpace(klass))
+ << klass << " " << PrettyClass(klass);
}
}
}
@@ -1394,10 +1398,10 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
// The image space is not yet added to the heap, avoid read barriers.
mirror::Class* klass = types[j].Read();
- if (klass != nullptr) {
+ if (space->HasAddress(klass)) {
DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
if (kIsDebugBuild) {
- if (new_class_set != nullptr) {
+ if (new_class_set != nullptr) {
auto it = new_class_set->Find(GcRoot<mirror::Class>(klass));
DCHECK(it != new_class_set->end());
DCHECK_EQ(it->Read(), klass);
@@ -1662,6 +1666,10 @@ bool ClassLinker::AddImageSpace(
// resolve the same way, simply flatten the hierarchy in the way the resolution order would be,
// and check that the dex file names are the same.
for (mirror::ClassLoader* image_class_loader : image_class_loaders) {
+ if (IsBootClassLoader(soa, image_class_loader)) {
+ // The dex cache can reference types from the boot class loader.
+ continue;
+ }
std::list<mirror::String*> image_dex_file_names;
std::string temp_error_msg;
if (!FlattenPathClassLoader(image_class_loader, &image_dex_file_names, &temp_error_msg)) {
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index d617caf78c..dc197c1066 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -20,7 +20,7 @@
namespace art {
-bool CompilerFilter::IsCompilationEnabled(Filter filter) {
+bool CompilerFilter::IsBytecodeCompilationEnabled(Filter filter) {
switch (filter) {
case CompilerFilter::kVerifyNone:
case CompilerFilter::kVerifyAtRuntime:
@@ -39,6 +39,25 @@ bool CompilerFilter::IsCompilationEnabled(Filter filter) {
UNREACHABLE();
}
+bool CompilerFilter::IsJniCompilationEnabled(Filter filter) {
+ switch (filter) {
+ case CompilerFilter::kVerifyNone:
+ case CompilerFilter::kVerifyAtRuntime: return false;
+
+ case CompilerFilter::kVerifyProfile:
+ case CompilerFilter::kInterpretOnly:
+ case CompilerFilter::kSpaceProfile:
+ case CompilerFilter::kSpace:
+ case CompilerFilter::kBalanced:
+ case CompilerFilter::kTime:
+ case CompilerFilter::kSpeedProfile:
+ case CompilerFilter::kSpeed:
+ case CompilerFilter::kEverythingProfile:
+ case CompilerFilter::kEverything: return true;
+ }
+ UNREACHABLE();
+}
+
bool CompilerFilter::IsVerificationEnabled(Filter filter) {
switch (filter) {
case CompilerFilter::kVerifyNone:
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index 6289d8a22c..65d1d987a7 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -30,10 +30,10 @@ class CompilerFilter FINAL {
// Note: Order here matters. Later filter choices are considered "as good
// as" earlier filter choices.
enum Filter {
- kVerifyNone, // Skip verification and compile nothing except JNI stubs.
- kVerifyAtRuntime, // Only compile JNI stubs and verify at runtime.
- kVerifyProfile, // Verify only the classes in the profile.
- kInterpretOnly, // Verify, and compile only JNI stubs.
+ kVerifyNone, // Skip verification but mark all classes as verified anyway.
+ kVerifyAtRuntime, // Delay verication to runtime, do not compile anything.
+ kVerifyProfile, // Verify only the classes in the profile, compile only JNI stubs.
+ kInterpretOnly, // Verify everything, compile only JNI stubs.
kTime, // Compile methods, but minimize compilation time.
kSpaceProfile, // Maximize space savings based on profile.
kSpace, // Maximize space savings.
@@ -45,8 +45,12 @@ class CompilerFilter FINAL {
};
// Returns true if an oat file with this compiler filter contains
- // compiled executable code.
- static bool IsCompilationEnabled(Filter filter);
+ // compiled executable code for bytecode.
+ static bool IsBytecodeCompilationEnabled(Filter filter);
+
+ // Returns true if an oat file with this compiler filter contains
+ // compiled executable code for JNI methods.
+ static bool IsJniCompilationEnabled(Filter filter);
// Returns true if this compiler filter requires running verification.
static bool IsVerificationEnabled(Filter filter);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index d8325525ac..1fb8b407ec 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -582,7 +582,7 @@ class UpdateEntryPointsClassVisitor : public ClassVisitor {
if (Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) &&
!m.IsNative() &&
!m.IsProxyMethod()) {
- instrumentation_->UpdateMethodsCode(&m, GetQuickToInterpreterBridge());
+ instrumentation_->UpdateMethodsCodeFromDebugger(&m, GetQuickToInterpreterBridge());
}
}
return true;
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 34bc458575..61119f8499 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -687,8 +687,7 @@ void Instrumentation::ResetQuickAllocEntryPoints() {
}
}
-void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* quick_code) {
- DCHECK(method->GetDeclaringClass()->IsResolved());
+void Instrumentation::UpdateMethodsCodeImpl(ArtMethod* method, const void* quick_code) {
const void* new_quick_code;
if (LIKELY(!instrumentation_stubs_installed_)) {
new_quick_code = quick_code;
@@ -710,6 +709,18 @@ void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* quick_cod
UpdateEntrypoints(method, new_quick_code);
}
+void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* quick_code) {
+ DCHECK(method->GetDeclaringClass()->IsResolved());
+ UpdateMethodsCodeImpl(method, quick_code);
+}
+
+void Instrumentation::UpdateMethodsCodeFromDebugger(ArtMethod* method, const void* quick_code) {
+ // When debugger attaches, we may update the entry points of all methods of a class
+ // to the interpreter bridge. A method's declaring class might not be in resolved
+ // state yet in that case.
+ UpdateMethodsCodeImpl(method, quick_code);
+}
+
bool Instrumentation::AddDeoptimizedMethod(ArtMethod* method) {
if (IsDeoptimizedMethod(method)) {
// Already in the map. Return.
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index a4c3d41537..ce6ead453f 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -227,6 +227,10 @@ class Instrumentation {
void UpdateMethodsCode(ArtMethod* method, const void* quick_code)
SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
+ // Update the code of a method respecting any installed stubs from debugger.
+ void UpdateMethodsCodeFromDebugger(ArtMethod* method, const void* quick_code)
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
+
// Get the quick code for the given method. More efficient than asking the class linker as it
// will short-cut to GetCode if instrumentation and static method resolution stubs aren't
// installed.
@@ -493,6 +497,9 @@ class Instrumentation {
SHARED_REQUIRES(Locks::mutator_lock_, deoptimized_methods_lock_);
bool IsDeoptimizedMethodsEmpty() const
SHARED_REQUIRES(Locks::mutator_lock_, deoptimized_methods_lock_);
+ void UpdateMethodsCodeImpl(ArtMethod* method, const void* quick_code)
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
+
// Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code?
bool instrumentation_stubs_installed_;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 1d0e600e4d..8c42b3abce 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -484,6 +484,36 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive
self->PopShadowFrame();
}
+static bool IsStringInit(const Instruction* instr, ArtMethod* caller)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ if (instr->Opcode() == Instruction::INVOKE_DIRECT ||
+ instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
+ // Instead of calling ResolveMethod() which has suspend point and can trigger
+ // GC, look up the callee method symbolically.
+ uint16_t callee_method_idx = (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
+ instr->VRegB_3rc() : instr->VRegB_35c();
+ const DexFile* dex_file = caller->GetDexFile();
+ const DexFile::MethodId& method_id = dex_file->GetMethodId(callee_method_idx);
+ const char* class_name = dex_file->StringByTypeIdx(method_id.class_idx_);
+ const char* method_name = dex_file->GetMethodName(method_id);
+ // Compare method's class name and method name against string init.
+ // It's ok since it's not allowed to create your own java/lang/String.
+ // TODO: verify that assumption.
+ if ((strcmp(class_name, "Ljava/lang/String;") == 0) &&
+ (strcmp(method_name, "<init>") == 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int16_t GetReceiverRegisterForStringInit(const Instruction* instr) {
+ DCHECK(instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE ||
+ instr->Opcode() == Instruction::INVOKE_DIRECT);
+ return (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
+ instr->VRegC_3rc() : instr->VRegC_35c();
+}
+
void EnterInterpreterFromDeoptimize(Thread* self,
ShadowFrame* shadow_frame,
bool from_code,
@@ -519,22 +549,38 @@ void EnterInterpreterFromDeoptimize(Thread* self,
// TODO: should be tested more once b/17586779 is fixed.
const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
if (instr->IsInvoke()) {
+ if (IsStringInit(instr, shadow_frame->GetMethod())) {
+ uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr);
+ // Move the StringFactory.newStringFromChars() result into the register representing
+ // "this object" when invoking the string constructor in the original dex instruction.
+ // Also move the result into all aliases.
+ DCHECK(value.GetL()->IsString());
+ SetStringInitValueToAllAliases(shadow_frame, this_obj_vreg, value);
+ // Calling string constructor in the original dex code doesn't generate a result value.
+ value.SetJ(0);
+ }
new_dex_pc = dex_pc + instr->SizeInCodeUnits();
} else if (instr->Opcode() == Instruction::NEW_INSTANCE) {
// It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a
// java string, which is turned into a call into StringFactory.newEmptyString();
+ // Move the StringFactory.newEmptyString() result into the destination register.
+ DCHECK(value.GetL()->IsString());
+ shadow_frame->SetVRegReference(instr->VRegA_21c(), value.GetL());
+ // new-instance doesn't generate a result value.
+ value.SetJ(0);
+ // Skip the dex instruction since we essentially come back from an invocation.
+ new_dex_pc = dex_pc + instr->SizeInCodeUnits();
if (kIsDebugBuild) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ // This is a suspend point. But it's ok since value has been set into shadow_frame.
mirror::Class* klass = class_linker->ResolveType(
instr->VRegB_21c(), shadow_frame->GetMethod());
DCHECK(klass->IsStringClass());
}
- // Skip the dex instruction since we essentially come back from an invocation.
- new_dex_pc = dex_pc + instr->SizeInCodeUnits();
} else {
- DCHECK(false) << "Unexpected instruction opcode " << instr->Opcode()
- << " at dex_pc " << dex_pc
- << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false);
+ CHECK(false) << "Unexpected instruction opcode " << instr->Opcode()
+ << " at dex_pc " << dex_pc
+ << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false);
}
} else {
// Nothing to do, the dex_pc is the one at which the code requested
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 12d70c5244..53d5e43989 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -540,6 +540,30 @@ void ArtInterpreterToCompiledCodeBridge(Thread* self,
result, method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty());
}
+void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
+ uint16_t this_obj_vreg,
+ JValue result)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ Object* existing = shadow_frame->GetVRegReference(this_obj_vreg);
+ if (existing == nullptr) {
+ // If it's null, we come from compiled code that was deoptimized. Nothing to do,
+ // as the compiler verified there was no alias.
+ // Set the new string result of the StringFactory.
+ shadow_frame->SetVRegReference(this_obj_vreg, result.GetL());
+ return;
+ }
+ // Set the string init result into all aliases.
+ for (uint32_t i = 0, e = shadow_frame->NumberOfVRegs(); i < e; ++i) {
+ if (shadow_frame->GetVRegReference(i) == existing) {
+ DCHECK_EQ(shadow_frame->GetVRegReference(i),
+ reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
+ shadow_frame->SetVRegReference(i, result.GetL());
+ DCHECK_EQ(shadow_frame->GetVRegReference(i),
+ reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
+ }
+ }
+}
+
template <bool is_range,
bool do_assignability_check,
size_t kVarArgMax>
@@ -739,24 +763,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
}
if (string_init && !self->IsExceptionPending()) {
- mirror::Object* existing = shadow_frame.GetVRegReference(string_init_vreg_this);
- if (existing == nullptr) {
- // If it's null, we come from compiled code that was deoptimized. Nothing to do,
- // as the compiler verified there was no alias.
- // Set the new string result of the StringFactory.
- shadow_frame.SetVRegReference(string_init_vreg_this, result->GetL());
- } else {
- // Replace the fake string that was allocated with the StringFactory result.
- for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
- if (shadow_frame.GetVRegReference(i) == existing) {
- DCHECK_EQ(shadow_frame.GetVRegReference(i),
- reinterpret_cast<mirror::Object*>(shadow_frame.GetVReg(i)));
- shadow_frame.SetVRegReference(i, result->GetL());
- DCHECK_EQ(shadow_frame.GetVRegReference(i),
- reinterpret_cast<mirror::Object*>(shadow_frame.GetVReg(i)));
- }
- }
- }
+ SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result);
}
return !self->IsExceptionPending();
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 69376fd7a1..cc470f372b 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -1021,6 +1021,12 @@ void ArtInterpreterToCompiledCodeBridge(Thread* self,
ShadowFrame* shadow_frame,
JValue* result);
+// Set string value created from StringFactory.newStringFromXXX() into all aliases of
+// StringFactory.newEmptyString().
+void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
+ uint16_t this_obj_vreg,
+ JValue result);
+
// Explicitly instantiate all DoInvoke functions.
#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check) \
template SHARED_REQUIRES(Locks::mutator_lock_) \
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index b0a786e9e3..c5d3ccd748 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -35,6 +35,8 @@ namespace art {
// with all profile savers running at the same time.
static constexpr const uint64_t kMinSavePeriodNs = MsToNs(20 * 1000); // 20 seconds
static constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000; // 2 seconds
+// Minimum number of JIT samples during launch to include a method into the profile.
+static constexpr const size_t kStartupMethodSamples = 1;
static constexpr const uint32_t kMinimumNumberOfMethodsToSave = 10;
static constexpr const uint32_t kMinimumNumberOfClassesToSave = 10;
@@ -108,7 +110,7 @@ void ProfileSaver::Run() {
}
total_ms_of_sleep_ += kSaveResolvedClassesDelayMs;
}
- FetchAndCacheResolvedClasses();
+ FetchAndCacheResolvedClassesAndMethods();
// Loop for the profiled methods.
while (!ShuttingDown(self)) {
@@ -204,11 +206,48 @@ ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& f
return &info_it->second;
}
-void ProfileSaver::FetchAndCacheResolvedClasses() {
+// Get resolved methods that have a profile info or more than kStartupMethodSamples samples.
+// Excludes native methods and classes in the boot image.
+class GetMethodsVisitor : public ClassVisitor {
+ public:
+ explicit GetMethodsVisitor(std::vector<MethodReference>* methods) : methods_(methods) {}
+
+ virtual bool operator()(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) {
+ if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
+ return true;
+ }
+ for (ArtMethod& method : klass->GetMethods(sizeof(void*))) {
+ if (!method.IsNative()) {
+ if (method.GetCounter() >= kStartupMethodSamples ||
+ method.GetProfilingInfo(sizeof(void*)) != nullptr) {
+ // Have samples, add to profile.
+ const DexFile* dex_file = method.GetInterfaceMethodIfProxy(sizeof(void*))->GetDexFile();
+ methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex()));
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ std::vector<MethodReference>* const methods_;
+};
+
+void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
ScopedTrace trace(__PRETTY_FUNCTION__);
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
std::set<DexCacheResolvedClasses> resolved_classes =
class_linker->GetResolvedClasses(/*ignore boot classes*/ true);
+
+ std::vector<MethodReference> methods;
+ {
+ ScopedTrace trace2("Get hot methods");
+ GetMethodsVisitor visitor(&methods);
+ ScopedObjectAccess soa(Thread::Current());
+ class_linker->VisitClasses(&visitor);
+ VLOG(profiler) << "Methods with samples greater than "
+ << kStartupMethodSamples << " = " << methods.size();
+ }
MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
uint64_t total_number_of_profile_entries_cached = 0;
@@ -216,11 +255,16 @@ void ProfileSaver::FetchAndCacheResolvedClasses() {
std::set<DexCacheResolvedClasses> resolved_classes_for_location;
const std::string& filename = it.first;
const std::set<std::string>& locations = it.second;
-
+ std::vector<MethodReference> methods_for_location;
+ for (const MethodReference& ref : methods) {
+ if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
+ methods_for_location.push_back(ref);
+ }
+ }
for (const DexCacheResolvedClasses& classes : resolved_classes) {
if (locations.find(classes.GetBaseLocation()) != locations.end()) {
- VLOG(profiler) << "Added classes for location " << classes.GetBaseLocation()
- << " (" << classes.GetDexLocation() << ")";
+ VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location "
+ << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")";
resolved_classes_for_location.insert(classes);
} else {
VLOG(profiler) << "Location not found " << classes.GetBaseLocation()
@@ -228,7 +272,7 @@ void ProfileSaver::FetchAndCacheResolvedClasses() {
}
}
ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
- info->AddMethodsAndClasses(std::vector<MethodReference>(), resolved_classes_for_location);
+ info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location);
total_number_of_profile_entries_cached += resolved_classes_for_location.size();
}
max_number_of_profile_entries_cached_ = std::max(
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index c6da95931c..9c6d0fa1cf 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -95,9 +95,9 @@ class ProfileSaver {
// If no entry exists, a new empty one will be created, added to the cache and
// then returned.
ProfileCompilationInfo* GetCachedProfiledInfo(const std::string& filename);
- // Fetches the current resolved classes from the ClassLinker and stores them
- // in the profile_cache_ for later save.
- void FetchAndCacheResolvedClasses();
+ // Fetches the current resolved classes and methods from the ClassLinker and stores them in the
+ // profile_cache_ for later save.
+ void FetchAndCacheResolvedClassesAndMethods();
static bool MaybeRecordDexUseInternal(
const std::string& dex_location,
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 2da3d8479c..2894b68f03 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -148,9 +148,7 @@ inline void DexCache::FixupStrings(GcRoot<mirror::String>* dest, const Visitor&
for (size_t i = 0, count = NumStrings(); i < count; ++i) {
mirror::String* source = src[i].Read<kReadBarrierOption>();
mirror::String* new_source = visitor(source);
- if (source != new_source) {
- dest[i] = GcRoot<mirror::String>(new_source);
- }
+ dest[i] = GcRoot<mirror::String>(new_source);
}
}
@@ -160,9 +158,7 @@ inline void DexCache::FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visi
for (size_t i = 0, count = NumResolvedTypes(); i < count; ++i) {
mirror::Class* source = src[i].Read<kReadBarrierOption>();
mirror::Class* new_source = visitor(source);
- if (source != new_source) {
- dest[i] = GcRoot<mirror::Class>(new_source);
- }
+ dest[i] = GcRoot<mirror::Class>(new_source);
}
}
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index a64a6dfb3d..28fd9b98cd 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -153,7 +153,7 @@ bool OatFileAssistant::OdexFileCompilerFilterIsOkay(CompilerFilter::Filter targe
}
OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target) {
- bool compilation_desired = CompilerFilter::IsCompilationEnabled(target);
+ bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
// See if the oat file is in good shape as is.
bool oat_okay = OatFileCompilerFilterIsOkay(target);
@@ -573,7 +573,7 @@ bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
- if (CompilerFilter::IsCompilationEnabled(current_compiler_filter)) {
+ if (CompilerFilter::IsBytecodeCompilationEnabled(current_compiler_filter)) {
if (!file.IsPic()) {
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 78ed5893de..ccab48cdc5 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -233,7 +233,7 @@ class OatFileAssistantTest : public CommonRuntimeTest {
EXPECT_TRUE(odex_file->HasPatchInfo());
EXPECT_EQ(filter, odex_file->GetCompilerFilter());
- if (CompilerFilter::IsCompilationEnabled(filter)) {
+ if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
const std::vector<gc::space::ImageSpace*> image_spaces =
runtime->GetHeap()->GetBootImageSpaces();
ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr);
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 1f33651243..ba71dc3c6e 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -58,11 +58,6 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
-#ifdef __ANDROID__
-// This function is provided by android linker.
-extern "C" void android_update_LD_LIBRARY_PATH(const char* ld_library_path);
-#endif // __ANDROID__
-
#undef LOG_TAG
#define LOG_TAG "artopenjdk"
@@ -324,22 +319,6 @@ JNIEXPORT __attribute__((noreturn)) void JVM_Exit(jint status) {
exit(status);
}
-static void SetLdLibraryPath(JNIEnv* env, jstring javaLdLibraryPath) {
-#ifdef __ANDROID__
- if (javaLdLibraryPath != nullptr) {
- ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath);
- if (ldLibraryPath.c_str() != nullptr) {
- android_update_LD_LIBRARY_PATH(ldLibraryPath.c_str());
- }
- }
-
-#else
- LOG(WARNING) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!";
- UNUSED(javaLdLibraryPath, env);
-#endif
-}
-
-
JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
jstring javaFilename,
jobject javaLoader,
@@ -349,17 +328,6 @@ JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
return NULL;
}
- int32_t target_sdk_version = art::Runtime::Current()->GetTargetSdkVersion();
-
- // Starting with N nativeLoad uses classloader local
- // linker namespace instead of global LD_LIBRARY_PATH
- // (23 is Marshmallow). This call is here to preserve
- // backwards compatibility for the apps targeting sdk
- // version <= 23
- if (target_sdk_version == 0) {
- SetLdLibraryPath(env, javaLibrarySearchPath);
- }
-
std::string error_msg;
{
art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 2b96328f80..b2be770bf7 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4652,7 +4652,7 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType&
if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
<< " from other class " << GetDeclaringClass();
- return;
+ // Keep hunting for possible hard fails.
}
}
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index 0dab4007a7..c6a2e9a5a8 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -55,7 +55,7 @@ class NoPatchoatTest {
const OatFile* oat_file = oat_dex_file->GetOatFile();
return !oat_file->IsPic()
- && CompilerFilter::IsCompilationEnabled(oat_file->GetCompilerFilter());
+ && CompilerFilter::IsBytecodeCompilationEnabled(oat_file->GetCompilerFilter());
}
};
diff --git a/test/597-deopt-new-string/src/Main.java b/test/597-deopt-new-string/src/Main.java
index 1224e407b0..e78f0d36ec 100644
--- a/test/597-deopt-new-string/src/Main.java
+++ b/test/597-deopt-new-string/src/Main.java
@@ -48,7 +48,12 @@ public class Main implements Runnable {
throw new Error();
}
char[] arr = {'a', 'b', 'c'};
- return new String(arr, 0, arr.length);
+ String str = new String(arr, 0, arr.length);
+ if (!str.equals("abc")) {
+ System.out.println("Failure 1! " + str);
+ System.exit(0);
+ }
+ return str;
}
public void run() {
@@ -68,7 +73,11 @@ public class Main implements Runnable {
} else {
// This thread keeps doing new String() from a char array.
while (!done) {
- $noinline$run0();
+ String str = $noinline$run0();
+ if (!str.equals("abc")) {
+ System.out.println("Failure 2! " + str);
+ System.exit(0);
+ }
}
}
}
diff --git a/test/600-verifier-fails/expected.txt b/test/600-verifier-fails/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/600-verifier-fails/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/600-verifier-fails/info.txt b/test/600-verifier-fails/info.txt
new file mode 100644
index 0000000000..478dd9bceb
--- /dev/null
+++ b/test/600-verifier-fails/info.txt
@@ -0,0 +1,4 @@
+The situation in this test was discovered by running dexfuzz on
+another fuzzingly random generated Java test. The soft verification
+fail (on the final field modification) should not hide the hard
+verification fail (on the type mismatch) to avoid a crash later on.
diff --git a/test/600-verifier-fails/smali/sput.smali b/test/600-verifier-fails/smali/sput.smali
new file mode 100644
index 0000000000..87f3799e02
--- /dev/null
+++ b/test/600-verifier-fails/smali/sput.smali
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LA;
+.super Ljava/lang/Object;
+
+.method public foo(I)V
+.registers 2
+ sput v1, LMain;->staticField:Ljava/lang/String;
+ return-void
+.end method
diff --git a/test/600-verifier-fails/src/Main.java b/test/600-verifier-fails/src/Main.java
new file mode 100644
index 0000000000..ba4cc31ad7
--- /dev/null
+++ b/test/600-verifier-fails/src/Main.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+ public static final String staticField = null;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Class<?> a = Class.forName("A");
+ } catch (java.lang.VerifyError e) {
+ System.out.println("passed");
+ }
+ }
+}