Merge "ART: Add GetClassLoaderClasses"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 5bdfbc7..392f044 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -120,14 +120,14 @@
ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
$(HOST_CORE_IMAGE_optimizing_pic_64) \
$(HOST_CORE_IMAGE_optimizing_pic_32) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_optimizing_pic_multi_64) \
+ $(HOST_CORE_IMAGE_optimizing_pic_multi_32) \
$(HOST_OUT_EXECUTABLES)/patchoatd
ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_optimizing_pic_64) \
$(TARGET_CORE_IMAGE_optimizing_pic_32) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_optimizing_pic_multi_64) \
+ $(TARGET_CORE_IMAGE_optimizing_pic_multi_32) \
$(TARGET_OUT_EXECUTABLES)/patchoatd
ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index e41d9bd..28c009e 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -770,8 +770,6 @@
existing = existing | ExperimentalFlags::kAgents;
} else if (option == "runtime-plugins") {
existing = existing | ExperimentalFlags::kRuntimePlugins;
- } else if (option == "method-handles") {
- existing = existing | ExperimentalFlags::kMethodHandles;
} else {
return Result::Failure(std::string("Unknown option '") + option + "'");
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 2950266..5da59f3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1950,66 +1950,82 @@
DCHECK(!it.HasNext());
}
-void CompilerDriver::Verify(jobject jclass_loader,
- const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
+bool CompilerDriver::FastVerify(jobject jclass_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
verifier::VerifierDeps* verifier_deps =
Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
// If there is an existing `VerifierDeps`, try to use it for fast verification.
- if (verifier_deps != nullptr) {
- TimingLogger::ScopedTiming t("Fast Verify", timings);
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
- MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (verifier_deps->ValidateDependencies(class_loader, soa.Self())) {
- // We successfully validated the dependencies, now update class status
- // of verified classes. Note that the dependencies also record which classes
- // could not be fully verified; we could try again, but that would hurt verification
- // time. So instead we assume these classes still need to be verified at
- // runtime.
- for (const DexFile* dex_file : dex_files) {
- // Fetch the list of unverified classes and turn it into a set for faster
- // lookups.
- const std::vector<dex::TypeIndex>& unverified_classes =
- verifier_deps->GetUnverifiedClasses(*dex_file);
- std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
- for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
- if (set.find(class_def.class_idx_) == set.end()) {
- if (!GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
- // Just update the compiled_classes_ map. The compiler doesn't need to resolve
- // the type.
- compiled_classes_.Overwrite(
- ClassReference(dex_file, i), new CompiledClass(mirror::Class::kStatusVerified));
- } else {
- // Resolve the type, so later compilation stages know they don't need to verify
- // the class.
- const char* descriptor = dex_file->GetClassDescriptor(class_def);
- cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
- if (cls.Get() != nullptr) {
- ObjectLock<mirror::Class> lock(soa.Self(), cls);
- mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
- } else {
- DCHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- }
- // Create `VerifiedMethod`s for each methods, the compiler expects one for
- // quickening or compiling.
- // Note that this means:
- // - We're only going to compile methods that did verify.
- // - Quickening will not do checkcast ellision.
- // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
- PopulateVerifiedMethods(*dex_file, i, verification_results_);
+ if (verifier_deps == nullptr) {
+ return false;
+ }
+ TimingLogger::ScopedTiming t("Fast Verify", timings);
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
+ MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (!verifier_deps->ValidateDependencies(class_loader, soa.Self())) {
+ return false;
+ }
+
+ // We successfully validated the dependencies, now update class status
+ // of verified classes. Note that the dependencies also record which classes
+ // could not be fully verified; we could try again, but that would hurt verification
+ // time. So instead we assume these classes still need to be verified at
+ // runtime.
+ for (const DexFile* dex_file : dex_files) {
+ // Fetch the list of unverified classes and turn it into a set for faster
+ // lookups.
+ const std::vector<dex::TypeIndex>& unverified_classes =
+ verifier_deps->GetUnverifiedClasses(*dex_file);
+ std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ if (set.find(class_def.class_idx_) == set.end()) {
+ if (!GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+ // Just update the compiled_classes_ map. The compiler doesn't need to resolve
+ // the type.
+ compiled_classes_.Overwrite(
+ ClassReference(dex_file, i), new CompiledClass(mirror::Class::kStatusVerified));
+ } else {
+ // Resolve the type, so later compilation stages know they don't need to verify
+ // the class.
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
+ if (cls.Get() != nullptr) {
+ // Check that the class is resolved with the current dex file. We might get
+ // a boot image class, or a class in a different dex file for multidex, and
+ // we should not update the status in that case.
+ if (&cls->GetDexFile() == dex_file) {
+ ObjectLock<mirror::Class> lock(soa.Self(), cls);
+ mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
}
+ } else {
+ DCHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
}
+ // Create `VerifiedMethod`s for each methods, the compiler expects one for
+ // quickening or compiling.
+ // Note that this means:
+ // - We're only going to compile methods that did verify.
+ // - Quickening will not do checkcast ellision.
+ // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
+ PopulateVerifiedMethods(*dex_file, i, verification_results_);
}
}
- return;
}
}
+ return true;
+}
+
+void CompilerDriver::Verify(jobject jclass_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ if (FastVerify(jclass_loader, dex_files, timings)) {
+ return;
+ }
// If there is no existing `verifier_deps` (because of non-existing vdex), or
// the existing `verifier_deps` is not valid anymore, create a new one for
@@ -2017,7 +2033,7 @@
// Then dex2oat can update the vdex file with these new dependencies.
if (!GetCompilerOptions().IsBootImage()) {
// Create the main VerifierDeps, and set it to this thread.
- verifier_deps = new verifier::VerifierDeps(dex_files);
+ verifier::VerifierDeps* verifier_deps = new verifier::VerifierDeps(dex_files);
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(verifier_deps);
Thread::Current()->SetVerifierDeps(verifier_deps);
// Create per-thread VerifierDeps to avoid contention on the main one.
@@ -2026,6 +2042,7 @@
worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files));
}
}
+
// Note: verification should not be pulling in classes anymore when compiling the boot image,
// as all should have been resolved before. As such, doing this in parallel should still
// be deterministic.
@@ -2041,6 +2058,7 @@
if (!GetCompilerOptions().IsBootImage()) {
// Merge all VerifierDeps into the main one.
+ verifier::VerifierDeps* verifier_deps = Thread::Current()->GetVerifierDeps();
for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
worker->GetThread()->SetVerifierDeps(nullptr);
@@ -2061,7 +2079,10 @@
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *manager_->GetDexFile();
if (!manager_->GetCompiler()->ShouldVerifyClassBasedOnProfile(dex_file, class_def_index)) {
- // Skip verification since the class is not in the profile.
+ // Skip verification since the class is not in the profile, and let the VerifierDeps know
+ // that the class will need to be verified at runtime.
+ verifier::VerifierDeps::MaybeRecordVerificationStatus(
+ dex_file, dex::TypeIndex(class_def_index), verifier::MethodVerifier::kSoftFailure);
return;
}
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 2e3b7c8..6bfdd4d 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -433,12 +433,18 @@
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_);
+ // Do fast verification through VerifierDeps if possible. Return whether
+ // verification was successful.
// NO_THREAD_SAFETY_ANALYSIS as the method accesses a guarded value in a
// single-threaded way.
+ bool FastVerify(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings)
+ NO_THREAD_SAFETY_ANALYSIS;
+
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings)
- NO_THREAD_SAFETY_ANALYSIS;
+ TimingLogger* timings);
void VerifyDexFile(jobject class_loader,
const DexFile& dex_file,
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index f896f11..8cf4089 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -63,7 +63,8 @@
driver,
interpreter_metadata,
compiler_stats,
- dex_cache) {}
+ dex_cache,
+ handles) {}
// Only for unit testing.
HGraphBuilder(HGraph* graph,
@@ -90,7 +91,8 @@
/* compiler_driver */ nullptr,
/* interpreter_metadata */ nullptr,
/* compiler_stats */ nullptr,
- null_dex_cache_) {}
+ null_dex_cache_,
+ handles) {}
GraphAnalysisResult BuildGraph();
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 6c680c8..70c2738 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -936,10 +936,10 @@
if (environment->GetParent() != nullptr) {
// We emit the parent environment first.
EmitEnvironment(environment->GetParent(), slow_path);
- stack_map_stream_.BeginInlineInfoEntry(environment->GetMethodIdx(),
+ stack_map_stream_.BeginInlineInfoEntry(environment->GetMethod(),
environment->GetDexPc(),
- environment->GetInvokeType(),
- environment->Size());
+ environment->Size(),
+ &graph_->GetDexFile());
}
// Walk over the environment, and record the location of dex registers.
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index ef4bd1e..07b1746 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -5770,7 +5770,9 @@
locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -5821,8 +5823,9 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
@@ -5842,7 +5845,7 @@
case HLoadClass::LoadKind::kJitTableAddress: {
__ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
cls->GetTypeIndex(),
- cls->GetAddress()));
+ cls->GetClass()));
// /* GcRoot<mirror::Class> */ out = *out
GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
break;
@@ -7348,8 +7351,9 @@
Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
dex::TypeIndex type_index,
- uint64_t address) {
- jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index), address);
+ Handle<mirror::Class> handle) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
+ reinterpret_cast64<uint64_t>(handle.GetReference()));
return jit_class_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index bd237e9..52d1857 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -496,7 +496,7 @@
Handle<mirror::String> handle);
Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
dex::TypeIndex type_index,
- uint64_t address);
+ Handle<mirror::Class> handle);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9617e1..b094e54 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4013,7 +4013,7 @@
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
// Add ADRP with its PC-relative DexCache access patch.
- const DexFile& dex_file = invoke->GetDexFile();
+ const DexFile& dex_file = invoke->GetDexFileForPcRelativeDexCache();
uint32_t element_offset = invoke->GetDexCacheArrayOffset();
vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
@@ -4181,8 +4181,9 @@
}
vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateJitClassLiteral(
- const DexFile& dex_file, dex::TypeIndex type_index, uint64_t address) {
- jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index), address);
+ const DexFile& dex_file, dex::TypeIndex type_index, Handle<mirror::Class> handle) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
+ reinterpret_cast64<uint64_t>(handle.GetReference()));
return jit_class_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
@@ -4377,7 +4378,9 @@
locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -4426,8 +4429,10 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- DCHECK(cls->GetAddress() != 0u && IsUint<32>(cls->GetAddress()));
- __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(cls->GetAddress()));
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
+ __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
case HLoadClass::LoadKind::kBssEntry: {
@@ -4452,7 +4457,7 @@
case HLoadClass::LoadKind::kJitTableAddress: {
__ Ldr(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
cls->GetTypeIndex(),
- cls->GetAddress()));
+ cls->GetClass()));
GenerateGcRootFieldLoad(cls,
out_loc,
out.X(),
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index c7a0614..a9dca92 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -579,7 +579,7 @@
Handle<mirror::String> handle);
vixl::aarch64::Literal<uint32_t>* DeduplicateJitClassLiteral(const DexFile& dex_file,
dex::TypeIndex string_index,
- uint64_t address);
+ Handle<mirror::Class> handle);
void EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label, vixl::aarch64::Register reg);
void EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 83c289e..05a76e1 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -5846,7 +5846,9 @@
locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -5892,8 +5894,9 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ Ldr(out, codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
@@ -5908,7 +5911,7 @@
case HLoadClass::LoadKind::kJitTableAddress: {
__ Ldr(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
cls->GetTypeIndex(),
- cls->GetAddress()));
+ cls->GetClass()));
// /* GcRoot<mirror::Class> */ out = *out
GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
break;
@@ -7466,8 +7469,9 @@
VIXLUInt32Literal* CodeGeneratorARMVIXL::DeduplicateJitClassLiteral(const DexFile& dex_file,
dex::TypeIndex type_index,
- uint64_t address) {
- jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index), address);
+ Handle<mirror::Class> handle) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
+ reinterpret_cast64<uint64_t>(handle.GetReference()));
return jit_class_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() {
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 0f0a954..be65353 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -579,7 +579,7 @@
Handle<mirror::String> handle);
VIXLUInt32Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
dex::TypeIndex type_index,
- uint64_t address);
+ Handle<mirror::Class> handle);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 1f4ff27..24234e1 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5490,7 +5490,9 @@
locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -5548,8 +5550,9 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK(!kEmitCompilerReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ LoadLiteral(out,
base_or_current_method_reg,
codegen_->DeduplicateBootImageAddressLiteral(address));
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index a350de7..fc8fb7a 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3395,7 +3395,7 @@
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
uint32_t offset = invoke->GetDexCacheArrayOffset();
CodeGeneratorMIPS64::PcRelativePatchInfo* info =
- NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset);
+ NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
EmitPcRelativeAddressPlaceholderHigh(info, AT);
__ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
break;
@@ -3524,7 +3524,9 @@
locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -3569,8 +3571,9 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK(!kEmitCompilerReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ LoadLiteral(out,
kLoadUnsignedWord,
codegen_->DeduplicateBootImageAddressLiteral(address));
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index a850d38..cc727d2 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4521,7 +4521,7 @@
__ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
// Bind a new fixup label at the end of the "movl" insn.
uint32_t offset = invoke->GetDexCacheArrayOffset();
- __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
+ __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset));
break;
}
case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
@@ -6055,15 +6055,18 @@
Label* CodeGeneratorX86::NewJitRootClassPatch(const DexFile& dex_file,
dex::TypeIndex dex_index,
- uint64_t address) {
- jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index), address);
+ Handle<mirror::Class> handle) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index),
+ reinterpret_cast64<uint64_t>(handle.GetReference()));
// Add a patch entry and return the label.
jit_class_patches_.emplace_back(dex_file, dex_index.index_);
PatchInfo<Label>* info = &jit_class_patches_.back();
return &info->label;
}
-void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -6110,8 +6113,9 @@
}
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ movl(out, Immediate(address));
codegen_->RecordSimplePatch();
break;
@@ -6127,7 +6131,7 @@
case HLoadClass::LoadKind::kJitTableAddress: {
Address address = Address::Absolute(CodeGeneratorX86::kDummy32BitOffset);
Label* fixup_label = codegen_->NewJitRootClassPatch(
- cls->GetDexFile(), cls->GetTypeIndex(), cls->GetAddress());
+ cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
// /* GcRoot<mirror::Class> */ out = *address
GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, kCompilerReadBarrierOption);
break;
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index b86d080..9eb9765 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -419,7 +419,9 @@
Label* NewJitRootStringPatch(const DexFile& dex_file,
dex::StringIndex dex_index,
Handle<mirror::String> handle);
- Label* NewJitRootClassPatch(const DexFile& dex_file, dex::TypeIndex dex_index, uint64_t address);
+ Label* NewJitRootClassPatch(const DexFile& dex_file,
+ dex::TypeIndex dex_index,
+ Handle<mirror::Class> handle);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 2691af8..9adedab 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -991,7 +991,7 @@
Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
// Bind a new fixup label at the end of the "movl" insn.
uint32_t offset = invoke->GetDexCacheArrayOffset();
- __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
+ __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset));
break;
}
case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
@@ -5482,15 +5482,18 @@
Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
dex::TypeIndex dex_index,
- uint64_t address) {
- jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index), address);
+ Handle<mirror::Class> handle) {
+ jit_class_roots_.Overwrite(
+ TypeReference(&dex_file, dex_index), reinterpret_cast64<uint64_t>(handle.GetReference()));
// Add a patch entry and return the label.
jit_class_patches_.emplace_back(dex_file, dex_index.index_);
PatchInfo<Label>* info = &jit_class_patches_.back();
return &info->label;
}
-void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
+// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
+// move.
+void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
codegen_->GenerateLoadClassRuntimeCall(cls);
@@ -5528,8 +5531,9 @@
break;
case HLoadClass::LoadKind::kBootImageAddress: {
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ uint32_t address = dchecked_integral_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
+ DCHECK_NE(address, 0u);
__ movl(out, Immediate(address)); // Zero-extended.
codegen_->RecordSimplePatch();
break;
@@ -5547,7 +5551,7 @@
Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
/* no_rip */ true);
Label* fixup_label =
- codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetAddress());
+ codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetClass());
// /* GcRoot<mirror::Class> */ out = *address
GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, kCompilerReadBarrierOption);
break;
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 8b3ab4c..3438b81 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -416,7 +416,9 @@
Label* NewJitRootStringPatch(const DexFile& dex_file,
dex::StringIndex dex_index,
Handle<mirror::String> handle);
- Label* NewJitRootClassPatch(const DexFile& dex_file, dex::TypeIndex dex_index, uint64_t address);
+ Label* NewJitRootClassPatch(const DexFile& dex_file,
+ dex::TypeIndex dex_index,
+ Handle<mirror::Class> handle);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc
index a3140d0..9ddcd56 100644
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc
@@ -64,9 +64,10 @@
// we need to add the dex cache arrays base as the special input.
if (invoke->HasPcRelativeDexCache() &&
!IsCallFreeIntrinsic<IntrinsicLocationsBuilderARMType>(invoke, codegen_)) {
- HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
+ HArmDexCacheArraysBase* base =
+ GetOrCreateDexCacheArrayBase(invoke->GetDexFileForPcRelativeDexCache());
// Update the element offset in base.
- DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFile());
+ DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFileForPcRelativeDexCache());
base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
// Add the special argument base to the method.
DCHECK(!invoke->HasCurrentMethodInput());
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc
index 9a34f54..04a4294 100644
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_mips.cc
@@ -59,9 +59,10 @@
if (invoke->HasPcRelativeDexCache() &&
!IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) {
// Initialize base for target method dex file if needed.
- HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
+ HMipsDexCacheArraysBase* base =
+ GetOrCreateDexCacheArrayBase(invoke->GetDexFileForPcRelativeDexCache());
// Update the element offset in base.
- DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFile());
+ DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFileForPcRelativeDexCache());
base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
// Add the special argument base to the method.
DCHECK(!invoke->HasCurrentMethodInput());
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index d7da46b..50aa442 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -474,10 +474,10 @@
HInstruction* receiver = invoke_instruction->InputAt(0);
HInstruction* cursor = invoke_instruction->GetPrevious();
HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
- Handle<mirror::Class> handle = handles_->NewHandle(GetMonomorphicType(classes));
+ Handle<mirror::Class> monomorphic_type = handles_->NewHandle(GetMonomorphicType(classes));
if (!TryInlineAndReplace(invoke_instruction,
resolved_method,
- ReferenceTypeInfo::Create(handle, /* is_exact */ true),
+ ReferenceTypeInfo::Create(monomorphic_type, /* is_exact */ true),
/* do_rtp */ false,
/* cha_devirtualize */ false)) {
return false;
@@ -488,7 +488,7 @@
cursor,
bb_cursor,
class_index,
- GetMonomorphicType(classes),
+ monomorphic_type,
invoke_instruction,
/* with_deoptimization */ true);
@@ -533,11 +533,9 @@
HInstruction* cursor,
HBasicBlock* bb_cursor,
dex::TypeIndex class_index,
- mirror::Class* klass,
+ Handle<mirror::Class> klass,
HInstruction* invoke_instruction,
bool with_deoptimization) {
- ScopedAssertNoThreadSuspension sants("Adding compiler type guard");
-
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
class_linker, receiver, invoke_instruction->GetDexPc());
@@ -548,19 +546,20 @@
}
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
- bool is_referrer = (klass == outermost_graph_->GetArtMethod()->GetDeclaringClass());
+ bool is_referrer = (klass.Get() == outermost_graph_->GetArtMethod()->GetDeclaringClass());
// Note that we will just compare the classes, so we don't need Java semantics access checks.
// Note that the type index and the dex file are relative to the method this type guard is
// inlined into.
HLoadClass* load_class = new (graph_->GetArena()) HLoadClass(graph_->GetCurrentMethod(),
class_index,
caller_dex_file,
+ klass,
is_referrer,
invoke_instruction->GetDexPc(),
/* needs_access_check */ false);
bb_cursor->InsertInstructionAfter(load_class, receiver_class);
// Sharpen after adding the instruction, as the sharpening may remove inputs.
- HSharpening::SharpenClass(load_class, klass, handles_, codegen_, compiler_driver_);
+ HSharpening::SharpenClass(load_class, codegen_, compiler_driver_);
// TODO: Extend reference type propagation to understand the guard.
HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class);
@@ -637,7 +636,7 @@
cursor,
bb_cursor,
class_index,
- handle.Get(),
+ handle,
invoke_instruction,
deoptimize);
if (deoptimize) {
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 4c0b990..11aacab 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -170,7 +170,7 @@
HInstruction* cursor,
HBasicBlock* bb_cursor,
dex::TypeIndex class_index,
- mirror::Class* klass,
+ Handle<mirror::Class> klass,
HInstruction* invoke_instruction,
bool with_deoptimization)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 3cfabdd..8ed0e7f 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -208,10 +208,8 @@
HEnvironment* environment = new (arena_) HEnvironment(
arena_,
current_locals_->size(),
- graph_->GetDexFile(),
- graph_->GetMethodIdx(),
+ graph_->GetArtMethod(),
instruction->GetDexPc(),
- graph_->GetInvokeType(),
instruction);
environment->CopyFrom(*current_locals_);
instruction->SetRawEnvironment(environment);
@@ -936,48 +934,40 @@
bool HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
- Handle<mirror::Class> resolved_class(hs.NewHandle(dex_cache->GetResolvedType(type_index)));
- const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
Handle<mirror::DexCache> outer_dex_cache = outer_compilation_unit_->GetDexCache();
- bool finalizable;
- bool needs_access_check = NeedsAccessCheck(type_index, dex_cache, &finalizable);
-
- // Only the access check entrypoint handles the finalizable class case. If we
- // need access checks, then we haven't resolved the method and the class may
- // again be finalizable.
- QuickEntrypointEnum entrypoint = (finalizable || needs_access_check)
- ? kQuickAllocObjectWithChecks
- : kQuickAllocObjectInitialized;
-
if (outer_dex_cache.Get() != dex_cache.Get()) {
// We currently do not support inlining allocations across dex files.
return false;
}
- HLoadClass* load_class = new (arena_) HLoadClass(
- graph_->GetCurrentMethod(),
- type_index,
- outer_dex_file,
- IsOutermostCompilingClass(type_index),
- dex_pc,
- needs_access_check);
+ HLoadClass* load_class = BuildLoadClass(type_index, dex_pc, /* check_access */ true);
- AppendInstruction(load_class);
HInstruction* cls = load_class;
- if (!IsInitialized(resolved_class)) {
+ Handle<mirror::Class> klass = load_class->GetClass();
+
+ if (!IsInitialized(klass)) {
cls = new (arena_) HClinitCheck(load_class, dex_pc);
AppendInstruction(cls);
}
+ // Only the access check entrypoint handles the finalizable class case. If we
+ // need access checks, then we haven't resolved the method and the class may
+ // again be finalizable.
+ QuickEntrypointEnum entrypoint = kQuickAllocObjectInitialized;
+ if (load_class->NeedsAccessCheck() || klass->IsFinalizable() || !klass->IsInstantiable()) {
+ entrypoint = kQuickAllocObjectWithChecks;
+ }
+
+ // Consider classes we haven't resolved as potentially finalizable.
+ bool finalizable = (klass.Get() == nullptr) || klass->IsFinalizable();
+
AppendInstruction(new (arena_) HNewInstance(
cls,
dex_pc,
type_index,
*dex_compilation_unit_->GetDexFile(),
- needs_access_check,
finalizable,
entrypoint));
return true;
@@ -1018,7 +1008,6 @@
ArtMethod* resolved_method,
uint32_t method_idx,
HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) {
- const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
Thread* self = Thread::Current();
StackHandleScope<2> hs(self);
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1046,15 +1035,9 @@
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
} else if (storage_index.IsValid()) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
- HLoadClass* load_class = new (arena_) HLoadClass(
- graph_->GetCurrentMethod(),
- storage_index,
- outer_dex_file,
- is_outer_class,
- dex_pc,
- /*needs_access_check*/ false);
- AppendInstruction(load_class);
- clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
+ HLoadClass* cls = BuildLoadClass(
+ storage_index, dex_pc, /* check_access */ false, /* outer */ true);
+ clinit_check = new (arena_) HClinitCheck(cls, dex_pc);
AppendInstruction(clinit_check);
}
return clinit_check;
@@ -1376,7 +1359,6 @@
}
Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
- const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
Handle<mirror::DexCache> outer_dex_cache = outer_compilation_unit_->GetDexCache();
Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
@@ -1404,16 +1386,10 @@
}
}
- HLoadClass* constant = new (arena_) HLoadClass(graph_->GetCurrentMethod(),
- storage_index,
- outer_dex_file,
- is_outer_class,
- dex_pc,
- /*needs_access_check*/ false);
- AppendInstruction(constant);
+ HLoadClass* constant = BuildLoadClass(
+ storage_index, dex_pc, /* check_access */ false, /* outer */ true);
HInstruction* cls = constant;
-
Handle<mirror::Class> klass(hs.NewHandle(resolved_field->GetDeclaringClass()));
if (!IsInitialized(klass)) {
cls = new (arena_) HClinitCheck(constant, dex_pc);
@@ -1660,33 +1636,53 @@
}
}
+HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index,
+ uint32_t dex_pc,
+ bool check_access,
+ bool outer) {
+ ScopedObjectAccess soa(Thread::Current());
+ const DexCompilationUnit* compilation_unit =
+ outer ? outer_compilation_unit_ : dex_compilation_unit_;
+ const DexFile& dex_file = *compilation_unit->GetDexFile();
+ Handle<mirror::DexCache> dex_cache = compilation_unit->GetDexCache();
+ bool is_accessible = false;
+ Handle<mirror::Class> klass = handles_->NewHandle(dex_cache->GetResolvedType(type_index));
+ if (!check_access) {
+ is_accessible = true;
+ } else if (klass.Get() != nullptr) {
+ if (klass->IsPublic()) {
+ is_accessible = true;
+ } else {
+ mirror::Class* compiling_class = GetCompilingClass();
+ if (compiling_class != nullptr && compiling_class->CanAccess(klass.Get())) {
+ is_accessible = true;
+ }
+ }
+ }
+
+ HLoadClass* load_class = new (arena_) HLoadClass(
+ graph_->GetCurrentMethod(),
+ type_index,
+ dex_file,
+ klass,
+ klass.Get() != nullptr && (klass.Get() == GetOutermostCompilingClass()),
+ dex_pc,
+ !is_accessible);
+
+ AppendInstruction(load_class);
+ return load_class;
+}
+
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
dex::TypeIndex type_index,
uint32_t dex_pc) {
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
- Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
- Handle<mirror::Class> resolved_class(hs.NewHandle(dex_cache->GetResolvedType(type_index)));
-
- bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
- dex_compilation_unit_->GetDexMethodIndex(),
- dex_cache,
- type_index);
-
HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
- HLoadClass* cls = new (arena_) HLoadClass(
- graph_->GetCurrentMethod(),
- type_index,
- dex_file,
- IsOutermostCompilingClass(type_index),
- dex_pc,
- !can_access);
- AppendInstruction(cls);
+ HLoadClass* cls = BuildLoadClass(type_index, dex_pc, /* check_access */ true);
- TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class);
+ ScopedObjectAccess soa(Thread::Current());
+ TypeCheckKind check_kind = ComputeTypeCheckKind(cls->GetClass());
if (instruction.Opcode() == Instruction::INSTANCE_OF) {
AppendInstruction(new (arena_) HInstanceOf(object, cls, check_kind, dex_pc));
UpdateLocal(destination, current_block_->GetLastInstruction());
@@ -2690,21 +2686,7 @@
case Instruction::CONST_CLASS: {
dex::TypeIndex type_index(instruction.VRegB_21c());
- // `CanAccessTypeWithoutChecks` will tell whether the method being
- // built is trying to access its own class, so that the generated
- // code can optimize for this case. However, the optimization does not
- // work for inlining, so we use `IsOutermostCompilingClass` instead.
- ScopedObjectAccess soa(Thread::Current());
- Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
- bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
- dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index);
- AppendInstruction(new (arena_) HLoadClass(
- graph_->GetCurrentMethod(),
- type_index,
- *dex_file_,
- IsOutermostCompilingClass(type_index),
- dex_pc,
- !can_access));
+ BuildLoadClass(type_index, dex_pc, /* check_access */ true);
UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
break;
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index aef0b94..5efe950 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -46,9 +46,11 @@
CompilerDriver* driver,
const uint8_t* interpreter_metadata,
OptimizingCompilerStats* compiler_stats,
- Handle<mirror::DexCache> dex_cache)
+ Handle<mirror::DexCache> dex_cache,
+ VariableSizedHandleScope* handles)
: arena_(graph->GetArena()),
graph_(graph),
+ handles_(handles),
dex_file_(dex_file),
code_item_(code_item),
return_type_(return_type),
@@ -223,6 +225,14 @@
// Builds an instruction sequence for a switch statement.
void BuildSwitch(const Instruction& instruction, uint32_t dex_pc);
+ // Builds a `HLoadClass` loading the given `type_index`. If `outer` is true,
+ // this method will use the outer class's dex file to lookup the type at
+ // `type_index`.
+ HLoadClass* BuildLoadClass(dex::TypeIndex type_index,
+ uint32_t dex_pc,
+ bool check_access,
+ bool outer = false);
+
// Returns the outer-most compiling method's class.
mirror::Class* GetOutermostCompilingClass() const;
@@ -282,6 +292,7 @@
ArenaAllocator* const arena_;
HGraph* const graph_;
+ VariableSizedHandleScope* handles_;
// The dex file where the method being compiled is, and the bytecode data.
const DexFile* const dex_file_;
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index fc6ff7b..17d683f 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -145,7 +145,7 @@
if (!CheckInvokeType(intrinsic, invoke)) {
LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
<< intrinsic << " for "
- << invoke->GetDexFile().PrettyMethod(invoke->GetDexMethodIndex())
+ << art_method->PrettyMethod()
<< invoke->DebugName();
} else {
invoke->SetIntrinsic(intrinsic,
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 4f30b11..2d3c00f 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -979,7 +979,7 @@
}
if (ref_info->IsSingletonAndRemovable() &&
!new_instance->IsFinalizable() &&
- !new_instance->NeedsAccessCheck()) {
+ !new_instance->NeedsChecks()) {
singleton_new_instances_.push_back(new_instance);
}
ArenaVector<HInstruction*>& heap_values =
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 0af0d19..d15145e 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2391,6 +2391,14 @@
return !opt.GetDoesNotNeedEnvironment();
}
+const DexFile& HInvokeStaticOrDirect::GetDexFileForPcRelativeDexCache() const {
+ ArtMethod* caller = GetEnvironment()->GetMethod();
+ ScopedObjectAccess soa(Thread::Current());
+ // `caller` is null for a top-level graph representing a method whose declaring
+ // class was not resolved.
+ return caller == nullptr ? GetBlock()->GetGraph()->GetDexFile() : *caller->GetDexFile();
+}
+
bool HInvokeStaticOrDirect::NeedsDexCacheOfDeclaringClass() const {
if (GetMethodLoadKind() != MethodLoadKind::kDexCacheViaMethod) {
return false;
@@ -2434,17 +2442,6 @@
}
}
-// Helper for InstructionDataEquals to fetch the mirror Class out
-// from a kJitTableAddress LoadClass kind.
-// NO_THREAD_SAFETY_ANALYSIS because even though we're accessing
-// mirrors, they are stored in a variable size handle scope which is always
-// visited during a pause. Also, the only caller of this helper
-// only uses the mirror for pointer comparison.
-static inline mirror::Class* AsMirrorInternal(uint64_t address)
- NO_THREAD_SAFETY_ANALYSIS {
- return reinterpret_cast<StackReference<mirror::Class>*>(address)->AsMirrorPtr();
-}
-
bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
const HLoadClass* other_load_class = other->AsLoadClass();
// TODO: To allow GVN for HLoadClass from different dex files, we should compare the type
@@ -2455,9 +2452,10 @@
}
switch (GetLoadKind()) {
case LoadKind::kBootImageAddress:
- return GetAddress() == other_load_class->GetAddress();
- case LoadKind::kJitTableAddress:
- return AsMirrorInternal(GetAddress()) == AsMirrorInternal(other_load_class->GetAddress());
+ case LoadKind::kJitTableAddress: {
+ ScopedObjectAccess soa(Thread::Current());
+ return GetClass().Get() == other_load_class->GetClass().Get();
+ }
default:
DCHECK(HasTypeReference(GetLoadKind()));
return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile());
@@ -2502,17 +2500,6 @@
}
}
-// Helper for InstructionDataEquals to fetch the mirror String out
-// from a kJitTableAddress LoadString kind.
-// NO_THREAD_SAFETY_ANALYSIS because even though we're accessing
-// mirrors, they are stored in a variable size handle scope which is always
-// visited during a pause. Also, the only caller of this helper
-// only uses the mirror for pointer comparison.
-static inline mirror::String* AsMirrorInternal(Handle<mirror::String> handle)
- NO_THREAD_SAFETY_ANALYSIS {
- return handle.Get();
-}
-
bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
const HLoadString* other_load_string = other->AsLoadString();
// TODO: To allow GVN for HLoadString from different dex files, we should compare the strings
@@ -2523,8 +2510,10 @@
}
switch (GetLoadKind()) {
case LoadKind::kBootImageAddress:
- case LoadKind::kJitTableAddress:
- return AsMirrorInternal(GetString()) == AsMirrorInternal(other_load_string->GetString());
+ case LoadKind::kJitTableAddress: {
+ ScopedObjectAccess soa(Thread::Current());
+ return GetString().Get() == other_load_string->GetString().Get();
+ }
default:
return IsSameDexFile(GetDexFile(), other_load_string->GetDexFile());
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3e7914c..53b0fdd 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1724,28 +1724,22 @@
public:
HEnvironment(ArenaAllocator* arena,
size_t number_of_vregs,
- const DexFile& dex_file,
- uint32_t method_idx,
+ ArtMethod* method,
uint32_t dex_pc,
- InvokeType invoke_type,
HInstruction* holder)
: vregs_(number_of_vregs, arena->Adapter(kArenaAllocEnvironmentVRegs)),
locations_(number_of_vregs, arena->Adapter(kArenaAllocEnvironmentLocations)),
parent_(nullptr),
- dex_file_(dex_file),
- method_idx_(method_idx),
+ method_(method),
dex_pc_(dex_pc),
- invoke_type_(invoke_type),
holder_(holder) {
}
HEnvironment(ArenaAllocator* arena, const HEnvironment& to_copy, HInstruction* holder)
: HEnvironment(arena,
to_copy.Size(),
- to_copy.GetDexFile(),
- to_copy.GetMethodIdx(),
+ to_copy.GetMethod(),
to_copy.GetDexPc(),
- to_copy.GetInvokeType(),
holder) {}
void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
@@ -1794,16 +1788,8 @@
return dex_pc_;
}
- uint32_t GetMethodIdx() const {
- return method_idx_;
- }
-
- InvokeType GetInvokeType() const {
- return invoke_type_;
- }
-
- const DexFile& GetDexFile() const {
- return dex_file_;
+ ArtMethod* GetMethod() const {
+ return method_;
}
HInstruction* GetHolder() const {
@@ -1819,10 +1805,8 @@
ArenaVector<HUserRecord<HEnvironment*>> vregs_;
ArenaVector<Location> locations_;
HEnvironment* parent_;
- const DexFile& dex_file_;
- const uint32_t method_idx_;
+ ArtMethod* method_;
const uint32_t dex_pc_;
- const InvokeType invoke_type_;
// The instruction that holds this environment.
HInstruction* const holder_;
@@ -3784,14 +3768,12 @@
uint32_t dex_pc,
dex::TypeIndex type_index,
const DexFile& dex_file,
- bool needs_access_check,
bool finalizable,
QuickEntrypointEnum entrypoint)
: HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
type_index_(type_index),
dex_file_(dex_file),
entrypoint_(entrypoint) {
- SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
SetPackedFlag<kFlagFinalizable>(finalizable);
SetRawInputAt(0, cls);
}
@@ -3805,8 +3787,9 @@
// Can throw errors when out-of-memory or if it's not instantiable/accessible.
bool CanThrow() const OVERRIDE { return true; }
- // Needs to call into runtime to make sure it's instantiable/accessible.
- bool NeedsAccessCheck() const { return GetPackedFlag<kFlagNeedsAccessCheck>(); }
+ bool NeedsChecks() const {
+ return entrypoint_ == kQuickAllocObjectWithChecks;
+ }
bool IsFinalizable() const { return GetPackedFlag<kFlagFinalizable>(); }
@@ -3823,8 +3806,7 @@
DECLARE_INSTRUCTION(NewInstance);
private:
- static constexpr size_t kFlagNeedsAccessCheck = kNumberOfExpressionPackedBits;
- static constexpr size_t kFlagFinalizable = kFlagNeedsAccessCheck + 1;
+ static constexpr size_t kFlagFinalizable = kNumberOfExpressionPackedBits;
static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1;
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
@@ -3870,7 +3852,6 @@
Primitive::Type GetType() const OVERRIDE { return GetPackedField<ReturnTypeField>(); }
uint32_t GetDexMethodIndex() const { return dex_method_index_; }
- const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
InvokeType GetInvokeType() const {
return GetPackedField<InvokeTypeField>();
@@ -4190,6 +4171,8 @@
return dispatch_info_.method_load_data;
}
+ const DexFile& GetDexFileForPcRelativeDexCache() const;
+
ClinitCheckRequirement GetClinitCheckRequirement() const {
return GetPackedField<ClinitCheckRequirementField>();
}
@@ -5449,10 +5432,10 @@
HBoundsCheck(HInstruction* index,
HInstruction* length,
uint32_t dex_pc,
- uint32_t string_char_at_method_index = DexFile::kDexNoIndex)
- : HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc),
- string_char_at_method_index_(string_char_at_method_index) {
+ bool string_char_at = false)
+ : HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc) {
DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(index->GetType()));
+ SetPackedFlag<kFlagIsStringCharAt>(string_char_at);
SetRawInputAt(0, index);
SetRawInputAt(1, length);
}
@@ -5466,22 +5449,14 @@
bool CanThrow() const OVERRIDE { return true; }
- bool IsStringCharAt() const { return GetStringCharAtMethodIndex() != DexFile::kDexNoIndex; }
- uint32_t GetStringCharAtMethodIndex() const { return string_char_at_method_index_; }
+ bool IsStringCharAt() const { return GetPackedFlag<kFlagIsStringCharAt>(); }
HInstruction* GetIndex() const { return InputAt(0); }
DECLARE_INSTRUCTION(BoundsCheck);
private:
- // We treat a String as an array, creating the HBoundsCheck from String.charAt()
- // intrinsic in the instruction simplifier. We want to include the String.charAt()
- // in the stack trace if we actually throw the StringIndexOutOfBoundsException,
- // so we need to create an HEnvironment which will be translated to an InlineInfo
- // indicating the extra stack frame. Since we add this HEnvironment quite late,
- // in the PrepareForRegisterAllocation pass, we need to remember the method index
- // from the invoke as we don't want to look again at the dex bytecode.
- uint32_t string_char_at_method_index_; // DexFile::kDexNoIndex if regular array.
+ static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits;
DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
};
@@ -5567,6 +5542,7 @@
HLoadClass(HCurrentMethod* current_method,
dex::TypeIndex type_index,
const DexFile& dex_file,
+ Handle<mirror::Class> klass,
bool is_referrers_class,
uint32_t dex_pc,
bool needs_access_check)
@@ -5574,7 +5550,7 @@
special_input_(HUserRecord<HInstruction*>(current_method)),
type_index_(type_index),
dex_file_(dex_file),
- address_(0u),
+ klass_(klass),
loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) {
// Referrers class should not need access check. We never inline unverified
// methods so we can't possibly end up in this situation.
@@ -5587,10 +5563,7 @@
SetPackedFlag<kFlagGenerateClInitCheck>(false);
}
- void SetLoadKindWithAddress(LoadKind load_kind, uint64_t address) {
- DCHECK(HasAddress(load_kind));
- DCHECK_NE(address, 0u);
- address_ = address;
+ void SetLoadKind(LoadKind load_kind) {
SetLoadKindInternal(load_kind);
}
@@ -5657,11 +5630,6 @@
dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
- uint64_t GetAddress() const {
- DCHECK(HasAddress(GetLoadKind()));
- return address_;
- }
-
bool NeedsDexCacheOfDeclaringClass() const OVERRIDE {
return GetLoadKind() == LoadKind::kDexCacheViaMethod;
}
@@ -5691,6 +5659,10 @@
return Primitive::kPrimNot;
}
+ Handle<mirror::Class> GetClass() const {
+ return klass_;
+ }
+
DECLARE_INSTRUCTION(LoadClass);
private:
@@ -5714,11 +5686,6 @@
load_kind == LoadKind::kDexCacheViaMethod;
}
- static bool HasAddress(LoadKind load_kind) {
- return load_kind == LoadKind::kBootImageAddress ||
- load_kind == LoadKind::kJitTableAddress;
- }
-
void SetLoadKindInternal(LoadKind load_kind);
// The special input is the HCurrentMethod for kDexCacheViaMethod or kReferrersClass.
@@ -5729,7 +5696,7 @@
const dex::TypeIndex type_index_;
const DexFile& dex_file_;
- uint64_t address_; // Up to 64-bit, needed for kJitTableAddress on 64-bit targets.
+ Handle<mirror::Class> klass_;
ReferenceTypeInfo loaded_class_rti_;
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index 5d9a652..7686ba8 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -52,7 +52,7 @@
exit_block->AddInstruction(new (&allocator) HExit());
HEnvironment* environment = new (&allocator) HEnvironment(
- &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, null_check);
+ &allocator, 1, graph->GetArtMethod(), 0, null_check);
null_check->SetRawEnvironment(environment);
environment->SetRawEnvAt(0, parameter);
parameter->AddEnvUseAt(null_check->GetEnvironment(), 0);
@@ -137,7 +137,7 @@
ASSERT_TRUE(parameter1->GetUses().HasExactlyOneElement());
HEnvironment* environment = new (&allocator) HEnvironment(
- &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, with_environment);
+ &allocator, 1, graph->GetArtMethod(), 0, with_environment);
ArenaVector<HInstruction*> array(allocator.Adapter());
array.push_back(parameter1);
@@ -148,13 +148,13 @@
ASSERT_TRUE(parameter1->GetEnvUses().HasExactlyOneElement());
HEnvironment* parent1 = new (&allocator) HEnvironment(
- &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, nullptr);
+ &allocator, 1, graph->GetArtMethod(), 0, nullptr);
parent1->CopyFrom(array);
ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u);
HEnvironment* parent2 = new (&allocator) HEnvironment(
- &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, nullptr);
+ &allocator, 1, graph->GetArtMethod(), 0, nullptr);
parent2->CopyFrom(array);
parent1->SetAndCopyParentChain(&allocator, parent2);
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index db7c1fb..efbaf6c 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -16,6 +16,9 @@
#include "prepare_for_register_allocation.h"
+#include "jni_internal.h"
+#include "well_known_classes.h"
+
namespace art {
void PrepareForRegisterAllocation::Run() {
@@ -42,16 +45,12 @@
if (check->IsStringCharAt()) {
// Add a fake environment for String.charAt() inline info as we want
// the exception to appear as being thrown from there.
- const DexFile& dex_file = check->GetEnvironment()->GetDexFile();
- DCHECK_STREQ(dex_file.PrettyMethod(check->GetStringCharAtMethodIndex()).c_str(),
- "char java.lang.String.charAt(int)");
+ ArtMethod* char_at_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
ArenaAllocator* arena = GetGraph()->GetArena();
HEnvironment* environment = new (arena) HEnvironment(arena,
/* number_of_vregs */ 0u,
- dex_file,
- check->GetStringCharAtMethodIndex(),
+ char_at_method,
/* dex_pc */ DexFile::kDexNoIndex,
- kVirtual,
check);
check->InsertRawEnvironment(environment);
}
@@ -199,8 +198,7 @@
return false;
}
if (user_environment->GetDexPc() != input_environment->GetDexPc() ||
- user_environment->GetMethodIdx() != input_environment->GetMethodIdx() ||
- !IsSameDexFile(user_environment->GetDexFile(), input_environment->GetDexFile())) {
+ user_environment->GetMethod() != input_environment->GetMethod()) {
return false;
}
user_environment = user_environment->GetParent();
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index f8a4469..a4d59ab 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -295,13 +295,13 @@
}
if (check->IsIf()) {
- HBasicBlock* trueBlock = check->IsEqual()
+ HBasicBlock* trueBlock = compare->IsEqual()
? check->AsIf()->IfTrueSuccessor()
: check->AsIf()->IfFalseSuccessor();
BoundTypeIn(receiver, trueBlock, /* start_instruction */ nullptr, class_rti);
} else {
DCHECK(check->IsDeoptimize());
- if (check->IsEqual()) {
+ if (compare->IsEqual()) {
BoundTypeIn(receiver, check->GetBlock(), check, class_rti);
}
}
@@ -499,18 +499,19 @@
if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
// Calls to String.<init> are replaced with a StringFactory.
if (kIsDebugBuild) {
- HInvoke* invoke = instr->AsInvoke();
+ HInvokeStaticOrDirect* invoke = instr->AsInvokeStaticOrDirect();
ClassLinker* cl = Runtime::Current()->GetClassLinker();
Thread* self = Thread::Current();
StackHandleScope<2> hs(self);
+ const DexFile& dex_file = *invoke->GetTargetMethod().dex_file;
Handle<mirror::DexCache> dex_cache(
- hs.NewHandle(FindDexCacheWithHint(self, invoke->GetDexFile(), hint_dex_cache_)));
+ hs.NewHandle(FindDexCacheWithHint(self, dex_file, hint_dex_cache_)));
// Use a null loader. We should probably use the compiling method's class loader,
// but then we would need to pass it to RTPVisitor just for this debug check. Since
// the method is from the String class, the null loader is good enough.
Handle<mirror::ClassLoader> loader;
ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
+ dex_file, invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
DCHECK(method != nullptr);
mirror::Class* declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != nullptr);
@@ -619,14 +620,10 @@
void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
ScopedObjectAccess soa(Thread::Current());
- // Get type from dex cache assuming it was populated by the verifier.
- mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
- instr->GetDexFile(),
- instr->GetTypeIndex(),
- hint_dex_cache_);
- if (IsAdmissible(resolved_class)) {
+ Handle<mirror::Class> resolved_class = instr->GetClass();
+ if (IsAdmissible(resolved_class.Get())) {
instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
- handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
+ resolved_class, /* is_exact */ true));
}
instr->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
@@ -844,10 +841,8 @@
ScopedObjectAccess soa(Thread::Current());
ClassLinker* cl = Runtime::Current()->GetClassLinker();
- mirror::DexCache* dex_cache =
- FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_);
PointerSize pointer_size = cl->GetImagePointerSize();
- ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
+ ArtMethod* method = instr->GetResolvedMethod();
mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index eabda26..c529410 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -133,24 +133,13 @@
void HSharpening::ProcessLoadClass(HLoadClass* load_class) {
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- const DexFile& dex_file = load_class->GetDexFile();
- dex::TypeIndex type_index = load_class->GetTypeIndex();
- Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *compilation_unit_.GetDexFile())
- ? compilation_unit_.GetDexCache()
- : hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
- mirror::Class* cls = dex_cache->GetResolvedType(type_index);
- SharpenClass(load_class, cls, handles_, codegen_, compiler_driver_);
+ SharpenClass(load_class, codegen_, compiler_driver_);
}
void HSharpening::SharpenClass(HLoadClass* load_class,
- mirror::Class* klass,
- VariableSizedHandleScope* handles,
CodeGenerator* codegen,
CompilerDriver* compiler_driver) {
- ScopedAssertNoThreadSuspension sants("Sharpening class in compiler");
+ Handle<mirror::Class> klass = load_class->GetClass();
DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kDexCacheViaMethod ||
load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
<< load_class->GetLoadKind();
@@ -174,7 +163,6 @@
bool is_in_boot_image = false;
HLoadClass::LoadKind desired_load_kind = static_cast<HLoadClass::LoadKind>(-1);
- uint64_t address = 0u; // Class or dex cache element address.
Runtime* runtime = Runtime::Current();
if (codegen->GetCompilerOptions().IsBootImage()) {
// Compiling boot image. Check if the class is a boot image class.
@@ -182,7 +170,7 @@
if (!compiler_driver->GetSupportBootImageFixup()) {
// compiler_driver_test. Do not sharpen.
desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
- } else if ((klass != nullptr) && compiler_driver->IsImageClass(
+ } else if ((klass.Get() != nullptr) && compiler_driver->IsImageClass(
dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) {
is_in_boot_image = true;
desired_load_kind = codegen->GetCompilerOptions().GetCompilePic()
@@ -194,20 +182,16 @@
desired_load_kind = HLoadClass::LoadKind::kBssEntry;
}
} else {
- is_in_boot_image = (klass != nullptr) && runtime->GetHeap()->ObjectIsInBootImageSpace(klass);
+ is_in_boot_image = (klass.Get() != nullptr) &&
+ runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get());
if (runtime->UseJitCompilation()) {
// TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
// DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
if (is_in_boot_image) {
// TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787
desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
- address = reinterpret_cast64<uint64_t>(klass);
- } else if (klass != nullptr) {
+ } else if (klass.Get() != nullptr) {
desired_load_kind = HLoadClass::LoadKind::kJitTableAddress;
- // We store in the address field the location of the stack reference maintained
- // by the handle. We do this now so that the code generation does not need to figure
- // out which class loader to use.
- address = reinterpret_cast<uint64_t>(handles->NewHandle(klass).GetReference());
} else {
// Class not loaded yet. This happens when the dex code requesting
// this `HLoadClass` hasn't been executed in the interpreter.
@@ -218,7 +202,6 @@
} else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) {
// AOT app compilation. Check if the class is in the boot image.
desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
- address = reinterpret_cast64<uint64_t>(klass);
} else {
// Not JIT and either the klass is not in boot image or we are compiling in PIC mode.
desired_load_kind = HLoadClass::LoadKind::kBssEntry;
@@ -240,8 +223,7 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
case HLoadClass::LoadKind::kJitTableAddress:
- DCHECK_NE(address, 0u);
- load_class->SetLoadKindWithAddress(load_kind, address);
+ load_class->SetLoadKind(load_kind);
break;
default:
LOG(FATAL) << "Unexpected load kind: " << load_kind;
diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h
index ae5ccb3..ae3d83e 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -49,8 +49,6 @@
// Used internally but also by the inliner.
static void SharpenClass(HLoadClass* load_class,
- mirror::Class* klass,
- VariableSizedHandleScope* handles,
CodeGenerator* codegen,
CompilerDriver* compiler_driver)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index fc8af64..6087e36 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -13,8 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include "stack_map_stream.h"
+#include "art_method.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+
namespace art {
void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,
@@ -98,15 +103,27 @@
current_dex_register_++;
}
-void StackMapStream::BeginInlineInfoEntry(uint32_t method_index,
+static bool EncodeArtMethodInInlineInfo(ArtMethod* method ATTRIBUTE_UNUSED) {
+ // Note: the runtime is null only for unit testing.
+ return Runtime::Current() == nullptr || !Runtime::Current()->IsAotCompiler();
+}
+
+void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
uint32_t dex_pc,
- InvokeType invoke_type,
- uint32_t num_dex_registers) {
+ uint32_t num_dex_registers,
+ const DexFile* outer_dex_file) {
DCHECK(!in_inline_frame_);
in_inline_frame_ = true;
- current_inline_info_.method_index = method_index;
+ if (EncodeArtMethodInInlineInfo(method)) {
+ current_inline_info_.method = method;
+ } else {
+ if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) {
+ ScopedObjectAccess soa(Thread::Current());
+ DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile()));
+ }
+ current_inline_info_.method_index = method->GetDexMethodIndexUnchecked();
+ }
current_inline_info_.dex_pc = dex_pc;
- current_inline_info_.invoke_type = invoke_type;
current_inline_info_.num_dex_registers = num_dex_registers;
current_inline_info_.dex_register_locations_start_index = dex_register_locations_.size();
if (num_dex_registers != 0) {
@@ -229,25 +246,32 @@
void StackMapStream::ComputeInlineInfoEncoding() {
uint32_t method_index_max = 0;
uint32_t dex_pc_max = DexFile::kDexNoIndex;
- uint32_t invoke_type_max = 0;
+ uint32_t extra_data_max = 0;
uint32_t inline_info_index = 0;
for (const StackMapEntry& entry : stack_maps_) {
for (size_t j = 0; j < entry.inlining_depth; ++j) {
InlineInfoEntry inline_entry = inline_infos_[inline_info_index++];
- method_index_max = std::max(method_index_max, inline_entry.method_index);
+ if (inline_entry.method == nullptr) {
+ method_index_max = std::max(method_index_max, inline_entry.method_index);
+ extra_data_max = std::max(extra_data_max, 1u);
+ } else {
+ method_index_max = std::max(
+ method_index_max, High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
+ extra_data_max = std::max(
+ extra_data_max, Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
+ }
if (inline_entry.dex_pc != DexFile::kDexNoIndex &&
(dex_pc_max == DexFile::kDexNoIndex || dex_pc_max < inline_entry.dex_pc)) {
dex_pc_max = inline_entry.dex_pc;
}
- invoke_type_max = std::max(invoke_type_max, static_cast<uint32_t>(inline_entry.invoke_type));
}
}
DCHECK_EQ(inline_info_index, inline_infos_.size());
inline_info_encoding_.SetFromSizes(method_index_max,
dex_pc_max,
- invoke_type_max,
+ extra_data_max,
dex_register_maps_size_);
}
@@ -354,9 +378,20 @@
DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size());
for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index];
- inline_info.SetMethodIndexAtDepth(inline_info_encoding_, depth, inline_entry.method_index);
+ if (inline_entry.method != nullptr) {
+ inline_info.SetMethodIndexAtDepth(
+ inline_info_encoding_,
+ depth,
+ High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
+ inline_info.SetExtraDataAtDepth(
+ inline_info_encoding_,
+ depth,
+ Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
+ } else {
+ inline_info.SetMethodIndexAtDepth(inline_info_encoding_, depth, inline_entry.method_index);
+ inline_info.SetExtraDataAtDepth(inline_info_encoding_, depth, 1);
+ }
inline_info.SetDexPcAtDepth(inline_info_encoding_, depth, inline_entry.dex_pc);
- inline_info.SetInvokeTypeAtDepth(inline_info_encoding_, depth, inline_entry.invoke_type);
if (inline_entry.num_dex_registers == 0) {
// No dex map available.
inline_info.SetDexRegisterMapOffsetAtDepth(inline_info_encoding_,
@@ -544,10 +579,13 @@
InlineInfoEntry inline_entry = inline_infos_[inline_info_index];
DCHECK_EQ(inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, d),
inline_entry.dex_pc);
- DCHECK_EQ(inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, d),
- inline_entry.method_index);
- DCHECK_EQ(inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, d),
- inline_entry.invoke_type);
+ if (inline_info.EncodesArtMethodAtDepth(encoding.inline_info_encoding, d)) {
+ DCHECK_EQ(inline_info.GetArtMethodAtDepth(encoding.inline_info_encoding, d),
+ inline_entry.method);
+ } else {
+ DCHECK_EQ(inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, d),
+ inline_entry.method_index);
+ }
CheckDexRegisterMap(code_info,
code_info.GetDexRegisterMapAtDepth(
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 53a9795..d6f42b3 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -109,8 +109,8 @@
struct InlineInfoEntry {
uint32_t dex_pc; // DexFile::kDexNoIndex for intrinsified native methods.
+ ArtMethod* method;
uint32_t method_index;
- InvokeType invoke_type;
uint32_t num_dex_registers;
BitVector* live_dex_registers_mask;
size_t dex_register_locations_start_index;
@@ -126,10 +126,10 @@
void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value);
- void BeginInlineInfoEntry(uint32_t method_index,
+ void BeginInlineInfoEntry(ArtMethod* method,
uint32_t dex_pc,
- InvokeType invoke_type,
- uint32_t num_dex_registers);
+ uint32_t num_dex_registers,
+ const DexFile* outer_dex_file = nullptr);
void EndInlineInfoEntry();
size_t GetNumberOfStackMaps() const {
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 967fd96..22810ea 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -16,6 +16,7 @@
#include "stack_map.h"
+#include "art_method.h"
#include "base/arena_bit_vector.h"
#include "stack_map_stream.h"
@@ -128,6 +129,7 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
StackMapStream stream(&arena);
+ ArtMethod art_method;
ArenaBitVector sp_mask1(&arena, 0, true);
sp_mask1.SetBit(2);
@@ -137,9 +139,9 @@
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2);
stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
- stream.BeginInlineInfoEntry(82, 3, kDirect, number_of_dex_registers_in_inline_info);
+ stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(42, 2, kStatic, number_of_dex_registers_in_inline_info);
+ stream.BeginInlineInfoEntry(&art_method, 2, number_of_dex_registers_in_inline_info);
stream.EndInlineInfoEntry();
stream.EndStackMapEntry();
@@ -238,12 +240,10 @@
ASSERT_TRUE(stack_map.HasInlineInfo(encoding.stack_map_encoding));
InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
ASSERT_EQ(2u, inline_info.GetDepth(encoding.inline_info_encoding));
- ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(kDirect, inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(kStatic, inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+ ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 0));
+ ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 1));
}
// Second stack map.
@@ -662,6 +662,7 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
StackMapStream stream(&arena);
+ ArtMethod art_method;
ArenaBitVector sp_mask1(&arena, 0, true);
sp_mask1.SetBit(2);
@@ -672,10 +673,10 @@
stream.AddDexRegisterEntry(Kind::kInStack, 0);
stream.AddDexRegisterEntry(Kind::kConstant, 4);
- stream.BeginInlineInfoEntry(42, 2, kStatic, 1);
+ stream.BeginInlineInfoEntry(&art_method, 2, 1);
stream.AddDexRegisterEntry(Kind::kInStack, 8);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+ stream.BeginInlineInfoEntry(&art_method, 3, 3);
stream.AddDexRegisterEntry(Kind::kInStack, 16);
stream.AddDexRegisterEntry(Kind::kConstant, 20);
stream.AddDexRegisterEntry(Kind::kInRegister, 15);
@@ -688,15 +689,15 @@
stream.AddDexRegisterEntry(Kind::kInStack, 56);
stream.AddDexRegisterEntry(Kind::kConstant, 0);
- stream.BeginInlineInfoEntry(42, 2, kDirect, 1);
+ stream.BeginInlineInfoEntry(&art_method, 2, 1);
stream.AddDexRegisterEntry(Kind::kInStack, 12);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+ stream.BeginInlineInfoEntry(&art_method, 3, 3);
stream.AddDexRegisterEntry(Kind::kInStack, 80);
stream.AddDexRegisterEntry(Kind::kConstant, 10);
stream.AddDexRegisterEntry(Kind::kInRegister, 5);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(52, 5, kVirtual, 0);
+ stream.BeginInlineInfoEntry(&art_method, 5, 0);
stream.EndInlineInfoEntry();
stream.EndStackMapEntry();
@@ -712,12 +713,12 @@
stream.AddDexRegisterEntry(Kind::kInStack, 56);
stream.AddDexRegisterEntry(Kind::kConstant, 0);
- stream.BeginInlineInfoEntry(42, 2, kVirtual, 0);
+ stream.BeginInlineInfoEntry(&art_method, 2, 0);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(52, 5, kInterface, 1);
+ stream.BeginInlineInfoEntry(&art_method, 5, 1);
stream.AddDexRegisterEntry(Kind::kInRegister, 2);
stream.EndInlineInfoEntry();
- stream.BeginInlineInfoEntry(52, 10, kStatic, 2);
+ stream.BeginInlineInfoEntry(&art_method, 10, 2);
stream.AddDexRegisterEntry(Kind::kNone, 0);
stream.AddDexRegisterEntry(Kind::kInRegister, 3);
stream.EndInlineInfoEntry();
@@ -743,11 +744,9 @@
InlineInfo if0 = ci.GetInlineInfoOf(sm0, encoding);
ASSERT_EQ(2u, if0.GetDepth(encoding.inline_info_encoding));
ASSERT_EQ(2u, if0.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+ ASSERT_TRUE(if0.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 0));
ASSERT_EQ(3u, if0.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+ ASSERT_TRUE(if0.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 1));
DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, encoding, 1);
ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
@@ -769,14 +768,11 @@
InlineInfo if1 = ci.GetInlineInfoOf(sm1, encoding);
ASSERT_EQ(3u, if1.GetDepth(encoding.inline_info_encoding));
ASSERT_EQ(2u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(kDirect, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+ ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 0));
ASSERT_EQ(3u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(kStatic, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+ ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 1));
ASSERT_EQ(5u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 2));
- ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 2));
- ASSERT_EQ(kVirtual, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 2));
+ ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 2));
DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, encoding, 1);
ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
@@ -810,14 +806,11 @@
InlineInfo if2 = ci.GetInlineInfoOf(sm3, encoding);
ASSERT_EQ(3u, if2.GetDepth(encoding.inline_info_encoding));
ASSERT_EQ(2u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
- ASSERT_EQ(kVirtual, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+ ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 0));
ASSERT_EQ(5u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
- ASSERT_EQ(kInterface, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+ ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 1));
ASSERT_EQ(10u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 2));
- ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 2));
- ASSERT_EQ(kStatic, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 2));
+ ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info_encoding, 2));
ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, 0));
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index ab4f9e9..5e55210 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5610,7 +5610,7 @@
" 214: ecbd 8a10 vpop {s16-s31}\n",
" 218: e8bd 8de0 ldmia.w sp!, {r5, r6, r7, r8, sl, fp, pc}\n",
" 21c: 4660 mov r0, ip\n",
- " 21e: f8d9 c2b0 ldr.w ip, [r9, #688] ; 0x2b0\n",
+ " 21e: f8d9 c2c0 ldr.w ip, [r9, #704] ; 0x2c0\n",
" 222: 47e0 blx ip\n",
nullptr
};
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 7ae13a5..2bf7495 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -54,48 +54,6 @@
namespace art {
-static bool LocationToFilename(const std::string& location, InstructionSet isa,
- std::string* filename) {
- bool has_system = false;
- bool has_cache = false;
- // image_location = /system/framework/boot.art
- // system_image_filename = /system/framework/<image_isa>/boot.art
- std::string system_filename(GetSystemImageFilename(location.c_str(), isa));
- if (OS::FileExists(system_filename.c_str())) {
- has_system = true;
- }
-
- bool have_android_data = false;
- bool dalvik_cache_exists = false;
- bool is_global_cache = false;
- std::string dalvik_cache;
- GetDalvikCache(GetInstructionSetString(isa), false, &dalvik_cache,
- &have_android_data, &dalvik_cache_exists, &is_global_cache);
-
- std::string cache_filename;
- if (have_android_data && dalvik_cache_exists) {
- // Always set output location even if it does not exist,
- // so that the caller knows where to create the image.
- //
- // image_location = /system/framework/boot.art
- // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
- std::string error_msg;
- if (GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(),
- &cache_filename, &error_msg)) {
- has_cache = true;
- }
- }
- if (has_system) {
- *filename = system_filename;
- return true;
- } else if (has_cache) {
- *filename = cache_filename;
- return true;
- } else {
- return false;
- }
-}
-
static const OatHeader* GetOatHeader(const ElfFile* elf_file) {
uint64_t off = 0;
if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) {
@@ -106,28 +64,10 @@
return oat_header;
}
-// This function takes an elf file and reads the current patch delta value
-// encoded in its oat header value
-static bool ReadOatPatchDelta(const ElfFile* elf_file, off_t* delta, std::string* error_msg) {
- const OatHeader* oat_header = GetOatHeader(elf_file);
- if (oat_header == nullptr) {
- *error_msg = "Unable to get oat header from elf file.";
- return false;
- }
- if (!oat_header->IsValid()) {
- *error_msg = "Elf file has an invalid oat header";
- return false;
- }
- *delta = oat_header->GetImagePatchDelta();
- return true;
-}
-
-static File* CreateOrOpen(const char* name, bool* created) {
+static File* CreateOrOpen(const char* name) {
if (OS::FileExists(name)) {
- *created = false;
return OS::OpenFileReadWrite(name);
} else {
- *created = true;
std::unique_ptr<File> f(OS::CreateEmptyFile(name));
if (f.get() != nullptr) {
if (fchmod(f->Fd(), 0644) != 0) {
@@ -206,12 +146,11 @@
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
ScopedObjectAccess soa(Thread::Current());
- t.NewTiming("Image and oat Patching setup");
+ t.NewTiming("Image Patching setup");
std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
std::map<gc::space::ImageSpace*, std::unique_ptr<File>> space_to_file_map;
std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>> space_to_memmap_map;
std::map<gc::space::ImageSpace*, PatchOat> space_to_patchoat_map;
- std::map<gc::space::ImageSpace*, bool> space_to_skip_patching_map;
for (size_t i = 0; i < spaces.size(); ++i) {
gc::space::ImageSpace* space = spaces[i];
@@ -255,8 +194,7 @@
space_to_memmap_map.emplace(space, std::move(image));
}
- // Do a first pass over the image spaces. Symlink PIC oat and vdex files, and
- // prepare PatchOat instances for the rest.
+ // Symlink PIC oat and vdex files and patch the image spaces in memory.
for (size_t i = 0; i < spaces.size(); ++i) {
gc::space::ImageSpace* space = spaces[i];
std::string input_image_filename = space->GetImageFilename();
@@ -277,14 +215,17 @@
return false;
}
- bool skip_patching_oat = false;
MaybePic is_oat_pic = IsOatPic(elf.get());
if (is_oat_pic >= ERROR_FIRST) {
// Error logged by IsOatPic
return false;
- } else if (is_oat_pic == PIC) {
- // Do not need to do ELF-file patching. Create a symlink and skip the ELF patching.
+ } else if (is_oat_pic == NOT_PIC) {
+ LOG(ERROR) << input_oat_file->GetPath() << " is not PIC";
+ return false;
+ } else {
+ CHECK(is_oat_pic == PIC);
+ // Create a symlink.
std::string converted_image_filename = space->GetImageLocation();
std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
std::string output_image_filename = output_directory +
@@ -296,23 +237,16 @@
ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(),
- output_oat_filename,
- false,
- true) ||
+ output_oat_filename) ||
!SymlinkFile(input_vdex_filename, output_vdex_filename)) {
// Errors already logged by above call.
return false;
}
- // Don't patch the OAT, since we just symlinked it. Image still needs patching.
- skip_patching_oat = true;
- } else {
- CHECK(is_oat_pic == NOT_PIC);
}
PatchOat& p = space_to_patchoat_map.emplace(space,
PatchOat(
isa,
- elf.release(),
space_to_memmap_map.find(space)->second.get(),
space->GetLiveBitmap(),
space->GetMemMap(),
@@ -320,36 +254,24 @@
&space_to_memmap_map,
timings)).first->second;
- t.NewTiming("Patching files");
- if (!skip_patching_oat && !p.PatchElf()) {
- LOG(ERROR) << "Failed to patch oat file " << input_oat_file->GetPath();
- return false;
- }
+ t.NewTiming("Patching image");
if (!p.PatchImage(i == 0)) {
LOG(ERROR) << "Failed to patch image file " << input_image_filename;
return false;
}
-
- space_to_skip_patching_map.emplace(space, skip_patching_oat);
}
- // Do a second pass over the image spaces. Patch image files, non-PIC oat files
- // and symlink their corresponding vdex files.
+ // Write the patched image spaces.
for (size_t i = 0; i < spaces.size(); ++i) {
gc::space::ImageSpace* space = spaces[i];
- std::string input_image_filename = space->GetImageFilename();
- std::string input_vdex_filename =
- ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
- t.NewTiming("Writing files");
+ t.NewTiming("Writing image");
std::string converted_image_filename = space->GetImageLocation();
std::replace(converted_image_filename.begin() + 1, converted_image_filename.end(), '/', '@');
std::string output_image_filename = output_directory +
(android::base::StartsWith(converted_image_filename, "/") ? "" : "/") +
converted_image_filename;
- bool new_oat_out;
- std::unique_ptr<File>
- output_image_file(CreateOrOpen(output_image_filename.c_str(), &new_oat_out));
+ std::unique_ptr<File> output_image_file(CreateOrOpen(output_image_filename.c_str()));
if (output_image_file.get() == nullptr) {
LOG(ERROR) << "Failed to open output image file at " << output_image_filename;
return false;
@@ -362,48 +284,10 @@
if (!success) {
return false;
}
-
- bool skip_patching_oat = space_to_skip_patching_map.find(space)->second;
- if (!skip_patching_oat) {
- std::string output_vdex_filename =
- ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
- std::string output_oat_filename =
- ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
-
- std::unique_ptr<File>
- output_oat_file(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
- if (output_oat_file.get() == nullptr) {
- LOG(ERROR) << "Failed to open output oat file at " << output_oat_filename;
- return false;
- }
- success = p.WriteElf(output_oat_file.get());
- success = FinishFile(output_oat_file.get(), success);
- if (success) {
- success = SymlinkFile(input_vdex_filename, output_vdex_filename);
- }
- if (!success) {
- return false;
- }
- }
}
return true;
}
-bool PatchOat::WriteElf(File* out) {
- TimingLogger::ScopedTiming t("Writing Elf File", timings_);
-
- CHECK(oat_file_.get() != nullptr);
- CHECK(out != nullptr);
- size_t expect = oat_file_->Size();
- if (out->WriteFully(reinterpret_cast<char*>(oat_file_->Begin()), expect) &&
- out->SetLength(expect) == 0) {
- return true;
- } else {
- LOG(ERROR) << "Writing to oat file " << out->GetPath() << " failed.";
- return false;
- }
-}
-
bool PatchOat::WriteImage(File* out) {
TimingLogger::ScopedTiming t("Writing image File", timings_);
std::string error_msg;
@@ -466,22 +350,7 @@
}
bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
- const std::string& output_oat_filename,
- bool output_oat_opened_from_fd,
- bool new_oat_out) {
- // Need a file when we are PIC, since we symlink over it. Refusing to symlink into FD.
- if (output_oat_opened_from_fd) {
- // TODO: installd uses --output-oat-fd. Should we change class linking logic for PIC?
- LOG(ERROR) << "No output oat filename specified, needs filename for when we are PIC";
- return false;
- }
-
- // Image was PIC. Create symlink where the oat is supposed to go.
- if (!new_oat_out) {
- LOG(ERROR) << "Oat file " << output_oat_filename << " already exists, refusing to overwrite";
- return false;
- }
-
+ const std::string& output_oat_filename) {
// Delete the original file, since we won't need it.
unlink(output_oat_filename.c_str());
@@ -799,133 +668,6 @@
object->GetDataPtrSize(pointer_size)), pointer_size);
}
-bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings,
- bool output_oat_opened_from_fd, bool new_oat_out) {
- CHECK(input_oat != nullptr);
- CHECK(output_oat != nullptr);
- CHECK_GE(input_oat->Fd(), 0);
- CHECK_GE(output_oat->Fd(), 0);
- TimingLogger::ScopedTiming t("Setup Oat File Patching", timings);
-
- std::string error_msg;
- std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat,
- PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg));
- if (elf.get() == nullptr) {
- LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
- return false;
- }
-
- MaybePic is_oat_pic = IsOatPic(elf.get());
- if (is_oat_pic >= ERROR_FIRST) {
- // Error logged by IsOatPic
- return false;
- } else if (is_oat_pic == PIC) {
- // Do not need to do ELF-file patching. Create a symlink and skip the rest.
- // Any errors will be logged by the function call.
- return ReplaceOatFileWithSymlink(input_oat->GetPath(),
- output_oat->GetPath(),
- output_oat_opened_from_fd,
- new_oat_out);
- } else {
- CHECK(is_oat_pic == NOT_PIC);
- }
-
- PatchOat p(elf.release(), delta, timings);
- t.NewTiming("Patch Oat file");
- if (!p.PatchElf()) {
- return false;
- }
-
- t.NewTiming("Writing oat file");
- if (!p.WriteElf(output_oat)) {
- return false;
- }
- return true;
-}
-
-template <typename ElfFileImpl>
-bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) {
- auto rodata_sec = oat_file->FindSectionByName(".rodata");
- if (rodata_sec == nullptr) {
- return false;
- }
- OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset);
- if (!oat_header->IsValid()) {
- LOG(ERROR) << "Elf file " << oat_file->GetFilePath() << " has an invalid oat header";
- return false;
- }
- oat_header->RelocateOat(delta_);
- return true;
-}
-
-bool PatchOat::PatchElf() {
- if (oat_file_->Is64Bit()) {
- return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64());
- } else {
- return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32());
- }
-}
-
-template <typename ElfFileImpl>
-bool PatchOat::PatchElf(ElfFileImpl* oat_file) {
- TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_);
-
- // Fix up absolute references to locations within the boot image.
- if (!oat_file->ApplyOatPatchesTo(".text", delta_)) {
- return false;
- }
-
- // Update the OatHeader fields referencing the boot image.
- if (!PatchOatHeader<ElfFileImpl>(oat_file)) {
- return false;
- }
-
- bool need_boot_oat_fixup = true;
- for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); ++i) {
- auto hdr = oat_file->GetProgramHeader(i);
- if (hdr->p_type == PT_LOAD && hdr->p_vaddr == 0u) {
- need_boot_oat_fixup = false;
- break;
- }
- }
- if (!need_boot_oat_fixup) {
- // This is an app oat file that can be loaded at an arbitrary address in memory.
- // Boot image references were patched above and there's nothing else to do.
- return true;
- }
-
- // This is a boot oat file that's loaded at a particular address and we need
- // to patch all absolute addresses, starting with ELF program headers.
-
- t.NewTiming("Fixup Elf Headers");
- // Fixup Phdr's
- oat_file->FixupProgramHeaders(delta_);
-
- t.NewTiming("Fixup Section Headers");
- // Fixup Shdr's
- oat_file->FixupSectionHeaders(delta_);
-
- t.NewTiming("Fixup Dynamics");
- oat_file->FixupDynamic(delta_);
-
- t.NewTiming("Fixup Elf Symbols");
- // Fixup dynsym
- if (!oat_file->FixupSymbols(delta_, true)) {
- return false;
- }
- // Fixup symtab
- if (!oat_file->FixupSymbols(delta_, false)) {
- return false;
- }
-
- t.NewTiming("Fixup Debug Sections");
- if (!oat_file->FixupDebugSections(delta_)) {
- return false;
- }
-
- return true;
-}
-
static int orig_argc;
static char** orig_argv;
@@ -960,32 +702,10 @@
UsageError("Usage: patchoat [options]...");
UsageError("");
UsageError(" --instruction-set=<isa>: Specifies the instruction set the patched code is");
- UsageError(" compiled for. Required if you use --input-oat-location");
- UsageError("");
- UsageError(" --input-oat-file=<file.oat>: Specifies the exact filename of the oat file to be");
- UsageError(" patched.");
- UsageError("");
- UsageError(" --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file");
- UsageError(" to be patched.");
- UsageError("");
- UsageError(" --input-vdex-fd=<file-descriptor>: Specifies the file-descriptor of the vdex file");
- UsageError(" associated with the oat file.");
- UsageError("");
- UsageError(" --input-oat-location=<file.oat>: Specifies the 'location' to read the patched");
- UsageError(" oat file from. If used one must also supply the --instruction-set");
+ UsageError(" compiled for (required).");
UsageError("");
UsageError(" --input-image-location=<file.art>: Specifies the 'location' of the image file to");
- UsageError(" be patched. If --instruction-set is not given it will use the instruction set");
- UsageError(" extracted from the --input-oat-file.");
- UsageError("");
- UsageError(" --output-oat-file=<file.oat>: Specifies the exact file to write the patched oat");
- UsageError(" file to.");
- UsageError("");
- UsageError(" --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the");
- UsageError(" patched oat file to.");
- UsageError("");
- UsageError(" --output-vdex-fd=<file-descriptor>: Specifies the file-descriptor to copy the");
- UsageError(" the vdex file associated with the patch oat file to.");
+ UsageError(" be patched.");
UsageError("");
UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched");
UsageError(" image file to.");
@@ -993,15 +713,6 @@
UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by.");
UsageError(" This value may be negative.");
UsageError("");
- UsageError(" --patched-image-location=<file.art>: Relocate the oat file to be the same as the");
- UsageError(" image at the given location. If used one must also specify the");
- UsageError(" --instruction-set flag. It will search for this image in the same way that");
- UsageError(" is done when loading one.");
- UsageError("");
- UsageError(" --lock-output: Obtain a flock on output oat file before starting.");
- UsageError("");
- UsageError(" --no-lock-output: Do not attempt to obtain a flock on output oat file.");
- UsageError("");
UsageError(" --dump-timings: dump out patch timing information");
UsageError("");
UsageError(" --no-dump-timings: do not dump out patch timing information");
@@ -1010,34 +721,6 @@
exit(EXIT_FAILURE);
}
-static bool ReadBaseDelta(const char* name, off_t* delta, std::string* error_msg) {
- CHECK(name != nullptr);
- CHECK(delta != nullptr);
- std::unique_ptr<File> file;
- if (OS::FileExists(name)) {
- file.reset(OS::OpenFileForReading(name));
- if (file.get() == nullptr) {
- *error_msg = "Failed to open file %s for reading";
- return false;
- }
- } else {
- *error_msg = "File %s does not exist";
- return false;
- }
- CHECK(file.get() != nullptr);
- ImageHeader hdr;
- if (sizeof(hdr) != file->Read(reinterpret_cast<char*>(&hdr), sizeof(hdr), 0)) {
- *error_msg = "Failed to read file %s";
- return false;
- }
- if (!hdr.IsValid()) {
- *error_msg = "%s does not contain a valid image header.";
- return false;
- }
- *delta = hdr.GetPatchDelta();
- return true;
-}
-
static int patchoat_image(TimingLogger& timings,
InstructionSet isa,
const std::string& input_image_location,
@@ -1076,293 +759,6 @@
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}
-static int patchoat_oat(TimingLogger& timings,
- InstructionSet isa,
- const std::string& patched_image_location,
- off_t base_delta,
- bool base_delta_set,
- int input_oat_fd,
- int input_vdex_fd,
- const std::string& input_oat_location,
- std::string input_oat_filename,
- bool have_input_oat,
- int output_oat_fd,
- int output_vdex_fd,
- std::string output_oat_filename,
- bool have_output_oat,
- bool lock_output,
- bool debug) {
- {
- // Only 1 of these may be set.
- uint32_t cnt = 0;
- cnt += (base_delta_set) ? 1 : 0;
- cnt += (!patched_image_location.empty()) ? 1 : 0;
- if (cnt > 1) {
- Usage("Only one of --base-offset-delta or --patched-image-location may be used.");
- } else if (cnt == 0) {
- Usage("Must specify --base-offset-delta or --patched-image-location.");
- }
- }
-
- if (!have_input_oat || !have_output_oat) {
- Usage("Both input and output oat must be supplied to patch an app odex.");
- }
-
- if (!input_oat_location.empty()) {
- if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) {
- Usage("Unable to find filename for input oat location %s", input_oat_location.c_str());
- }
- if (debug) {
- LOG(INFO) << "Using input-oat-file " << input_oat_filename;
- }
- }
-
- if ((input_oat_fd == -1) != (input_vdex_fd == -1)) {
- Usage("Either both input oat and vdex have to be passed as file descriptors or none of them");
- } else if ((output_oat_fd == -1) != (output_vdex_fd == -1)) {
- Usage("Either both output oat and vdex have to be passed as file descriptors or none of them");
- }
-
- bool match_delta = false;
- if (!patched_image_location.empty()) {
- std::string system_filename;
- bool has_system = false;
- std::string cache_filename;
- bool has_cache = false;
- bool has_android_data_unused = false;
- bool is_global_cache = false;
- if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa,
- &system_filename, &has_system, &cache_filename,
- &has_android_data_unused, &has_cache,
- &is_global_cache)) {
- Usage("Unable to determine image file for location %s", patched_image_location.c_str());
- }
- std::string patched_image_filename;
- if (has_cache) {
- patched_image_filename = cache_filename;
- } else if (has_system) {
- LOG(WARNING) << "Only image file found was in /system for image location "
- << patched_image_location;
- patched_image_filename = system_filename;
- } else {
- Usage("Unable to determine image file for location %s", patched_image_location.c_str());
- }
- if (debug) {
- LOG(INFO) << "Using patched-image-file " << patched_image_filename;
- }
-
- base_delta_set = true;
- match_delta = true;
- std::string error_msg;
- if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) {
- Usage(error_msg.c_str(), patched_image_filename.c_str());
- }
- }
-
- if (!IsAligned<kPageSize>(base_delta)) {
- Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize);
- }
-
- // We can symlink VDEX only if we have both input and output specified as filenames.
- // Store that piece of information before we possibly create bogus filenames for
- // files passed as file descriptors.
- bool symlink_vdex = !input_oat_filename.empty() && !output_oat_filename.empty();
-
- // Infer names of VDEX files.
- std::string input_vdex_filename;
- std::string output_vdex_filename;
- if (!input_oat_filename.empty()) {
- input_vdex_filename = ReplaceFileExtension(input_oat_filename, "vdex");
- }
- if (!output_oat_filename.empty()) {
- output_vdex_filename = ReplaceFileExtension(output_oat_filename, "vdex");
- }
-
- // Do we need to cleanup output files if we fail?
- bool new_oat_out = false;
- bool new_vdex_out = false;
-
- std::unique_ptr<File> input_oat;
- std::unique_ptr<File> output_oat;
-
- if (input_oat_fd != -1) {
- if (input_oat_filename.empty()) {
- input_oat_filename = "input-oat-file";
- }
- input_oat.reset(new File(input_oat_fd, input_oat_filename, false));
- if (input_oat_fd == output_oat_fd) {
- input_oat.get()->DisableAutoClose();
- }
- if (input_oat == nullptr) {
- // Unlikely, but ensure exhaustive logging in non-0 exit code case
- LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd;
- return EXIT_FAILURE;
- }
- } else {
- CHECK(!input_oat_filename.empty());
- input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
- if (input_oat == nullptr) {
- int err = errno;
- LOG(ERROR) << "Failed to open input oat file " << input_oat_filename
- << ": " << strerror(err) << "(" << err << ")";
- return EXIT_FAILURE;
- }
- }
-
- std::string error_msg;
- std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat.get(), PROT_READ, MAP_PRIVATE, &error_msg));
- if (elf.get() == nullptr) {
- LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
- return EXIT_FAILURE;
- }
- if (!elf->HasSection(".text.oat_patches")) {
- LOG(ERROR) << "missing oat patch section in input oat file " << input_oat->GetPath();
- return EXIT_FAILURE;
- }
-
- if (output_oat_fd != -1) {
- if (output_oat_filename.empty()) {
- output_oat_filename = "output-oat-file";
- }
- output_oat.reset(new File(output_oat_fd, output_oat_filename, true));
- if (output_oat == nullptr) {
- // Unlikely, but ensure exhaustive logging in non-0 exit code case
- LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd;
- }
- } else {
- CHECK(!output_oat_filename.empty());
- output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
- if (output_oat == nullptr) {
- int err = errno;
- LOG(ERROR) << "Failed to open output oat file " << output_oat_filename
- << ": " << strerror(err) << "(" << err << ")";
- }
- }
-
- // Open VDEX files if we are not symlinking them.
- std::unique_ptr<File> input_vdex;
- std::unique_ptr<File> output_vdex;
- if (symlink_vdex) {
- new_vdex_out = !OS::FileExists(output_vdex_filename.c_str());
- } else {
- if (input_vdex_fd != -1) {
- input_vdex.reset(new File(input_vdex_fd, input_vdex_filename, true));
- if (input_vdex == nullptr) {
- // Unlikely, but ensure exhaustive logging in non-0 exit code case
- LOG(ERROR) << "Failed to open input vdex file by its FD" << input_vdex_fd;
- }
- } else {
- input_vdex.reset(OS::OpenFileForReading(input_vdex_filename.c_str()));
- if (input_vdex == nullptr) {
- PLOG(ERROR) << "Failed to open input vdex file " << input_vdex_filename;
- return EXIT_FAILURE;
- }
- }
- if (output_vdex_fd != -1) {
- output_vdex.reset(new File(output_vdex_fd, output_vdex_filename, true));
- if (output_vdex == nullptr) {
- // Unlikely, but ensure exhaustive logging in non-0 exit code case
- LOG(ERROR) << "Failed to open output vdex file by its FD" << output_vdex_fd;
- }
- } else {
- output_vdex.reset(CreateOrOpen(output_vdex_filename.c_str(), &new_vdex_out));
- if (output_vdex == nullptr) {
- PLOG(ERROR) << "Failed to open output vdex file " << output_vdex_filename;
- return EXIT_FAILURE;
- }
- }
- }
-
- // TODO: get rid of this.
- auto cleanup = [&output_oat_filename, &output_vdex_filename, &new_oat_out, &new_vdex_out]
- (bool success) {
- if (!success) {
- if (new_oat_out) {
- CHECK(!output_oat_filename.empty());
- unlink(output_oat_filename.c_str());
- }
- if (new_vdex_out) {
- CHECK(!output_vdex_filename.empty());
- unlink(output_vdex_filename.c_str());
- }
- }
-
- if (kIsDebugBuild) {
- LOG(INFO) << "Cleaning up.. success? " << success;
- }
- };
-
- if (output_oat.get() == nullptr) {
- cleanup(false);
- return EXIT_FAILURE;
- }
-
- if (match_delta) {
- // Figure out what the current delta is so we can match it to the desired delta.
- off_t current_delta = 0;
- if (!ReadOatPatchDelta(elf.get(), ¤t_delta, &error_msg)) {
- LOG(ERROR) << "Unable to get current delta: " << error_msg;
- cleanup(false);
- return EXIT_FAILURE;
- }
- // Before this line base_delta is the desired final delta. We need it to be the actual amount to
- // change everything by. We subtract the current delta from it to make it this.
- base_delta -= current_delta;
- if (!IsAligned<kPageSize>(base_delta)) {
- LOG(ERROR) << "Given image file was relocated by an illegal delta";
- cleanup(false);
- return false;
- }
- }
-
- if (debug) {
- LOG(INFO) << "moving offset by " << base_delta
- << " (0x" << std::hex << base_delta << ") bytes or "
- << std::dec << (base_delta/kPageSize) << " pages.";
- }
-
- ScopedFlock output_oat_lock;
- if (lock_output) {
- if (!output_oat_lock.Init(output_oat.get(), &error_msg)) {
- LOG(ERROR) << "Unable to lock output oat " << output_oat->GetPath() << ": " << error_msg;
- cleanup(false);
- return EXIT_FAILURE;
- }
- }
-
- TimingLogger::ScopedTiming pt("patch oat", &timings);
- bool ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
- output_oat_fd >= 0, // was it opened from FD?
- new_oat_out);
- ret = FinishFile(output_oat.get(), ret);
-
- if (ret) {
- if (symlink_vdex) {
- ret = SymlinkFile(input_vdex_filename, output_vdex_filename);
- } else {
- ret = unix_file::CopyFile(*input_vdex.get(), output_vdex.get());
- }
- }
-
- if (kIsDebugBuild) {
- LOG(INFO) << "Exiting with return ... " << ret;
- }
- cleanup(ret);
- return ret ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static int ParseFd(const StringPiece& option, const char* cmdline_arg) {
- int fd;
- const char* fd_str = option.substr(strlen(cmdline_arg)).data();
- if (!ParseInt(fd_str, &fd)) {
- Usage("Failed to parse %d argument '%s' as an integer", cmdline_arg, fd_str);
- }
- if (fd < 0) {
- Usage("%s pass a negative value %d", cmdline_arg, fd);
- }
- return fd;
-}
-
static int patchoat(int argc, char **argv) {
InitLogging(argv, Runtime::Aborter);
MemMap::Init();
@@ -1384,23 +780,11 @@
// cmd line args
bool isa_set = false;
InstructionSet isa = kNone;
- std::string input_oat_filename;
- std::string input_oat_location;
- int input_oat_fd = -1;
- int input_vdex_fd = -1;
- bool have_input_oat = false;
std::string input_image_location;
- std::string output_oat_filename;
- int output_oat_fd = -1;
- int output_vdex_fd = -1;
- bool have_output_oat = false;
std::string output_image_filename;
off_t base_delta = 0;
bool base_delta_set = false;
- std::string patched_image_filename;
- std::string patched_image_location;
bool dump_timings = kIsDebugBuild;
- bool lock_output = true;
for (int i = 0; i < argc; ++i) {
const StringPiece option(argv[i]);
@@ -1415,42 +799,8 @@
if (isa == kNone) {
Usage("Unknown or invalid instruction set %s", isa_str);
}
- } else if (option.starts_with("--input-oat-location=")) {
- if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
- }
- have_input_oat = true;
- input_oat_location = option.substr(strlen("--input-oat-location=")).data();
- } else if (option.starts_with("--input-oat-file=")) {
- if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
- }
- have_input_oat = true;
- input_oat_filename = option.substr(strlen("--input-oat-file=")).data();
- } else if (option.starts_with("--input-oat-fd=")) {
- if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
- }
- have_input_oat = true;
- input_oat_fd = ParseFd(option, "--input-oat-fd=");
- } else if (option.starts_with("--input-vdex-fd=")) {
- input_vdex_fd = ParseFd(option, "--input-vdex-fd=");
} else if (option.starts_with("--input-image-location=")) {
input_image_location = option.substr(strlen("--input-image-location=")).data();
- } else if (option.starts_with("--output-oat-file=")) {
- if (have_output_oat) {
- Usage("Only one of --output-oat-file, and --output-oat-fd may be used.");
- }
- have_output_oat = true;
- output_oat_filename = option.substr(strlen("--output-oat-file=")).data();
- } else if (option.starts_with("--output-oat-fd=")) {
- if (have_output_oat) {
- Usage("Only one of --output-oat-file, --output-oat-fd may be used.");
- }
- have_output_oat = true;
- output_oat_fd = ParseFd(option, "--output-oat-fd=");
- } else if (option.starts_with("--output-vdex-fd=")) {
- output_vdex_fd = ParseFd(option, "--output-vdex-fd=");
} else if (option.starts_with("--output-image-file=")) {
output_image_filename = option.substr(strlen("--output-image-file=")).data();
} else if (option.starts_with("--base-offset-delta=")) {
@@ -1459,12 +809,6 @@
if (!ParseInt(base_delta_str, &base_delta)) {
Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str);
}
- } else if (option.starts_with("--patched-image-location=")) {
- patched_image_location = option.substr(strlen("--patched-image-location=")).data();
- } else if (option == "--lock-output") {
- lock_output = true;
- } else if (option == "--no-lock-output") {
- lock_output = false;
} else if (option == "--dump-timings") {
dump_timings = true;
} else if (option == "--no-dump-timings") {
@@ -1479,33 +823,13 @@
Usage("Instruction set must be set.");
}
- int ret;
- if (!input_image_location.empty()) {
- ret = patchoat_image(timings,
- isa,
- input_image_location,
- output_image_filename,
- base_delta,
- base_delta_set,
- debug);
- } else {
- ret = patchoat_oat(timings,
- isa,
- patched_image_location,
- base_delta,
- base_delta_set,
- input_oat_fd,
- input_vdex_fd,
- input_oat_location,
- input_oat_filename,
- have_input_oat,
- output_oat_fd,
- output_vdex_fd,
- output_oat_filename,
- have_output_oat,
- lock_output,
- debug);
- }
+ int ret = patchoat_image(timings,
+ isa,
+ input_image_location,
+ output_image_filename,
+ base_delta,
+ base_delta_set,
+ debug);
timings.EndTiming();
if (dump_timings) {
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index a519631..e15a6bc 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -44,17 +44,7 @@
class PatchOat {
public:
- // Patch only the oat file
- static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings,
- bool output_oat_opened_from_fd, // Was this using --oatput-oat-fd ?
- bool new_oat_out); // Output oat was a new file created by us?
-
- // Patch only the image (art file)
- static bool Patch(const std::string& art_location, off_t delta, File* art_out, InstructionSet isa,
- TimingLogger* timings);
-
- // Patch both the image and the oat file
- static bool Patch(const std::string& art_location,
+ static bool Patch(const std::string& image_location,
off_t delta,
const std::string& output_directory,
InstructionSet isa,
@@ -64,18 +54,11 @@
PatchOat(PatchOat&&) = default;
private:
- // Takes ownership only of the ElfFile. All other pointers are only borrowed.
- PatchOat(ElfFile* oat_file, off_t delta, TimingLogger* timings)
- : oat_file_(oat_file), image_(nullptr), bitmap_(nullptr), heap_(nullptr), delta_(delta),
- isa_(kNone), space_map_(nullptr), timings_(timings) {}
- PatchOat(InstructionSet isa, MemMap* image, gc::accounting::ContinuousSpaceBitmap* bitmap,
- MemMap* heap, off_t delta, TimingLogger* timings)
- : image_(image), bitmap_(bitmap), heap_(heap),
- delta_(delta), isa_(isa), space_map_(nullptr), timings_(timings) {}
- PatchOat(InstructionSet isa, ElfFile* oat_file, MemMap* image,
+ // All pointers are only borrowed.
+ PatchOat(InstructionSet isa, MemMap* image,
gc::accounting::ContinuousSpaceBitmap* bitmap, MemMap* heap, off_t delta,
std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>>* map, TimingLogger* timings)
- : oat_file_(oat_file), image_(image), bitmap_(bitmap), heap_(heap),
+ : image_(image), bitmap_(bitmap), heap_(heap),
delta_(delta), isa_(isa), space_map_(map), timings_(timings) {}
// Was the .art image at image_path made with --compile-pic ?
@@ -94,9 +77,7 @@
// Attempt to replace the file with a symlink
// Returns false if it fails
static bool ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
- const std::string& output_oat_filename,
- bool output_oat_opened_from_fd,
- bool new_oat_out); // Output oat was newly created?
+ const std::string& output_oat_filename);
static void BitmapCallback(mirror::Object* obj, void* arg)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -108,13 +89,6 @@
void FixupMethod(ArtMethod* object, ArtMethod* copy)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Patches oat in place, modifying the oat_file given to the constructor.
- bool PatchElf();
- template <typename ElfFileImpl>
- bool PatchElf(ElfFileImpl* oat_file);
- template <typename ElfFileImpl>
- bool PatchOatHeader(ElfFileImpl* oat_file);
-
bool PatchImage(bool primary_image) REQUIRES_SHARED(Locks::mutator_lock_);
void PatchArtFields(const ImageHeader* image_header) REQUIRES_SHARED(Locks::mutator_lock_);
void PatchArtMethods(const ImageHeader* image_header) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -128,7 +102,6 @@
void PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots)
REQUIRES_SHARED(Locks::mutator_lock_);
- bool WriteElf(File* out);
bool WriteImage(File* out);
template <typename T>
@@ -175,19 +148,6 @@
return reinterpret_cast<T*>(ret);
}
- template <typename T>
- T RelocatedAddressOfIntPointer(T obj) const {
- if (obj == 0) {
- return obj;
- }
- T ret = obj + delta_;
- // Trim off high bits in case negative relocation with 64 bit patchoat.
- if (Is32BitISA()) {
- ret = static_cast<T>(static_cast<uint32_t>(ret));
- }
- return ret;
- }
-
bool Is32BitISA() const {
return InstructionSetPointerSize(isa_) == PointerSize::k32;
}
@@ -213,8 +173,6 @@
mirror::Object* const copy_;
};
- // The elf file we are patching.
- std::unique_ptr<ElfFile> oat_file_;
// A mmap of the image we are patching. This is modified.
const MemMap* const image_;
// The bitmap over the image within the heap we are patching. This is not modified.
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 96976d9..9c20740 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -121,7 +121,7 @@
inline uint32_t ArtMethod::GetDexMethodIndex() {
DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
GetDeclaringClass()->IsErroneous());
- return dex_method_index_;
+ return GetDexMethodIndexUnchecked();
}
inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 11dcc35..2c31f6c 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -322,6 +322,9 @@
// Number of 32bit registers that would be required to hold all the arguments
static size_t NumArgRegisters(const StringPiece& shorty);
+ ALWAYS_INLINE uint32_t GetDexMethodIndexUnchecked() {
+ return dex_method_index_;
+ }
ALWAYS_INLINE uint32_t GetDexMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
void SetDexMethodIndex(uint32_t new_idx) {
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index e4972da..4b15a22 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -90,7 +90,7 @@
art::Thread::SelfOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_pos.
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 198 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 34 * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
art::Thread::ThreadLocalPosOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_end.
@@ -98,11 +98,13 @@
ADD_TEST_EQ(THREAD_LOCAL_END_OFFSET,
art::Thread::ThreadLocalEndOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_objects.
-#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + 2 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
art::Thread::ThreadLocalObjectsOffset<POINTER_SIZE>().Int32Value())
+
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
-#define THREAD_CURRENT_IBASE_OFFSET (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__)
+#define THREAD_CURRENT_IBASE_OFFSET \
+ (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 164) * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 129c93f..448b460 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2711,10 +2711,6 @@
CHECK(h_new_class.Get() != nullptr) << descriptor;
CHECK(h_new_class->IsResolved()) << descriptor;
- // Update the dex cache of where the class is defined. Inlining depends on having
- // this filled.
- h_new_class->GetDexCache()->SetResolvedType(h_new_class->GetDexTypeIndex(), h_new_class.Get());
-
// Instrumentation may have updated entrypoints for all methods of all
// classes. However it could not update methods of this class while we
// were loading it. Now the class is resolved, we can update entrypoints
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 42108d8..bbe7280 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -460,7 +460,6 @@
protected:
virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
CommonRuntimeTest::SetUpRuntimeOptions(options);
- options->push_back(std::make_pair("-Xexperimental:method-handles", nullptr));
}
};
@@ -757,6 +756,7 @@
struct EmulatedStackFrameOffsets : public CheckOffsets<mirror::EmulatedStackFrame> {
EmulatedStackFrameOffsets() : CheckOffsets<mirror::EmulatedStackFrame>(
false, "Ldalvik/system/EmulatedStackFrame;") {
+ addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, callsite_type_), "callsiteType");
addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, references_), "references");
addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, stack_frame_), "stackFrame");
addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, type_), "type");
@@ -899,7 +899,6 @@
dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
const DexFile& dex_file = klass->GetDexFile();
- EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
EXPECT_OBJ_PTR_EQ(
class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
klass);
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index b0c4597..8b1b5a3 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -160,7 +160,7 @@
// image at GetImageLocation(). This is used for testing mismatched
// image checksums in the oat_file_assistant_tests.
std::string GetImageLocation2() const {
- return GetImageDirectory() + "/core-npic.art";
+ return GetImageDirectory() + "/core-multi.art";
}
std::string GetDexSrc1() const {
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 5ff95b4..7d6f866 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -52,21 +52,19 @@
// suspended while executing it.
ScopedAssertNoThreadSuspension sants(__FUNCTION__);
+ if (inline_info.EncodesArtMethodAtDepth(encoding, inlining_depth)) {
+ return inline_info.GetArtMethodAtDepth(encoding, inlining_depth);
+ }
+
uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth);
- InvokeType invoke_type = static_cast<InvokeType>(
- inline_info.GetInvokeTypeAtDepth(encoding, inlining_depth));
- ArtMethod* inlined_method = outer_method->GetDexCacheResolvedMethod(method_index,
- kRuntimePointerSize);
- if (!inlined_method->IsRuntimeMethod()) {
+ if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) {
+ // "charAt" special case. It is the only non-leaf method we inline across dex files.
+ ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
+ DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index);
return inlined_method;
}
- // The method in the dex cache is the runtime method responsible for invoking
- // the stub that will then update the dex cache. Therefore, we need to do the
- // resolution ourselves.
-
- // We first find the dex cache of our caller. If it is the outer method, we can directly
- // use its dex cache. Otherwise, we also need to resolve our caller.
+ // Find which method did the call in the inlining hierarchy.
ArtMethod* caller = outer_method;
if (inlining_depth != 0) {
caller = GetResolvedMethod(outer_method,
@@ -74,51 +72,38 @@
encoding,
inlining_depth - 1);
}
- DCHECK_EQ(caller->GetDexCache(), outer_method->GetDexCache())
- << "Compiler only supports inlining calls within the same dex cache";
- const DexFile* dex_file = outer_method->GetDexFile();
- const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
- if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) {
- // "charAt" special case. It is the only non-leaf method we inline across dex files.
- if (kIsDebugBuild) {
- const char* name = dex_file->StringDataByIdx(method_id.name_idx_);
- DCHECK_EQ(std::string(name), "charAt");
- DCHECK_EQ(std::string(dex_file->GetMethodShorty(method_id)), "CI")
- << std::string(dex_file->GetMethodShorty(method_id));
- DCHECK_EQ(std::string(dex_file->StringByTypeIdx(method_id.class_idx_)), "Ljava/lang/String;")
- << std::string(dex_file->StringByTypeIdx(method_id.class_idx_));
- }
- mirror::Class* cls =
- Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangString);
- // Update the dex cache for future lookups.
- caller->GetDexCache()->SetResolvedType(method_id.class_idx_, cls);
- inlined_method = cls->FindVirtualMethod("charAt", "(I)C", kRuntimePointerSize);
- } else {
- mirror::Class* klass = caller->GetDexCache()->GetResolvedType(method_id.class_idx_);
- DCHECK_EQ(klass->GetDexCache(), caller->GetDexCache())
- << "Compiler only supports inlining calls within the same dex cache";
- switch (invoke_type) {
- case kDirect:
- case kStatic:
- inlined_method =
- klass->FindDirectMethod(klass->GetDexCache(), method_index, kRuntimePointerSize);
- break;
- case kSuper:
- case kVirtual:
- inlined_method =
- klass->FindVirtualMethod(klass->GetDexCache(), method_index, kRuntimePointerSize);
- break;
- default:
- LOG(FATAL) << "Unimplemented inlined invocation type: " << invoke_type;
- UNREACHABLE();
+ // Lookup the declaring class of the inlined method.
+ const DexFile* dex_file = caller->GetDexFile();
+ const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
+ const char* descriptor = dex_file->StringByTypeIdx(method_id.class_idx_);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Thread* self = Thread::Current();
+ mirror::ClassLoader* class_loader = caller->GetDeclaringClass()->GetClassLoader();
+ mirror::Class* klass = class_linker->LookupClass(self, descriptor, class_loader);
+ if (klass == nullptr) {
+ LOG(FATAL) << "Could not find an inlined method from an .oat file: "
+ << "the class " << descriptor << " was not found in the class loader of "
+ << caller->PrettyMethod() << ". "
+ << "This must be due to playing wrongly with class loaders";
+ }
+
+ // Lookup the method.
+ const char* method_name = dex_file->GetMethodName(method_id);
+ const Signature signature = dex_file->GetMethodSignature(method_id);
+
+ ArtMethod* inlined_method =
+ klass->FindDeclaredDirectMethod(method_name, signature, kRuntimePointerSize);
+ if (inlined_method == nullptr) {
+ inlined_method = klass->FindDeclaredVirtualMethod(method_name, signature, kRuntimePointerSize);
+ if (inlined_method == nullptr) {
+ LOG(FATAL) << "Could not find an inlined method from an .oat file: "
+ << "the class " << descriptor << " does not have "
+ << method_name << signature << " declared. "
+ << "This must be due to duplicate classes or playing wrongly with class loaders";
}
}
- // Update the dex cache for future lookups. Note that for static methods, this is safe
- // when the class is being initialized, as the entrypoint for the ArtMethod is at
- // this point still the resolution trampoline.
- outer_method->SetDexCacheResolvedMethod(method_index, inlined_method, kRuntimePointerSize);
return inlined_method;
}
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 96e17da..6301f93 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -117,15 +117,14 @@
sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, checkpoint_function, active_suspend_barriers,
sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, active_suspend_barriers, jni_entrypoints,
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, active_suspend_barriers, thread_local_start,
sizeof(Thread::tls_ptr_sized_values::active_suspend_barriers));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, jni_entrypoints, sizeof(size_t));
// Skip across the entrypoints structures.
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_start, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_objects, sizeof(void*));
-
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, mterp_current_ibase, sizeof(size_t));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_current_ibase, mterp_default_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_default_ibase, mterp_alt_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_alt_ibase, rosalloc_runs, sizeof(void*));
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 916f1cf..8f978e1 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -35,7 +35,6 @@
protected:
virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
CommonRuntimeTest::SetUpRuntimeOptions(options);
- options->push_back(std::make_pair("-Xexperimental:method-handles", nullptr));
}
};
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index d607040..978cc32 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -195,6 +195,7 @@
// Step 5: Construct the EmulatedStackFrame object.
Handle<EmulatedStackFrame> sf(hs.NewHandle(
ObjPtr<EmulatedStackFrame>::DownCast(StaticClass()->AllocObject(self))));
+ sf->SetFieldObject<false>(CallsiteTypeOffset(), caller_type.Get());
sf->SetFieldObject<false>(TypeOffset(), callee_type.Get());
sf->SetFieldObject<false>(ReferencesOffset(), references.Get());
sf->SetFieldObject<false>(StackFrameOffset(), stack_frame.Get());
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index d83a536..ddd84a1 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -81,6 +81,10 @@
OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, stack_frame_));
}
+ static MemberOffset CallsiteTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(EmulatedStackFrame, callsite_type_));
+ }
+
static MemberOffset TypeOffset() {
return MemberOffset(OFFSETOF_MEMBER(EmulatedStackFrame, type_));
}
@@ -93,6 +97,7 @@
return MemberOffset(OFFSETOF_MEMBER(EmulatedStackFrame, stack_frame_));
}
+ HeapReference<mirror::MethodType> callsite_type_;
HeapReference<mirror::ObjectArray<mirror::Object>> references_;
HeapReference<mirror::ByteArray> stack_frame_;
HeapReference<mirror::MethodType> type_;
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3341f53..5438a6d 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -428,6 +428,10 @@
}
auto ret = hs.NewHandle(mirror::ObjectArray<mirror::Method>::Alloc(
soa.Self(), mirror::Method::ArrayClass(), num_methods));
+ if (ret.Get() == nullptr) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
num_methods = 0;
for (auto& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
auto modifiers = m.GetAccessFlags();
diff --git a/runtime/oat.h b/runtime/oat.h
index f2d457c..ab03252 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '9', '7', '\0' }; // HLoadClass/kBssEntry change
+ static constexpr uint8_t kOatVersion[] = { '0', '9', '8', '\0' }; // art::Thread fields reorder
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 53ff8ea..3825c41 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -30,6 +30,7 @@
*/
#include <string>
+#include <type_traits>
#include <vector>
#include <jni.h>
@@ -37,6 +38,7 @@
#include "openjdkjvmti/jvmti.h"
#include "art_jvmti.h"
+#include "base/logging.h"
#include "base/mutex.h"
#include "events-inl.h"
#include "jni_env_ext-inl.h"
@@ -1168,7 +1170,57 @@
}
static jvmtiError SetVerboseFlag(jvmtiEnv* env, jvmtiVerboseFlag flag, jboolean value) {
- return ERR(NOT_IMPLEMENTED);
+ if (flag == jvmtiVerboseFlag::JVMTI_VERBOSE_OTHER) {
+ // OTHER is special, as it's 0, so can't do a bit check.
+ bool val = (value == JNI_TRUE) ? true : false;
+
+ art::gLogVerbosity.collector = val;
+ art::gLogVerbosity.compiler = val;
+ art::gLogVerbosity.deopt = val;
+ art::gLogVerbosity.heap = val;
+ art::gLogVerbosity.jdwp = val;
+ art::gLogVerbosity.jit = val;
+ art::gLogVerbosity.monitor = val;
+ art::gLogVerbosity.oat = val;
+ art::gLogVerbosity.profiler = val;
+ art::gLogVerbosity.signals = val;
+ art::gLogVerbosity.simulator = val;
+ art::gLogVerbosity.startup = val;
+ art::gLogVerbosity.third_party_jni = val;
+ art::gLogVerbosity.threads = val;
+ art::gLogVerbosity.verifier = val;
+ art::gLogVerbosity.image = val;
+
+ // Note: can't switch systrace_lock_logging. That requires changing entrypoints.
+
+ art::gLogVerbosity.agents = val;
+ } else {
+ // Spec isn't clear whether "flag" is a mask or supposed to be single. We implement the mask
+ // semantics.
+ constexpr std::underlying_type<jvmtiVerboseFlag>::type kMask =
+ jvmtiVerboseFlag::JVMTI_VERBOSE_GC |
+ jvmtiVerboseFlag::JVMTI_VERBOSE_CLASS |
+ jvmtiVerboseFlag::JVMTI_VERBOSE_JNI;
+ if ((flag & ~kMask) != 0) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ bool val = (value == JNI_TRUE) ? true : false;
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_GC) != 0) {
+ art::gLogVerbosity.gc = val;
+ }
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_CLASS) != 0) {
+ art::gLogVerbosity.class_linker = val;
+ }
+
+ if ((flag & jvmtiVerboseFlag::JVMTI_VERBOSE_JNI) != 0) {
+ art::gLogVerbosity.jni = val;
+ }
+ }
+
+ return ERR(NONE);
}
static jvmtiError GetJLocationFormat(jvmtiEnv* env, jvmtiJlocationFormat* format_ptr) {
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index e1022b0..a72159b 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -763,8 +763,6 @@
"(Enable new and experimental agent support)\n");
UsageMessage(stream, " -Xexperimental:agents"
"(Enable new and experimental agent support)\n");
- UsageMessage(stream, " -Xexperimental:method-handles"
- "(Enable new and experimental method handles support)\n");
UsageMessage(stream, "\n");
UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 8fc211c..a87e1c1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -304,7 +304,7 @@
}
bool IsMethodHandlesEnabled() const {
- return experimental_flags_ & ExperimentalFlags::kMethodHandles;
+ return true;
}
void DisallowNewSystemWeaks() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index d1970fe..ecabf9a 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -117,7 +117,7 @@
RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback)
RUNTIME_OPTIONS_KEY (std::string, CpuAbiList)
RUNTIME_OPTIONS_KEY (std::string, Fingerprint)
-RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{none, agents, method-handles}
+RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{none, agents}
RUNTIME_OPTIONS_KEY (std::vector<ti::Agent>, AgentLib) // -agentlib:<libname>=<options>, Requires -Xexperimental:agents
RUNTIME_OPTIONS_KEY (std::vector<ti::Agent>, AgentPath) // -agentpath:<libname>=<options>, Requires -Xexperimental:agents
RUNTIME_OPTIONS_KEY (std::vector<Plugin>, Plugins) // -Xplugin:<library> Requires -Xexperimental:runtime-plugins
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index a7e7c21..9ebf9a7 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -18,8 +18,9 @@
#include <stdint.h>
+#include "art_method.h"
#include "indenter.h"
-#include "invoke_type.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -106,7 +107,7 @@
<< "InlineInfoEncoding"
<< " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
<< ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
- << ", invoke_type_bit_offset=" << static_cast<uint32_t>(invoke_type_bit_offset_)
+ << ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_)
<< ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
<< ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
<< ")\n";
@@ -230,12 +231,16 @@
vios->Stream()
<< " At depth " << i
<< std::hex
- << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i)
- << std::dec
- << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i)
- << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(inline_info_encoding,
- i))
- << ")\n";
+ << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i);
+ if (EncodesArtMethodAtDepth(inline_info_encoding, i)) {
+ ScopedObjectAccess soa(Thread::Current());
+ vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod();
+ } else {
+ vios->Stream()
+ << std::dec
+ << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i);
+ }
+ vios->Stream() << ")\n";
if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
CodeInfoEncoding encoding = code_info.ExtractEncoding();
DexRegisterMap dex_register_map =
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 5e556be..15d7816 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -35,6 +35,7 @@
// Size of Dex virtual registers.
static constexpr size_t kVRegSize = 4;
+class ArtMethod;
class CodeInfo;
class StackMapEncoding;
struct CodeInfoEncoding;
@@ -887,7 +888,7 @@
public:
void SetFromSizes(size_t method_index_max,
size_t dex_pc_max,
- size_t invoke_type_max,
+ size_t extra_data_max,
size_t dex_register_map_size) {
total_bit_size_ = kMethodIndexBitOffset;
total_bit_size_ += MinimumBitsToStore(method_index_max);
@@ -899,8 +900,8 @@
total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
}
- invoke_type_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
- total_bit_size_ += MinimumBitsToStore(invoke_type_max);
+ extra_data_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
+ total_bit_size_ += MinimumBitsToStore(extra_data_max);
// We also need +1 for kNoDexRegisterMap, but since the size is strictly
// greater than any offset we might try to encode, we already implicitly have it.
@@ -912,10 +913,10 @@
return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_);
}
ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
- return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */);
+ return FieldEncoding(dex_pc_bit_offset_, extra_data_bit_offset_, -1 /* min_value */);
}
- ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
- return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_);
+ ALWAYS_INLINE FieldEncoding GetExtraDataEncoding() const {
+ return FieldEncoding(extra_data_bit_offset_, dex_register_map_bit_offset_);
}
ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */);
@@ -930,7 +931,7 @@
static constexpr uint8_t kIsLastBitOffset = 0;
static constexpr uint8_t kMethodIndexBitOffset = 1;
uint8_t dex_pc_bit_offset_;
- uint8_t invoke_type_bit_offset_;
+ uint8_t extra_data_bit_offset_;
uint8_t dex_register_map_bit_offset_;
uint8_t total_bit_size_;
};
@@ -938,7 +939,11 @@
/**
* Inline information for a specific PC. The information is of the form:
*
- * [is_last, method_index, dex_pc, invoke_type, dex_register_map_offset]+.
+ * [is_last,
+ * method_index (or ArtMethod high bits),
+ * dex_pc,
+ * extra_data (ArtMethod low bits or 1),
+ * dex_register_map_offset]+.
*/
class InlineInfo {
public:
@@ -960,6 +965,7 @@
ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
uint32_t depth) const {
+ DCHECK(!EncodesArtMethodAtDepth(encoding, depth));
return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
}
@@ -980,15 +986,28 @@
encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc);
}
- ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
- uint32_t depth) const {
- return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth));
+ ALWAYS_INLINE bool EncodesArtMethodAtDepth(const InlineInfoEncoding& encoding,
+ uint32_t depth) const {
+ return (encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)) & 1) == 0;
}
- ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
- uint32_t depth,
- uint32_t invoke_type) {
- encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
+ ALWAYS_INLINE void SetExtraDataAtDepth(const InlineInfoEncoding& encoding,
+ uint32_t depth,
+ uint32_t extra_data) {
+ encoding.GetExtraDataEncoding().Store(GetRegionAtDepth(encoding, depth), extra_data);
+ }
+
+ ALWAYS_INLINE ArtMethod* GetArtMethodAtDepth(const InlineInfoEncoding& encoding,
+ uint32_t depth) const {
+ uint32_t low_bits = encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth));
+ uint32_t high_bits = encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
+ if (high_bits == 0) {
+ return reinterpret_cast<ArtMethod*>(low_bits);
+ } else {
+ uint64_t address = high_bits;
+ address = address << 32;
+ return reinterpret_cast<ArtMethod*>(address | low_bits);
+ }
}
ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
diff --git a/runtime/thread.h b/runtime/thread.h
index 3958c10..2b451bc 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1426,7 +1426,7 @@
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0),
last_no_thread_suspension_cause(nullptr), checkpoint_function(nullptr),
- thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_start(nullptr),
+ thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr),
thread_local_objects(0), mterp_current_ibase(nullptr), mterp_default_ibase(nullptr),
mterp_alt_ibase(nullptr), thread_local_alloc_stack_top(nullptr),
thread_local_alloc_stack_end(nullptr), nested_signal_state(nullptr),
@@ -1545,21 +1545,21 @@
// to avoid additional cost of a mutex and a condition variable, as used in art::Barrier.
AtomicInteger* active_suspend_barriers[kMaxSuspendBarriers];
- // Entrypoint function pointers.
- // TODO: move this to more of a global offset table model to avoid per-thread duplication.
- JniEntryPoints jni_entrypoints;
- QuickEntryPoints quick_entrypoints;
+ // Thread-local allocation pointer. Moved here to force alignment for thread_local_pos on ARM.
+ uint8_t* thread_local_start;
// thread_local_pos and thread_local_end must be consecutive for ldrd and are 8 byte aligned for
// potentially better performance.
uint8_t* thread_local_pos;
uint8_t* thread_local_end;
- // Thread-local allocation pointer.
- uint8_t* thread_local_start;
-
size_t thread_local_objects;
+ // Entrypoint function pointers.
+ // TODO: move this to more of a global offset table model to avoid per-thread duplication.
+ JniEntryPoints jni_entrypoints;
+ QuickEntryPoints quick_entrypoints;
+
// Mterp jump table bases.
void* mterp_current_ibase;
void* mterp_default_ibase;
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 3b114a9..bb9844a 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -61,7 +61,7 @@
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- static constexpr uint8_t kVdexVersion[] = { '0', '0', '1', '\0' };
+ static constexpr uint8_t kVdexVersion[] = { '0', '0', '2', '\0' }; // Handle verify-profile
uint8_t magic_[4];
uint8_t version_[4];
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index a5b275c..507ea16 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -103,6 +103,7 @@
jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
jmethodID WellKnownClasses::java_lang_Short_valueOf;
+jmethodID WellKnownClasses::java_lang_String_charAt;
jmethodID WellKnownClasses::java_lang_System_runFinalization = nullptr;
jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException;
jmethodID WellKnownClasses::java_lang_Thread_init;
@@ -337,6 +338,7 @@
java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
+ java_lang_String_charAt = CacheMethod(env, java_lang_String, false, "charAt", "(I)C");
java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 371be61..b3ce3d1 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -113,6 +113,7 @@
static jmethodID java_lang_reflect_Proxy_invoke;
static jmethodID java_lang_Runtime_nativeLoad;
static jmethodID java_lang_Short_valueOf;
+ static jmethodID java_lang_String_charAt;
static jmethodID java_lang_System_runFinalization;
static jmethodID java_lang_Thread_dispatchUncaughtException;
static jmethodID java_lang_Thread_init;
diff --git a/test/080-oom-throw/expected.txt b/test/080-oom-throw/expected.txt
index 904393b..0967278 100644
--- a/test/080-oom-throw/expected.txt
+++ b/test/080-oom-throw/expected.txt
@@ -1,3 +1,4 @@
Test reflection correctly threw
+Test reflection2 correctly threw
NEW_ARRAY correctly threw OOME
NEW_INSTANCE correctly threw OOME
diff --git a/test/080-oom-throw/src/Main.java b/test/080-oom-throw/src/Main.java
index 0ae92a9..a6c18b7 100644
--- a/test/080-oom-throw/src/Main.java
+++ b/test/080-oom-throw/src/Main.java
@@ -53,6 +53,30 @@
}
}
+ public static Object eatAllMemory() {
+ Object[] result = null;
+ int size = 1000000;
+ while (result == null && size != 0) {
+ try {
+ result = new Object[size];
+ } catch (OutOfMemoryError oome) {
+ size /= 2;
+ }
+ }
+ if (result != null) {
+ int index = 0;
+ while (index != result.length && size != 0) {
+ try {
+ result[index] = new byte[size];
+ ++index;
+ } catch (OutOfMemoryError oome) {
+ size /= 2;
+ }
+ }
+ }
+ return result;
+ }
+
static boolean triggerArrayOOM() {
ArrayMemEater.blowup(new char[128 * 1024][]);
return ArrayMemEater.sawOome;
@@ -74,6 +98,9 @@
if (triggerReflectionOOM()) {
System.out.println("Test reflection correctly threw");
}
+ if (triggerReflectionOOM2()) {
+ System.out.println("Test reflection2 correctly threw");
+ }
if (triggerArrayOOM()) {
System.out.println("NEW_ARRAY correctly threw OOME");
@@ -125,4 +152,20 @@
}
return true;
}
+
+ static boolean triggerReflectionOOM2() {
+ Object memory = eatAllMemory();
+ boolean result = false;
+ try {
+ Main.class.getDeclaredMethods();
+ } catch (OutOfMemoryError e) {
+ result = true;
+ }
+ if (!result) {
+ boolean memoryWasAllocated = (memory != null);
+ memory = null;
+ System.out.println("memoryWasAllocated = " + memoryWasAllocated);
+ }
+ return result;
+ }
}
diff --git a/test/633-checker-rtp-getclass/expected.txt b/test/633-checker-rtp-getclass/expected.txt
new file mode 100644
index 0000000..a178d04
--- /dev/null
+++ b/test/633-checker-rtp-getclass/expected.txt
@@ -0,0 +1,3 @@
+2
+3
+6
diff --git a/test/633-checker-rtp-getclass/info.txt b/test/633-checker-rtp-getclass/info.txt
new file mode 100644
index 0000000..e98a0ac
--- /dev/null
+++ b/test/633-checker-rtp-getclass/info.txt
@@ -0,0 +1,3 @@
+Regression test for the RTP pass of the compiler, which
+used the wrong block when bounding a type after a obj.getClass()
+check.
diff --git a/test/633-checker-rtp-getclass/src/Main.java b/test/633-checker-rtp-getclass/src/Main.java
new file mode 100644
index 0000000..f29c139
--- /dev/null
+++ b/test/633-checker-rtp-getclass/src/Main.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println($opt$noinline$foo(new Main()));
+ System.out.println($opt$noinline$foo(new SubMain()));
+ System.out.println($opt$noinline$foo(new SubSubMain()));
+ }
+
+
+ // Checker test to make sure the only inlined instruction is
+ // SubMain.bar.
+ /// CHECK-START: int Main.$opt$noinline$foo(Main) inliner (after)
+ /// CHECK-DAG: InvokeVirtual method_name:Main.foo
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 3
+ /// CHECK: begin_block
+ /// CHECK: BoundType klass:SubMain
+ /// CHECK: Return [<<Const>>]
+ /// CHECK-NOT: begin_block
+ /// CHECK: end_block
+ public static int $opt$noinline$foo(Main o) {
+ if (doThrow) { throw new Error(); }
+ // To exercise the bug on Jack, we need two getClass compares.
+ if (o.getClass() == Main.class || o.getClass() != SubMain.class) {
+ return o.foo();
+ } else {
+ // We used to wrongly bound the type of o to `Main` here and then realize that's
+ // impossible and mark this branch as dead.
+ return o.bar();
+ }
+ }
+
+ public int bar() {
+ return 1;
+ }
+
+ public int foo() {
+ return 2;
+ }
+
+ public static boolean doThrow = false;
+}
+
+class SubMain extends Main {
+ public int bar() {
+ return 3;
+ }
+
+ public int foo() {
+ return 4;
+ }
+}
+
+class SubSubMain extends SubMain {
+ public int bar() {
+ return 5;
+ }
+
+ public int foo() {
+ return 6;
+ }
+}
diff --git a/test/634-vdex-duplicate/expected.txt b/test/634-vdex-duplicate/expected.txt
new file mode 100644
index 0000000..557db03
--- /dev/null
+++ b/test/634-vdex-duplicate/expected.txt
@@ -0,0 +1 @@
+Hello World
diff --git a/test/634-vdex-duplicate/info.txt b/test/634-vdex-duplicate/info.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/634-vdex-duplicate/info.txt
diff --git a/test/953-invoke-polymorphic-compiler/run b/test/634-vdex-duplicate/run
old mode 100755
new mode 100644
similarity index 71%
rename from test/953-invoke-polymorphic-compiler/run
rename to test/634-vdex-duplicate/run
index a9f1822..1ccb841
--- a/test/953-invoke-polymorphic-compiler/run
+++ b/test/634-vdex-duplicate/run
@@ -1,12 +1,12 @@
#!/bin/bash
#
-# Copyright 2016 The Android Open Source Project
+# 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
+# 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,
@@ -14,7 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
+exec ${RUN} -Xcompiler-option --compiler-filter=verify-profile --vdex-filter speed --vdex "${@}"
diff --git a/test/634-vdex-duplicate/src/Main.java b/test/634-vdex-duplicate/src/Main.java
new file mode 100644
index 0000000..2283106
--- /dev/null
+++ b/test/634-vdex-duplicate/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
diff --git a/test/634-vdex-duplicate/src/sun/misc/Unsafe.java b/test/634-vdex-duplicate/src/sun/misc/Unsafe.java
new file mode 100644
index 0000000..c32868c
--- /dev/null
+++ b/test/634-vdex-duplicate/src/sun/misc/Unsafe.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package sun.misc;
+
+public class Unsafe {
+}
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 3a475c6..052fb9a 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -22,6 +22,9 @@
#include "base/macros.h"
#include "openjdkjvmti/jvmti.h"
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
namespace art {
namespace Test901HelloTi {
@@ -72,9 +75,22 @@
CHECK_CALL_SUCCESS(env->DisposeEnvironment());
CHECK_CALL_SUCCESS(env2->DisposeEnvironment());
#undef CHECK_CALL_SUCCESS
+
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+
return JNI_OK;
}
+extern "C" JNIEXPORT void JNICALL Java_Main_setVerboseFlag(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jint iflag, jboolean val) {
+ jvmtiVerboseFlag flag = static_cast<jvmtiVerboseFlag>(iflag);
+ jvmtiError result = jvmti_env->SetVerboseFlag(flag, val);
+ JvmtiErrorToException(env, result);
+}
} // namespace Test901HelloTi
} // namespace art
diff --git a/test/901-hello-ti-agent/expected.txt b/test/901-hello-ti-agent/expected.txt
index 414eb3b..2aee99b 100644
--- a/test/901-hello-ti-agent/expected.txt
+++ b/test/901-hello-ti-agent/expected.txt
@@ -1,2 +1,8 @@
Loaded Agent for test 901-hello-ti-agent
Hello, world!
+0
+1
+2
+4
+8
+JVMTI_ERROR_ILLEGAL_ARGUMENT
diff --git a/test/901-hello-ti-agent/src/Main.java b/test/901-hello-ti-agent/src/Main.java
index 1ef6289..775e5c2 100644
--- a/test/901-hello-ti-agent/src/Main.java
+++ b/test/901-hello-ti-agent/src/Main.java
@@ -16,6 +16,26 @@
public class Main {
public static void main(String[] args) {
+ System.loadLibrary(args[1]);
+
System.out.println("Hello, world!");
+
+ set(0); // OTHER
+ set(1); // GC
+ set(2); // CLASS
+ set(4); // JNI
+ set(8); // Error.
}
+
+ private static void set(int i) {
+ System.out.println(i);
+ try {
+ setVerboseFlag(i, true);
+ setVerboseFlag(i, false);
+ } catch (RuntimeException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ private static native void setVerboseFlag(int flag, boolean value);
}
diff --git a/test/954-invoke-polymorphic-verifier/run b/test/954-invoke-polymorphic-verifier/run
deleted file mode 100755
index a9f1822..0000000
--- a/test/954-invoke-polymorphic-verifier/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/955-methodhandles-smali/run b/test/955-methodhandles-smali/run
deleted file mode 100755
index a9f1822..0000000
--- a/test/955-methodhandles-smali/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/956-methodhandles/run b/test/956-methodhandles/run
deleted file mode 100755
index a9f1822..0000000
--- a/test/956-methodhandles/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 17b56b4..f8daba6 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -76,6 +76,7 @@
testStringConstructors();
testReturnValueConversions();
testVariableArity();
+ testVariableArity_MethodHandles_bind();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -1466,4 +1467,23 @@
fail();
} catch (WrongMethodTypeException e) {}
}
+
+ // The same tests as the above, except that we use use MethodHandles.bind instead of
+ // MethodHandle.bindTo.
+ public static void testVariableArity_MethodHandles_bind() throws Throwable {
+ VariableArityTester vat = new VariableArityTester();
+ MethodHandle mh = MethodHandles.lookup().bind(vat, "update",
+ MethodType.methodType(String.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+
+ assertEquals("[]", mh.invoke());
+ assertEquals("[true, false, true]", mh.invoke(true, false, true));
+ assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true}));
+ assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true)));
+
+ try {
+ mh.invoke(true, true, 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
}
diff --git a/test/957-methodhandle-transforms/run b/test/957-methodhandle-transforms/run
deleted file mode 100755
index a9f1822..0000000
--- a/test/957-methodhandle-transforms/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/957-methodhandle-transforms/src/Main.java b/test/957-methodhandle-transforms/src/Main.java
index 9e79ff4..eebf55f 100644
--- a/test/957-methodhandle-transforms/src/Main.java
+++ b/test/957-methodhandle-transforms/src/Main.java
@@ -33,6 +33,7 @@
testBindTo();
testFilterReturnValue();
testPermuteArguments();
+ testInvokers();
}
public static void testThrowException() throws Throwable {
@@ -888,6 +889,38 @@
}
}
+ private static Object returnBar() {
+ return "bar";
+ }
+
+ public static void testInvokers() throws Throwable {
+ final MethodType targetType = MethodType.methodType(String.class, String.class);
+ final MethodHandle target = MethodHandles.lookup().findVirtual(
+ String.class, "concat", targetType);
+
+ MethodHandle invoker = MethodHandles.invoker(target.type());
+ assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar"));
+ assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar"));
+ try {
+ String foo = (String) invoker.invoke(target, "bar", "bar", 24);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type());
+ assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar"));
+ try {
+ String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar");
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+ try {
+ String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+ }
+
public static void fail() {
System.out.println("FAIL");
Thread.dumpStack();
diff --git a/test/958-methodhandle-emulated-stackframe/run b/test/958-methodhandle-emulated-stackframe/run
deleted file mode 100755
index a9f1822..0000000
--- a/test/958-methodhandle-emulated-stackframe/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/959-invoke-polymorphic-accessors/run b/test/959-invoke-polymorphic-accessors/run
deleted file mode 100644
index a9f1822..0000000
--- a/test/959-invoke-polymorphic-accessors/run
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# make us exit on a failure
-set -e
-
-./default-run "$@" --experimental method-handles
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 4794f6b..5f1071f 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -62,6 +62,7 @@
TEST_VDEX="n"
TEST_IS_NDEBUG="n"
APP_IMAGE="y"
+VDEX_FILTER=""
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -256,6 +257,11 @@
elif [ "x$1" = "x--vdex" ]; then
TEST_VDEX="y"
shift
+ elif [ "x$1" = "x--vdex-filter" ]; then
+ shift
+ option="$1"
+ VDEX_FILTER="--compiler-filter=$option"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
exit 1
@@ -514,7 +520,7 @@
dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 1m ${dex2oat_cmdline}"
fi
if [ "$TEST_VDEX" = "y" ]; then
- vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
fi
fi
diff --git a/test/run-test b/test/run-test
index abe73c3..a913e78 100755
--- a/test/run-test
+++ b/test/run-test
@@ -354,6 +354,11 @@
elif [ "x$1" = "x--vdex" ]; then
run_args="${run_args} --vdex"
shift
+ elif [ "x$1" = "x--vdex-filter" ]; then
+ shift
+ filter=$1
+ run_args="${run_args} --vdex-filter $filter"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
usage="yes"