summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmdline/cmdline_types.h2
-rw-r--r--compiler/driver/compiler_driver.cc134
-rw-r--r--compiler/driver/compiler_driver.h10
-rw-r--r--compiler/oat_test.cc2
-rw-r--r--compiler/optimizing/builder.h6
-rw-r--r--compiler/optimizing/code_generator.cc6
-rw-r--r--compiler/optimizing/code_generator_arm.cc16
-rw-r--r--compiler/optimizing/code_generator_arm.h2
-rw-r--r--compiler/optimizing/code_generator_arm64.cc19
-rw-r--r--compiler/optimizing/code_generator_arm64.h2
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc16
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.h2
-rw-r--r--compiler/optimizing/code_generator_mips.cc9
-rw-r--r--compiler/optimizing/code_generator_mips64.cc11
-rw-r--r--compiler/optimizing/code_generator_x86.cc18
-rw-r--r--compiler/optimizing/code_generator_x86.h4
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc18
-rw-r--r--compiler/optimizing/code_generator_x86_64.h4
-rw-r--r--compiler/optimizing/dex_cache_array_fixups_arm.cc5
-rw-r--r--compiler/optimizing/dex_cache_array_fixups_mips.cc5
-rw-r--r--compiler/optimizing/inliner.cc26
-rw-r--r--compiler/optimizing/inliner.h2
-rw-r--r--compiler/optimizing/instruction_builder.cc142
-rw-r--r--compiler/optimizing/instruction_builder.h13
-rw-r--r--compiler/optimizing/intrinsics.cc2
-rw-r--r--compiler/optimizing/load_store_elimination.cc2
-rw-r--r--compiler/optimizing/nodes.cc43
-rw-r--r--compiler/optimizing/nodes.h83
-rw-r--r--compiler/optimizing/nodes_test.cc8
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.cc14
-rw-r--r--compiler/optimizing/reference_type_propagation.cc29
-rw-r--r--compiler/optimizing/sharpening.cc32
-rw-r--r--compiler/optimizing/sharpening.h2
-rw-r--r--compiler/optimizing/stack_map_stream.cc68
-rw-r--r--compiler/optimizing/stack_map_stream.h8
-rw-r--r--compiler/optimizing/stack_map_test.cc53
-rw-r--r--compiler/utils/assembler_thumb_test_expected.cc.inc2
-rw-r--r--compiler/utils/x86/assembler_x86.cc145
-rw-r--r--compiler/utils/x86/assembler_x86.h23
-rw-r--r--compiler/utils/x86/assembler_x86_test.cc92
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.cc162
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.h22
-rw-r--r--compiler/utils/x86_64/assembler_x86_64_test.cc72
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S21
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S29
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc1
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S38
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S39
-rw-r--r--runtime/arch/quick_alloc_entrypoints.S32
-rw-r--r--runtime/arch/stub_test.cc133
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S20
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S46
-rw-r--r--runtime/art_method-inl.h43
-rw-r--r--runtime/art_method.cc5
-rw-r--r--runtime/art_method.h16
-rw-r--r--runtime/asm_support.h8
-rw-r--r--runtime/class_linker-inl.h30
-rw-r--r--runtime/class_linker.cc36
-rw-r--r--runtime/class_linker.h10
-rw-r--r--runtime/class_linker_test.cc3
-rw-r--r--runtime/debugger.cc4
-rw-r--r--runtime/dex_file_annotations.cc6
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h94
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc90
-rw-r--r--runtime/entrypoints/entrypoint_utils.h18
-rw-r--r--runtime/entrypoints/quick/quick_alloc_entrypoints.cc44
-rw-r--r--runtime/entrypoints/quick/quick_default_init_entrypoints.h3
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints_list.h5
-rw-r--r--runtime/entrypoints_order_test.cc26
-rw-r--r--runtime/interpreter/interpreter_common.cc6
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc4
-rw-r--r--runtime/mirror/dex_cache_test.cc1
-rw-r--r--runtime/mirror/emulated_stack_frame.cc1
-rw-r--r--runtime/mirror/emulated_stack_frame.h5
-rw-r--r--runtime/mirror/object_test.cc17
-rw-r--r--runtime/native/java_lang_Class.cc4
-rw-r--r--runtime/oat.h2
-rw-r--r--runtime/openjdkjvmti/Android.bp2
-rw-r--r--runtime/openjdkjvmti/OpenjdkJvmTi.cc75
-rw-r--r--runtime/openjdkjvmti/ti_class.cc89
-rw-r--r--runtime/openjdkjvmti/ti_class.h5
-rw-r--r--runtime/openjdkjvmti/ti_thread.cc39
-rw-r--r--runtime/openjdkjvmti/ti_thread.h3
-rw-r--r--runtime/openjdkjvmti/ti_threadgroup.cc285
-rw-r--r--runtime/openjdkjvmti/ti_threadgroup.h60
-rw-r--r--runtime/openjdkjvmti/ti_timers.cc93
-rw-r--r--runtime/openjdkjvmti/ti_timers.h51
-rw-r--r--runtime/parsed_options.cc2
-rw-r--r--runtime/reflection.cc11
-rw-r--r--runtime/runtime.h2
-rw-r--r--runtime/runtime_options.def2
-rw-r--r--runtime/stack_map.cc21
-rw-r--r--runtime/stack_map.h49
-rw-r--r--runtime/thread.cc5
-rw-r--r--runtime/thread.h28
-rw-r--r--runtime/vdex_file.h2
-rw-r--r--runtime/verifier/method_verifier.cc12
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--test/080-oom-throw/expected.txt1
-rw-r--r--test/080-oom-throw/src/Main.java43
-rw-r--r--test/129-ThreadGetId/src/Main.java4
-rw-r--r--test/633-checker-rtp-getclass/expected.txt3
-rw-r--r--test/633-checker-rtp-getclass/info.txt3
-rw-r--r--test/633-checker-rtp-getclass/src/Main.java76
-rw-r--r--test/634-vdex-duplicate/expected.txt1
-rw-r--r--test/634-vdex-duplicate/info.txt0
-rw-r--r--test/634-vdex-duplicate/run17
-rw-r--r--test/634-vdex-duplicate/src/Main.java21
-rw-r--r--test/634-vdex-duplicate/src/sun/misc/Unsafe.java20
-rw-r--r--test/901-hello-ti-agent/basics.cc16
-rw-r--r--test/901-hello-ti-agent/expected.txt6
-rw-r--r--test/901-hello-ti-agent/src/Main.java20
-rw-r--r--test/912-classes/classes.cc19
-rw-r--r--test/912-classes/expected.txt16
-rwxr-xr-xtest/912-classes/run7
-rw-r--r--test/912-classes/src-ex/A.java18
-rw-r--r--test/912-classes/src/B.java18
-rw-r--r--test/912-classes/src/Main.java116
-rw-r--r--test/916-obsolete-jit/src/Main.java35
-rwxr-xr-xtest/925-threadgroups/build (renamed from test/953-invoke-polymorphic-compiler/run)5
-rw-r--r--test/925-threadgroups/expected.txt16
-rw-r--r--test/925-threadgroups/info.txt1
-rwxr-xr-xtest/925-threadgroups/run (renamed from test/955-methodhandles-smali/run)7
-rw-r--r--test/925-threadgroups/src/Main.java113
-rw-r--r--test/925-threadgroups/threadgroups.cc127
-rwxr-xr-xtest/927-timers/build (renamed from test/954-invoke-polymorphic-verifier/run)5
-rw-r--r--test/927-timers/expected.txt3
-rw-r--r--test/927-timers/info.txt1
-rwxr-xr-xtest/927-timers/run (renamed from test/956-methodhandles/run)7
-rw-r--r--test/927-timers/src/Main.java62
-rw-r--r--test/927-timers/timers.cc84
-rw-r--r--test/956-methodhandles/src/Main.java20
-rwxr-xr-xtest/957-methodhandle-transforms/run20
-rw-r--r--test/957-methodhandle-transforms/src/Main.java33
-rwxr-xr-xtest/958-methodhandle-emulated-stackframe/run20
-rw-r--r--test/959-invoke-polymorphic-accessors/run20
-rw-r--r--test/Android.bp2
-rw-r--r--test/Android.run-test.mk6
-rw-r--r--test/common/runtime_state.cc17
-rwxr-xr-xtest/etc/run-test-jar8
-rwxr-xr-xtest/run-test5
142 files changed, 2765 insertions, 1292 deletions
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index e41d9bde59..28c009edf0 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -770,8 +770,6 @@ struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
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 29502666ad..faf8b41be1 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1060,13 +1060,13 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (auto& m : c->GetMethods(pointer_size)) {
- ResolveExceptionsForMethod(&m, pointer_size);
+ ResolveExceptionsForMethod(&m);
}
return true;
}
private:
- void ResolveExceptionsForMethod(ArtMethod* method_handle, PointerSize pointer_size)
+ void ResolveExceptionsForMethod(ArtMethod* method_handle)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile::CodeItem* code_item = method_handle->GetCodeItem();
if (code_item == nullptr) {
@@ -1088,8 +1088,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
dex::TypeIndex encoded_catch_handler_handlers_type_idx =
dex::TypeIndex(DecodeUnsignedLeb128(&encoded_catch_handler_list));
// Add to set of types to resolve if not already in the dex cache resolved types
- if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx,
- pointer_size)) {
+ if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
exceptions_to_resolve_.emplace(encoded_catch_handler_handlers_type_idx,
method_handle->GetDexFile());
}
@@ -1950,66 +1949,82 @@ static void PopulateVerifiedMethods(const DexFile& dex_file,
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 +2032,7 @@ void CompilerDriver::Verify(jobject jclass_loader,
// 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 +2041,7 @@ void CompilerDriver::Verify(jobject jclass_loader,
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 +2057,7 @@ void CompilerDriver::Verify(jobject jclass_loader,
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 +2078,10 @@ class VerifyClassVisitor : public CompilationVisitor {
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 2e3b7c8eb5..6bfdd4da9c 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -433,12 +433,18 @@ class CompilerDriver {
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/oat_test.cc b/compiler/oat_test.cc
index 86d92ff0b5..c69ed3198b 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -487,7 +487,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) {
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(159 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index f896f1199e..8cf4089eba 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -63,7 +63,8 @@ class HGraphBuilder : public ValueObject {
driver,
interpreter_metadata,
compiler_stats,
- dex_cache) {}
+ dex_cache,
+ handles) {}
// Only for unit testing.
HGraphBuilder(HGraph* graph,
@@ -90,7 +91,8 @@ class HGraphBuilder : public ValueObject {
/* 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 6c680c8dc6..70c2738010 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -936,10 +936,10 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo
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 ef4bd1e59d..07b174698a 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -5770,7 +5770,9 @@ void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
}
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 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
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::DeduplicateJitStringLiteral(const DexFile& dex_file,
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 bd237e96a5..52d18575ff 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -496,7 +496,7 @@ class CodeGeneratorARM : public CodeGenerator {
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 a9617e1212..b094e54f8a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4013,7 +4013,7 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
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::DeduplicateJitStringLitera
}
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 @@ void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
}
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 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
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 c7a06145e4..a9dca92980 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -579,7 +579,7 @@ class CodeGeneratorARM64 : public CodeGenerator {
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 f496d29b59..ecabc58c4d 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -5848,7 +5848,9 @@ void LocationsBuilderARMVIXL::VisitLoadClass(HLoadClass* cls) {
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);
@@ -5894,8 +5896,9 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
}
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;
}
@@ -5910,7 +5913,7 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
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;
@@ -7468,8 +7471,9 @@ VIXLUInt32Literal* CodeGeneratorARMVIXL::DeduplicateJitStringLiteral(
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 0f0a9540ba..be653535ea 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -579,7 +579,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator {
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 1f4ff279e8..24234e18c1 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5490,7 +5490,9 @@ void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
}
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 a350de7a51..fc8fb7acb2 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3395,7 +3395,7 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
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 @@ void LocationsBuilderMIPS64::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
}
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 a850d38dca..cc727d2068 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4521,7 +4521,7 @@ Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticO
__ 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 @@ void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
}
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 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
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 b86d080aa6..9eb97658da 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -419,7 +419,9 @@ class CodeGeneratorX86 : public CodeGenerator {
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 2691af8245..9adedab130 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -991,7 +991,7 @@ Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStat
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 @@ void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
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 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
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 8b3ab4c438..3438b8159f 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -416,7 +416,9 @@ class CodeGeneratorX86_64 : public CodeGenerator {
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 a3140d00cb..9ddcd563ca 100644
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc
@@ -64,9 +64,10 @@ class DexCacheArrayFixupsVisitor : public HGraphVisitor {
// 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 9a34f544ad..04a4294c48 100644
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_mips.cc
@@ -59,9 +59,10 @@ class DexCacheArrayFixupsVisitor : public HGraphVisitor {
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 d7da46bbe7..78a4251e3a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -474,10 +474,10 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,
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 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,
cursor,
bb_cursor,
class_index,
- GetMonomorphicType(classes),
+ monomorphic_type,
invoke_instruction,
/* with_deoptimization */ true);
@@ -533,11 +533,9 @@ HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
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 @@ HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
}
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 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction,
cursor,
bb_cursor,
class_index,
- handle.Get(),
+ handle,
invoke_instruction,
deoptimize);
if (deoptimize) {
@@ -1539,8 +1538,6 @@ bool HInliner::ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod*
}
}
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-
// Iterate over the list of parameter types and test whether any of the
// actual inputs has a more specific reference type than the type declared in
// the signature.
@@ -1552,9 +1549,9 @@ bool HInliner::ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod*
++param_idx, ++input_idx) {
HInstruction* input = invoke_instruction->InputAt(input_idx);
if (input->GetType() == Primitive::kPrimNot) {
- mirror::Class* param_cls = resolved_method->GetDexCacheResolvedType(
+ mirror::Class* param_cls = resolved_method->GetClassFromTypeIndex(
param_list->GetTypeItem(param_idx).type_idx_,
- pointer_size);
+ /* resolve */ false);
if (IsReferenceTypeRefinement(GetClassRTI(param_cls),
/* declared_can_be_null */ true,
input)) {
@@ -1603,8 +1600,7 @@ void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
// TODO: we could be more precise by merging the phi inputs but that requires
// some functionality from the reference type propagation.
DCHECK(return_replacement->IsPhi());
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* cls = resolved_method->GetReturnType(false /* resolve */, pointer_size);
+ mirror::Class* cls = resolved_method->GetReturnType(false /* resolve */);
return_replacement->SetReferenceTypeInfo(GetClassRTI(cls));
}
}
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 4c0b990f26..11aacab802 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -170,7 +170,7 @@ class HInliner : public HOptimization {
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 3cfabddf3a..8ed0e7fa06 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -208,10 +208,8 @@ void HInstructionBuilder::InitializeInstruction(HInstruction* instruction) {
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::BuildInvokePolymorphic(const Instruction& instruction
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 @@ HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke(
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 @@ HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke(
*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 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
}
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 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
}
}
- 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 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls)
}
}
-void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
- uint8_t destination,
- uint8_t reference,
- dex::TypeIndex type_index,
- uint32_t dex_pc) {
+HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index,
+ uint32_t dex_pc,
+ bool check_access,
+ bool outer) {
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);
+ 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;
+ }
+ }
+ }
- HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
- HLoadClass* cls = new (arena_) HLoadClass(
+ HLoadClass* load_class = new (arena_) HLoadClass(
graph_->GetCurrentMethod(),
type_index,
dex_file,
- IsOutermostCompilingClass(type_index),
+ klass,
+ klass.Get() != nullptr && (klass.Get() == GetOutermostCompilingClass()),
dex_pc,
- !can_access);
- AppendInstruction(cls);
+ !is_accessible);
- TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class);
+ 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) {
+ HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
+ HLoadClass* cls = BuildLoadClass(type_index, dex_pc, /* check_access */ true);
+
+ 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 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
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 aef0b94c1f..5efe95094c 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -46,9 +46,11 @@ class HInstructionBuilder : public ValueObject {
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 @@ class HInstructionBuilder : public ValueObject {
// 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 @@ class HInstructionBuilder : public ValueObject {
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 fc6ff7b197..17d683f357 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -145,7 +145,7 @@ void IntrinsicsRecognizer::Run() {
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 4f30b11753..2d3c00fb97 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -979,7 +979,7 @@ class LSEVisitor : public HGraphVisitor {
}
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 0af0d19849..d15145e673 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2391,6 +2391,14 @@ bool HInvoke::NeedsEnvironment() const {
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 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckReq
}
}
-// 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 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
}
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 @@ std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs) {
}
}
-// 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 @@ bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
}
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 3e7914c8c5..53b0fdde75 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1724,28 +1724,22 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
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 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
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 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
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 @@ class HNewInstance FINAL : public HExpression<1> {
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 @@ class HNewInstance FINAL : public HExpression<1> {
// 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 @@ class HNewInstance FINAL : public HExpression<1> {
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 @@ class HInvoke : public HVariableInputSizeInstruction {
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 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
return dispatch_info_.method_load_data;
}
+ const DexFile& GetDexFileForPcRelativeDexCache() const;
+
ClinitCheckRequirement GetClinitCheckRequirement() const {
return GetPackedField<ClinitCheckRequirementField>();
}
@@ -5449,10 +5432,10 @@ class HBoundsCheck FINAL : public HExpression<2> {
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 @@ class HBoundsCheck FINAL : public HExpression<2> {
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 @@ class HLoadClass FINAL : public HInstruction {
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 @@ class HLoadClass FINAL : public HInstruction {
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 @@ class HLoadClass FINAL : public HInstruction {
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 @@ class HLoadClass FINAL : public HInstruction {
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 @@ class HLoadClass FINAL : public HInstruction {
return Primitive::kPrimNot;
}
+ Handle<mirror::Class> GetClass() const {
+ return klass_;
+ }
+
DECLARE_INSTRUCTION(LoadClass);
private:
@@ -5714,11 +5686,6 @@ class HLoadClass FINAL : public HInstruction {
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 @@ class HLoadClass FINAL : public HInstruction {
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 5d9a6528ca..7686ba851b 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -52,7 +52,7 @@ TEST(Node, RemoveInstruction) {
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 @@ TEST(Node, ParentEnvironment) {
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 @@ TEST(Node, ParentEnvironment) {
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 db7c1fbb06..efbaf6c221 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 @@ void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {
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 @@ bool PrepareForRegisterAllocation::CanMoveClinitCheck(HInstruction* input,
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 f8a4469712..8854a2b08b 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -295,13 +295,13 @@ static void BoundTypeForClassCheck(HInstruction* check) {
}
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 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst
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::VisitUnresolvedStaticFieldGet(
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));
@@ -843,12 +840,8 @@ void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
}
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);
- mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
+ ArtMethod* method = instr->GetResolvedMethod();
+ mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(/* resolve */ false);
SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index eabda2675e..c5294107ae 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -133,24 +133,13 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
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 @@ void HSharpening::SharpenClass(HLoadClass* load_class,
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 @@ void HSharpening::SharpenClass(HLoadClass* load_class,
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 @@ void HSharpening::SharpenClass(HLoadClass* load_class,
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 @@ void HSharpening::SharpenClass(HLoadClass* load_class,
} 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 @@ void HSharpening::SharpenClass(HLoadClass* load_class,
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 ae5ccb33ab..ae3d83ef2c 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -49,8 +49,6 @@ class HSharpening : public HOptimization {
// 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 fc8af6462a..6087e36507 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 @@ void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t
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 @@ size_t StackMapStream::ComputeDexRegisterMapsSize() const {
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 @@ void StackMapStream::FillIn(MemoryRegion region) {
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 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const {
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 53a9795d52..d6f42b373c 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -109,8 +109,8 @@ class StackMapStream : public ValueObject {
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 @@ class StackMapStream : public ValueObject {
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 967fd96561..22810ea4f7 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 @@ TEST(StackMapTest, Test2) {
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 @@ TEST(StackMapTest, Test2) {
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 @@ TEST(StackMapTest, Test2) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 @@ TEST(StackMapTest, InlineTest) {
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 ab4f9e944c..a3fce02970 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5610,7 +5610,7 @@ const char* const VixlJniHelpersResults[] = {
" 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 c2ac ldr.w ip, [r9, #684] ; 0x2ac\n",
" 222: 47e0 blx ip\n",
nullptr
};
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index cd30872986..d3b15ac8cf 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -350,6 +350,38 @@ void X86Assembler::movaps(XmmRegister dst, XmmRegister src) {
}
+void X86Assembler::movaps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitOperand(dst, src);
+}
+
+
+void X86Assembler::movups(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst, src);
+}
+
+
+void X86Assembler::movaps(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x29);
+ EmitOperand(src, dst);
+}
+
+
+void X86Assembler::movups(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src, dst);
+}
+
+
void X86Assembler::movss(XmmRegister dst, const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
@@ -467,6 +499,83 @@ void X86Assembler::divss(XmmRegister dst, const Address& src) {
}
+void X86Assembler::addps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::subps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::mulps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::divps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::movapd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::movapd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitOperand(dst, src);
+}
+
+
+void X86Assembler::movupd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst, src);
+}
+
+
+void X86Assembler::movapd(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x29);
+ EmitOperand(src, dst);
+}
+
+
+void X86Assembler::movupd(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src, dst);
+}
+
+
void X86Assembler::flds(const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xD9);
@@ -638,6 +747,42 @@ void X86Assembler::divsd(XmmRegister dst, const Address& src) {
}
+void X86Assembler::addpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::subpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::mulpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::divpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void X86Assembler::cvtsi2ss(XmmRegister dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 114986b3e7..a93616c3e5 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -371,7 +371,12 @@ class X86Assembler FINAL : public Assembler {
void setb(Condition condition, Register dst);
- void movaps(XmmRegister dst, XmmRegister src);
+ void movaps(XmmRegister dst, XmmRegister src); // move
+ void movaps(XmmRegister dst, const Address& src); // load aligned
+ void movups(XmmRegister dst, const Address& src); // load unaligned
+ void movaps(const Address& dst, XmmRegister src); // store aligned
+ void movups(const Address& dst, XmmRegister src); // store unaligned
+
void movss(XmmRegister dst, const Address& src);
void movss(const Address& dst, XmmRegister src);
void movss(XmmRegister dst, XmmRegister src);
@@ -388,6 +393,17 @@ class X86Assembler FINAL : public Assembler {
void divss(XmmRegister dst, XmmRegister src);
void divss(XmmRegister dst, const Address& src);
+ void addps(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void subps(XmmRegister dst, XmmRegister src);
+ void mulps(XmmRegister dst, XmmRegister src);
+ void divps(XmmRegister dst, XmmRegister src);
+
+ void movapd(XmmRegister dst, XmmRegister src); // move
+ void movapd(XmmRegister dst, const Address& src); // load aligned
+ void movupd(XmmRegister dst, const Address& src); // load unaligned
+ void movapd(const Address& dst, XmmRegister src); // store aligned
+ void movupd(const Address& dst, XmmRegister src); // store unaligned
+
void movsd(XmmRegister dst, const Address& src);
void movsd(const Address& dst, XmmRegister src);
void movsd(XmmRegister dst, XmmRegister src);
@@ -409,6 +425,11 @@ class X86Assembler FINAL : public Assembler {
void divsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, const Address& src);
+ void addpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void subpd(XmmRegister dst, XmmRegister src);
+ void mulpd(XmmRegister dst, XmmRegister src);
+ void divpd(XmmRegister dst, XmmRegister src);
+
void cvtsi2ss(XmmRegister dst, Register src);
void cvtsi2sd(XmmRegister dst, Register src);
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 9bae6c20bd..4d60a12cb9 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -423,6 +423,98 @@ TEST_F(AssemblerX86Test, TestlAddressImmediate) {
DriverStr(expected, "TestlAddressImmediate");
}
+TEST_F(AssemblerX86Test, Movaps) {
+ DriverStr(RepeatFF(&x86::X86Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps");
+}
+
+TEST_F(AssemblerX86Test, MovapsAddr) {
+ GetAssembler()->movaps(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
+ GetAssembler()->movaps(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
+ const char* expected =
+ "movaps 0x4(%ESP), %xmm0\n"
+ "movaps %xmm1, 0x2(%ESP)\n";
+ DriverStr(expected, "movaps_address");
+}
+
+TEST_F(AssemblerX86Test, MovupsAddr) {
+ GetAssembler()->movups(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
+ GetAssembler()->movups(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
+ const char* expected =
+ "movups 0x4(%ESP), %xmm0\n"
+ "movups %xmm1, 0x2(%ESP)\n";
+ DriverStr(expected, "movups_address");
+}
+
+TEST_F(AssemblerX86Test, Movapd) {
+ DriverStr(RepeatFF(&x86::X86Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd");
+}
+
+TEST_F(AssemblerX86Test, MovapdAddr) {
+ GetAssembler()->movapd(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
+ GetAssembler()->movapd(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
+ const char* expected =
+ "movapd 0x4(%ESP), %xmm0\n"
+ "movapd %xmm1, 0x2(%ESP)\n";
+ DriverStr(expected, "movapd_address");
+}
+
+TEST_F(AssemblerX86Test, MovupdAddr) {
+ GetAssembler()->movupd(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
+ GetAssembler()->movupd(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
+ const char* expected =
+ "movupd 0x4(%ESP), %xmm0\n"
+ "movupd %xmm1, 0x2(%ESP)\n";
+ DriverStr(expected, "movupd_address");
+}
+
+TEST_F(AssemblerX86Test, AddPS) {
+ GetAssembler()->addps(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "addps %xmm1, %xmm0\n";
+ DriverStr(expected, "addps");
+}
+
+TEST_F(AssemblerX86Test, AddPD) {
+ GetAssembler()->addpd(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "addpd %xmm1, %xmm0\n";
+ DriverStr(expected, "addpd");
+}
+
+TEST_F(AssemblerX86Test, SubPS) {
+ GetAssembler()->subps(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "subps %xmm1, %xmm0\n";
+ DriverStr(expected, "subps");
+}
+
+TEST_F(AssemblerX86Test, SubPD) {
+ GetAssembler()->subpd(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "subpd %xmm1, %xmm0\n";
+ DriverStr(expected, "subpd");
+}
+
+TEST_F(AssemblerX86Test, MulPS) {
+ GetAssembler()->mulps(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "mulps %xmm1, %xmm0\n";
+ DriverStr(expected, "mulps");
+}
+
+TEST_F(AssemblerX86Test, MulPD) {
+ GetAssembler()->mulpd(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "mulpd %xmm1, %xmm0\n";
+ DriverStr(expected, "mulpd");
+}
+
+TEST_F(AssemblerX86Test, DivPS) {
+ GetAssembler()->divps(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "divps %xmm1, %xmm0\n";
+ DriverStr(expected, "divps");
+}
+
+TEST_F(AssemblerX86Test, DivPD) {
+ GetAssembler()->divpd(x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1));
+ const char* expected = "divpd %xmm1, %xmm0\n";
+ DriverStr(expected, "divpd");
+}
+
/////////////////
// Near labels //
/////////////////
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index e9a0607290..2366b68f11 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -386,6 +386,42 @@ void X86_64Assembler::movaps(XmmRegister dst, XmmRegister src) {
}
+void X86_64Assembler::movaps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::movups(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::movaps(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(src, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x29);
+ EmitOperand(src.LowBits(), dst);
+}
+
+
+void X86_64Assembler::movups(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(src, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src.LowBits(), dst);
+}
+
+
void X86_64Assembler::movss(XmmRegister dst, const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
@@ -539,6 +575,42 @@ void X86_64Assembler::divss(XmmRegister dst, const Address& src) {
}
+void X86_64Assembler::addps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::subps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::mulps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::divps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::flds(const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xD9);
@@ -560,6 +632,56 @@ void X86_64Assembler::fstps(const Address& dst) {
}
+void X86_64Assembler::movapd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::movapd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x28);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::movupd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::movapd(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(src, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x29);
+ EmitOperand(src.LowBits(), dst);
+}
+
+
+void X86_64Assembler::movupd(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(src, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src.LowBits(), dst);
+}
+
+
void X86_64Assembler::movsd(XmmRegister dst, const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
@@ -670,6 +792,46 @@ void X86_64Assembler::divsd(XmmRegister dst, const Address& src) {
}
+void X86_64Assembler::addpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::subpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::mulpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::divpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::cvtsi2ss(XmmRegister dst, CpuRegister src) {
cvtsi2ss(dst, src, false);
}
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index acad86d161..5923a41fe3 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -390,7 +390,11 @@ class X86_64Assembler FINAL : public Assembler {
void leaq(CpuRegister dst, const Address& src);
void leal(CpuRegister dst, const Address& src);
- void movaps(XmmRegister dst, XmmRegister src);
+ void movaps(XmmRegister dst, XmmRegister src); // move
+ void movaps(XmmRegister dst, const Address& src); // load aligned
+ void movups(XmmRegister dst, const Address& src); // load unaligned
+ void movaps(const Address& dst, XmmRegister src); // store aligned
+ void movups(const Address& dst, XmmRegister src); // store unaligned
void movss(XmmRegister dst, const Address& src);
void movss(const Address& dst, XmmRegister src);
@@ -413,6 +417,17 @@ class X86_64Assembler FINAL : public Assembler {
void divss(XmmRegister dst, XmmRegister src);
void divss(XmmRegister dst, const Address& src);
+ void addps(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void subps(XmmRegister dst, XmmRegister src);
+ void mulps(XmmRegister dst, XmmRegister src);
+ void divps(XmmRegister dst, XmmRegister src);
+
+ void movapd(XmmRegister dst, XmmRegister src); // move
+ void movapd(XmmRegister dst, const Address& src); // load aligned
+ void movupd(XmmRegister dst, const Address& src); // load unaligned
+ void movapd(const Address& dst, XmmRegister src); // store aligned
+ void movupd(const Address& dst, XmmRegister src); // store unaligned
+
void movsd(XmmRegister dst, const Address& src);
void movsd(const Address& dst, XmmRegister src);
void movsd(XmmRegister dst, XmmRegister src);
@@ -426,6 +441,11 @@ class X86_64Assembler FINAL : public Assembler {
void divsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, const Address& src);
+ void addpd(XmmRegister dst, XmmRegister src); // no addr variant (for now)
+ void subpd(XmmRegister dst, XmmRegister src);
+ void mulpd(XmmRegister dst, XmmRegister src);
+ void divpd(XmmRegister dst, XmmRegister src);
+
void cvtsi2ss(XmmRegister dst, CpuRegister src); // Note: this is the r/m32 version.
void cvtsi2ss(XmmRegister dst, CpuRegister src, bool is64bit);
void cvtsi2ss(XmmRegister dst, const Address& src, bool is64bit);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index ff01429058..2812c34406 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -986,10 +986,50 @@ TEST_F(AssemblerX86_64Test, Movaps) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps");
}
+TEST_F(AssemblerX86_64Test, MovapsAddr) {
+ GetAssembler()->movaps(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
+ GetAssembler()->movaps(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
+ const char* expected =
+ "movaps 0x4(%RSP), %xmm0\n"
+ "movaps %xmm1, 0x2(%RSP)\n";
+ DriverStr(expected, "movaps_address");
+}
+
+TEST_F(AssemblerX86_64Test, MovupsAddr) {
+ GetAssembler()->movups(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
+ GetAssembler()->movups(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
+ const char* expected =
+ "movups 0x4(%RSP), %xmm0\n"
+ "movups %xmm1, 0x2(%RSP)\n";
+ DriverStr(expected, "movups_address");
+}
+
TEST_F(AssemblerX86_64Test, Movss) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::movss, "movss %{reg2}, %{reg1}"), "movss");
}
+TEST_F(AssemblerX86_64Test, Movapd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd");
+}
+
+TEST_F(AssemblerX86_64Test, MovapdAddr) {
+ GetAssembler()->movapd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
+ GetAssembler()->movapd(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
+ const char* expected =
+ "movapd 0x4(%RSP), %xmm0\n"
+ "movapd %xmm1, 0x2(%RSP)\n";
+ DriverStr(expected, "movapd_address");
+}
+
+TEST_F(AssemblerX86_64Test, MovupdAddr) {
+ GetAssembler()->movupd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4));
+ GetAssembler()->movupd(x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 2), x86_64::XmmRegister(x86_64::XMM1));
+ const char* expected =
+ "movupd 0x4(%RSP), %xmm0\n"
+ "movupd %xmm1, 0x2(%RSP)\n";
+ DriverStr(expected, "movupd_address");
+}
+
TEST_F(AssemblerX86_64Test, Movsd) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::movsd, "movsd %{reg2}, %{reg1}"), "movsd");
}
@@ -1010,6 +1050,14 @@ TEST_F(AssemblerX86_64Test, Addsd) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::addsd, "addsd %{reg2}, %{reg1}"), "addsd");
}
+TEST_F(AssemblerX86_64Test, Addps) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::addps, "addps %{reg2}, %{reg1}"), "addps");
+}
+
+TEST_F(AssemblerX86_64Test, Addpd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::addpd, "addpd %{reg2}, %{reg1}"), "addpd");
+}
+
TEST_F(AssemblerX86_64Test, Subss) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::subss, "subss %{reg2}, %{reg1}"), "subss");
}
@@ -1018,6 +1066,14 @@ TEST_F(AssemblerX86_64Test, Subsd) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::subsd, "subsd %{reg2}, %{reg1}"), "subsd");
}
+TEST_F(AssemblerX86_64Test, Subps) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::subps, "subps %{reg2}, %{reg1}"), "subps");
+}
+
+TEST_F(AssemblerX86_64Test, Subpd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::subpd, "subpd %{reg2}, %{reg1}"), "subpd");
+}
+
TEST_F(AssemblerX86_64Test, Mulss) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulss, "mulss %{reg2}, %{reg1}"), "mulss");
}
@@ -1026,6 +1082,14 @@ TEST_F(AssemblerX86_64Test, Mulsd) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulsd, "mulsd %{reg2}, %{reg1}"), "mulsd");
}
+TEST_F(AssemblerX86_64Test, Mulps) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulps, "mulps %{reg2}, %{reg1}"), "mulps");
+}
+
+TEST_F(AssemblerX86_64Test, Mulpd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulpd, "mulpd %{reg2}, %{reg1}"), "mulpd");
+}
+
TEST_F(AssemblerX86_64Test, Divss) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::divss, "divss %{reg2}, %{reg1}"), "divss");
}
@@ -1034,6 +1098,14 @@ TEST_F(AssemblerX86_64Test, Divsd) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::divsd, "divsd %{reg2}, %{reg1}"), "divsd");
}
+TEST_F(AssemblerX86_64Test, Divps) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::divps, "divps %{reg2}, %{reg1}"), "divps");
+}
+
+TEST_F(AssemblerX86_64Test, Divpd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::divpd, "divpd %{reg2}, %{reg1}"), "divpd");
+}
+
TEST_F(AssemblerX86_64Test, Cvtsi2ss) {
DriverStr(RepeatFr(&x86_64::X86_64Assembler::cvtsi2ss, "cvtsi2ss %{reg2}, %{reg1}"), "cvtsi2ss");
}
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 102c313a6a..db1cad670d 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -856,27 +856,6 @@ END art_quick_check_instance_of
#endif // USE_READ_BARRIER
.endm
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- * r0 = array, r1 = index, r2 = value
- */
-ENTRY art_quick_aput_obj_with_null_and_bound_check
- tst r0, r0
- bne art_quick_aput_obj_with_bound_check
- b art_quick_throw_null_pointer_exception
-END art_quick_aput_obj_with_null_and_bound_check
-
- .hidden art_quick_aput_obj_with_bound_check
-ENTRY art_quick_aput_obj_with_bound_check
- ldr r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]
- cmp r3, r1
- bhi art_quick_aput_obj
- mov r0, r1
- mov r1, r3
- b art_quick_throw_array_bounds
-END art_quick_aput_obj_with_bound_check
-
#ifdef USE_READ_BARRIER
.extern artReadBarrierSlow
#endif
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 3b3783cad4..ed24a0723f 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1404,33 +1404,6 @@ END art_quick_check_instance_of
#endif // USE_READ_BARRIER
.endm
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- * x0 = array, x1 = index, x2 = value
- *
- * Currently all values should fit into w0/w1/w2, and w1 always will as indices are 32b. We
- * assume, though, that the upper 32b are zeroed out. At least for x1/w1 we can do better by
- * using index-zero-extension in load/stores.
- *
- * Temporaries: x3, x4
- * TODO: x4 OK? ip seems wrong here.
- */
-ENTRY art_quick_aput_obj_with_null_and_bound_check
- tst x0, x0
- bne art_quick_aput_obj_with_bound_check
- b art_quick_throw_null_pointer_exception
-END art_quick_aput_obj_with_null_and_bound_check
-
-ENTRY art_quick_aput_obj_with_bound_check
- ldr w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]
- cmp w3, w1
- bhi art_quick_aput_obj
- mov x0, x1
- mov x1, x3
- b art_quick_throw_array_bounds
-END art_quick_aput_obj_with_bound_check
-
#ifdef USE_READ_BARRIER
.extern artReadBarrierSlow
#endif
@@ -1675,8 +1648,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTL
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB) implemented in asm
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 5c569232ac..7a0bd3e40d 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -262,6 +262,7 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
art_quick_invoke_virtual_trampoline_with_access_check;
static_assert(!IsDirectEntrypoint(kQuickInvokeVirtualTrampolineWithAccessCheck),
"Non-direct C stub marked direct.");
+ qpoints->pInvokePolymorphic = art_quick_invoke_polymorphic;
// Thread
qpoints->pTestSuspend = art_quick_test_suspend;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 3acc0a9d5b..76218fb542 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1389,28 +1389,6 @@ END art_quick_check_instance_of
#endif // USE_READ_BARRIER
.endm
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- * a0 = array, a1 = index, a2 = value
- */
-ENTRY art_quick_aput_obj_with_null_and_bound_check
- bnez $a0, .Lart_quick_aput_obj_with_bound_check_gp_set
- nop
- b art_quick_throw_null_pointer_exception
- nop
-END art_quick_aput_obj_with_null_and_bound_check
-
-ENTRY art_quick_aput_obj_with_bound_check
- lw $t0, MIRROR_ARRAY_LENGTH_OFFSET($a0)
- sltu $t1, $a1, $t0
- bnez $t1, .Lart_quick_aput_obj_gp_set
- nop
- move $a0, $a1
- b art_quick_throw_array_bounds
- move $a1, $t0
-END art_quick_aput_obj_with_bound_check
-
#ifdef USE_READ_BARRIER
.extern artReadBarrierSlow
#endif
@@ -2285,15 +2263,12 @@ END art_quick_string_compareto
ENTRY art_quick_invoke_polymorphic
SETUP_SAVE_REFS_AND_ARGS_FRAME
move $a2, rSELF # Make $a2 an alias for the current Thread.
- move $a3, $sp # Make $a3 a pointer to the saved frame context.
- addiu $sp, $sp, -24 # Reserve space for JValue result and 4 words for callee.
- .cfi_adjust_cfa_offset 24
+ addiu $a3, $sp, ARG_SLOT_SIZE # Make $a3 a pointer to the saved frame context.
sw $zero, 20($sp) # Initialize JValue result.
sw $zero, 16($sp)
- addiu $a0, $sp, 16 # Make $a0 a pointer to the JValue result
la $t9, artInvokePolymorphic
jalr $t9 # (result, receiver, Thread*, context)
- nop
+ addiu $a0, $sp, 16 # Make $a0 a pointer to the JValue result
.macro MATCH_RETURN_TYPE c, handler
li $t0, \c
beq $v0, $t0, \handler
@@ -2307,18 +2282,17 @@ ENTRY art_quick_invoke_polymorphic
MATCH_RETURN_TYPE 'D', .Lstore_double_result
MATCH_RETURN_TYPE 'F', .Lstore_float_result
MATCH_RETURN_TYPE 'S', .Lstore_int_result
+ MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
.purgem MATCH_RETURN_TYPE
nop
b .Lcleanup_and_return
nop
.Lstore_boolean_result:
- lbu $v0, 16($sp) # Move byte from JValue result to return value register.
b .Lcleanup_and_return
- nop
+ lbu $v0, 16($sp) # Move byte from JValue result to return value register.
.Lstore_char_result:
- lhu $v0, 16($sp) # Move char from JValue result to return value register.
b .Lcleanup_and_return
- nop
+ lhu $v0, 16($sp) # Move char from JValue result to return value register.
.Lstore_double_result:
.Lstore_float_result:
LDu $f0, $f1, 16, $sp, $t0 # Move double/float from JValue result to return value register.
@@ -2331,8 +2305,6 @@ ENTRY art_quick_invoke_polymorphic
lw $v0, 16($sp) # Move lower bits from JValue result to return value register.
// Fall-through to clean up and return.
.Lcleanup_and_return:
- addiu $sp, $sp, 24 # Remove space for JValue result and the 4 words for the callee.
- .cfi_adjust_cfa_offset -24
lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # Load Thread::Current()->exception_
RESTORE_SAVE_REFS_AND_ARGS_FRAME
bnez $t7, 1f # Success if no exception is pending.
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index ae786fe626..b53fd100fa 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1360,29 +1360,6 @@ END art_quick_check_instance_of
#endif // USE_READ_BARRIER
.endm
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- * a0 = array, a1 = index, a2 = value
- */
-ENTRY art_quick_aput_obj_with_null_and_bound_check
- bne $a0, $zero, .Lart_quick_aput_obj_with_bound_check_gp_set
- nop
- b art_quick_throw_null_pointer_exception
- .cpreturn # Restore gp from t8 in branch delay slot.
-END art_quick_aput_obj_with_null_and_bound_check
-
-ENTRY art_quick_aput_obj_with_bound_check
- lwu $t0, MIRROR_ARRAY_LENGTH_OFFSET($a0)
- sltu $t1, $a1, $t0
- bne $t1, $zero, .Lart_quick_aput_obj_gp_set
- nop
- move $a0, $a1
- move $a1, $t0
- b art_quick_throw_array_bounds
- .cpreturn # Restore gp from t8 in branch delay slot.
-END art_quick_aput_obj_with_bound_check
-
ENTRY art_quick_aput_obj
beq $a2, $zero, .Ldo_aput_null
nop
@@ -2132,9 +2109,8 @@ ENTRY art_quick_invoke_polymorphic
daddiu $sp, $sp, -8 # Reserve space for JValue result.
.cfi_adjust_cfa_offset 8
sd $zero, 0($sp) # Initialize JValue result.
- move $a0, $sp # Make $a0 a pointer to the JValue result
jal artInvokePolymorphic # (result, receiver, Thread*, context)
- nop
+ move $a0, $sp # Make $a0 a pointer to the JValue result
.macro MATCH_RETURN_TYPE c, handler
li $t0, \c
beq $v0, $t0, \handler
@@ -2148,27 +2124,24 @@ ENTRY art_quick_invoke_polymorphic
MATCH_RETURN_TYPE 'D', .Lstore_double_result
MATCH_RETURN_TYPE 'F', .Lstore_float_result
MATCH_RETURN_TYPE 'S', .Lstore_long_result
+ MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
.purgem MATCH_RETURN_TYPE
nop
b .Lcleanup_and_return
nop
.Lstore_boolean_result:
- lbu $v0, 0($sp) # Move byte from JValue result to return value register.
b .Lcleanup_and_return
- nop
+ lbu $v0, 0($sp) # Move byte from JValue result to return value register.
.Lstore_char_result:
- lhu $v0, 0($sp) # Move char from JValue result to return value register.
b .Lcleanup_and_return
- nop
+ lhu $v0, 0($sp) # Move char from JValue result to return value register.
.Lstore_double_result:
.Lstore_float_result:
- l.d $f0, 0($sp) # Move double/float from JValue result to return value register.
b .Lcleanup_and_return
- nop
+ l.d $f0, 0($sp) # Move double/float from JValue result to return value register.
.Lstore_ref_result:
- lwu $v0, 0($sp) # Move zero extended lower 32-bits to return value register.
b .Lcleanup_and_return
- nop
+ lwu $v0, 0($sp) # Move zero extended lower 32-bits to return value register.
.Lstore_long_result:
ld $v0, 0($sp) # Move long from JValue result to return value register.
// Fall-through to clean up and return.
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index abd9046174..3959cbee05 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -29,10 +29,6 @@ THREE_ARG_DOWNCALL art_quick_alloc_array_resolved\c_suffix, artAllocArrayFromCod
// Called by managed code to allocate an array when the caller doesn't know whether it has access
// to the created type.
THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check\c_suffix, artAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-// Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
-THREE_ARG_DOWNCALL art_quick_check_and_alloc_array\c_suffix, artCheckAndAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-// Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
-THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check\c_suffix, artCheckAndAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate a string from bytes
FOUR_ARG_DOWNCALL art_quick_alloc_string_from_bytes\c_suffix, artAllocStringFromBytesFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Called by managed code to allocate a string from chars
@@ -71,10 +67,6 @@ GENERATE_ALLOC_ENTRYPOINTS _region_tlab_instrumented, RegionTLABInstrumented
THREE_ARG_DOWNCALL art_quick_alloc_array_resolved ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \
THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check ## c_suffix, artAllocArrayFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-#define GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(c_suffix, cxx_suffix) \
- THREE_ARG_DOWNCALL art_quick_check_and_alloc_array ## c_suffix, artCheckAndAllocArrayFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-#define GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \
- THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check ## c_suffix, artCheckAndAllocArrayFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(c_suffix, cxx_suffix) \
FOUR_ARG_DOWNCALL art_quick_alloc_string_from_bytes ## c_suffix, artAllocStringFromBytesFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(c_suffix, cxx_suffix) \
@@ -95,8 +87,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTL
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
@@ -110,8 +100,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
@@ -129,8 +117,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_dlmalloc, DlMalloc)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc, DlMalloc)
@@ -141,8 +127,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc_instrumented
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallocInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc_instrumented, DlMallocInstrumented)
@@ -154,8 +138,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_rosalloc, RosAlloc)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc, RosAlloc)
@@ -166,8 +148,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc_instrumented
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_rosalloc_instrumented, RosAllocInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_rosalloc_instrumented, RosAllocInstrumented)
@@ -178,8 +158,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer, BumpPoi
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_bump_pointer, BumpPointer)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer, BumpPointer)
@@ -190,8 +168,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer_instrume
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_bump_pointer_instrumented, BumpPointerInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_bump_pointer_instrumented, BumpPointerInstrumented)
@@ -202,8 +178,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab_instrumented, TL
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab_instrumented, TLABInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab_instrumented, TLABInstrumented)
@@ -214,8 +188,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region, Region)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region, Region)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region, Region)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region, Region)
@@ -226,8 +198,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_instrumented,
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_instrumented, RegionInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_instrumented, RegionInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_instrumented, RegionInstrumented)
@@ -238,8 +208,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab_instrumen
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab_instrumented, RegionTLABInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab_instrumented, RegionTLABInstrumented)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab_instrumented, RegionTLABInstrumented)
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index ee65fa8ab0..393dfe6d19 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -908,139 +908,6 @@ TEST_F(StubTest, CheckCast) {
#endif
}
-
-TEST_F(StubTest, APutObj) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
- (defined(__x86_64__) && !defined(__APPLE__))
- Thread* self = Thread::Current();
-
- // Do not check non-checked ones, we'd need handlers and stuff...
- const uintptr_t art_quick_aput_obj_with_null_and_bound_check =
- StubTest::GetEntrypoint(self, kQuickAputObjectWithNullAndBoundCheck);
-
- // Create an object
- ScopedObjectAccess soa(self);
- // garbage is created during ClassLinker::Init
-
- StackHandleScope<5> hs(soa.Self());
- Handle<mirror::Class> c(
- hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
- Handle<mirror::Class> ca(
- hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;")));
-
- // Build a string array of size 1
- Handle<mirror::ObjectArray<mirror::Object>> array(
- hs.NewHandle(mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.Get(), 10)));
-
- // Build a string -> should be assignable
- Handle<mirror::String> str_obj(
- hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!")));
-
- // Build a generic object -> should fail assigning
- Handle<mirror::Object> obj_obj(hs.NewHandle(c->AllocObject(soa.Self())));
-
- // Play with it...
-
- // 1) Success cases
- // 1.1) Assign str_obj to array[0..3]
-
- EXPECT_FALSE(self->IsExceptionPending());
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(str_obj.Get(), array->Get(0));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(str_obj.Get(), array->Get(1));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(str_obj.Get(), array->Get(2));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(str_obj.Get(), array->Get(3));
-
- // 1.2) Assign null to array[0..3]
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(nullptr),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(nullptr, array->Get(0));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 1U, reinterpret_cast<size_t>(nullptr),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(nullptr, array->Get(1));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 2U, reinterpret_cast<size_t>(nullptr),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(nullptr, array->Get(2));
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 3U, reinterpret_cast<size_t>(nullptr),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_FALSE(self->IsExceptionPending());
- EXPECT_EQ(nullptr, array->Get(3));
-
- // TODO: Check _which_ exception is thrown. Then make 3) check that it's the right check order.
-
- // 2) Failure cases (str into str[])
- // 2.1) Array = null
- // TODO: Throwing NPE needs actual DEX code
-
-// Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.Get()),
-// reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
-//
-// EXPECT_TRUE(self->IsExceptionPending());
-// self->ClearException();
-
- // 2.2) Index < 0
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), static_cast<size_t>(-1),
- reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_TRUE(self->IsExceptionPending());
- self->ClearException();
-
- // 2.3) Index > 0
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 10U, reinterpret_cast<size_t>(str_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_TRUE(self->IsExceptionPending());
- self->ClearException();
-
- // 3) Failure cases (obj into str[])
-
- Invoke3(reinterpret_cast<size_t>(array.Get()), 0U, reinterpret_cast<size_t>(obj_obj.Get()),
- art_quick_aput_obj_with_null_and_bound_check, self);
-
- EXPECT_TRUE(self->IsExceptionPending());
- self->ClearException();
-
- // Tests done.
-#else
- LOG(INFO) << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA;
- // Force-print to std::cout so it's also outside the logcat.
- std::cout << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA << std::endl;
-#endif
-}
-
TEST_F(StubTest, AllocObject) {
#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
(defined(__x86_64__) && !defined(__APPLE__))
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 1d979d852e..c4202596f2 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1352,26 +1352,6 @@ MACRO4(READ_BARRIER, obj_reg, offset, dest_reg, pop_eax)
#endif // USE_READ_BARRIER
END_MACRO
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- * eax = array, ecx = index, edx = value
- */
-DEFINE_FUNCTION art_quick_aput_obj_with_null_and_bound_check
- testl %eax, %eax
- jnz SYMBOL(art_quick_aput_obj_with_bound_check)
- jmp SYMBOL(art_quick_throw_null_pointer_exception)
-END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
-
-DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
- movl MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ebx
- cmpl %ebx, %ecx
- jb SYMBOL(art_quick_aput_obj)
- mov %ecx, %eax
- mov %ebx, %ecx
- jmp SYMBOL(art_quick_throw_array_bounds)
-END_FUNCTION art_quick_aput_obj_with_bound_check
-
DEFINE_FUNCTION art_quick_aput_obj
test %edx, %edx // store of null
jz .Ldo_aput_null
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 28034c9bae..550a5e8452 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -989,8 +989,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTL
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
@@ -1000,8 +998,6 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
@@ -1466,7 +1462,7 @@ END_MACRO
* 64b PUSH/POP and 32b argument.
* TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
*
- * As with art_quick_aput_obj* functions, the 64b versions are in comments.
+ * As with art_quick_aput_obj function, the 64b versions are in comments.
*/
MACRO4(READ_BARRIER, obj_reg, offset, dest_reg32, dest_reg64)
#ifdef USE_READ_BARRIER
@@ -1503,46 +1499,6 @@ MACRO4(READ_BARRIER, obj_reg, offset, dest_reg32, dest_reg64)
#endif // USE_READ_BARRIER
END_MACRO
- /*
- * Entry from managed code for array put operations of objects where the value being stored
- * needs to be checked for compatibility.
- *
- * Currently all the parameters should fit into the 32b portions of the registers. Index always
- * will. So we optimize for a tighter encoding. The 64b versions are in comments.
- *
- * rdi(edi) = array, rsi(esi) = index, rdx(edx) = value
- */
-DEFINE_FUNCTION art_quick_aput_obj_with_null_and_bound_check
-#if defined(__APPLE__)
- int3
- int3
-#else
- testl %edi, %edi
-// testq %rdi, %rdi
- jnz art_quick_aput_obj_with_bound_check
- jmp art_quick_throw_null_pointer_exception
-#endif // __APPLE__
-END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
-
-
-DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
-#if defined(__APPLE__)
- int3
- int3
-#else
- movl MIRROR_ARRAY_LENGTH_OFFSET(%edi), %ecx
-// movl MIRROR_ARRAY_LENGTH_OFFSET(%rdi), %ecx // This zero-extends, so value(%rcx)=value(%ecx)
- cmpl %ecx, %esi
- jb art_quick_aput_obj
- mov %esi, %edi
-// mov %rsi, %rdi
- mov %ecx, %esi
-// mov %rcx, %rsi
- jmp art_quick_throw_array_bounds
-#endif // __APPLE__
-END_FUNCTION art_quick_aput_obj_with_bound_check
-
-
DEFINE_FUNCTION art_quick_aput_obj
testl %edx, %edx // store of null
// test %rdx, %rdx
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 96976d9bce..0fd891c9ec 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -121,7 +121,7 @@ inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
inline uint32_t ArtMethod::GetDexMethodIndex() {
DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
GetDeclaringClass()->IsErroneous());
- return dex_method_index_;
+ return GetDexMethodIndexUnchecked();
}
inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
@@ -180,20 +180,6 @@ inline GcRoot<mirror::Class>* ArtMethod::GetDexCacheResolvedTypes(PointerSize po
pointer_size);
}
-template <bool kWithCheck>
-inline mirror::Class* ArtMethod::GetDexCacheResolvedType(dex::TypeIndex type_index,
- PointerSize pointer_size) {
- if (kWithCheck) {
- mirror::DexCache* dex_cache = GetInterfaceMethodIfProxy(pointer_size)->GetDexCache();
- if (UNLIKELY(type_index.index_ >= dex_cache->NumResolvedTypes())) {
- ThrowArrayIndexOutOfBoundsException(type_index.index_, dex_cache->NumResolvedTypes());
- return nullptr;
- }
- }
- mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index.index_].Read();
- return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
-}
-
inline bool ArtMethod::HasDexCacheResolvedTypes(PointerSize pointer_size) {
return GetDexCacheResolvedTypes(pointer_size) != nullptr;
}
@@ -207,15 +193,15 @@ inline bool ArtMethod::HasSameDexCacheResolvedTypes(ArtMethod* other, PointerSiz
return GetDexCacheResolvedTypes(pointer_size) == other->GetDexCacheResolvedTypes(pointer_size);
}
-inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx,
- bool resolve,
- PointerSize pointer_size) {
- mirror::Class* type = GetDexCacheResolvedType(type_idx, pointer_size);
- if (type == nullptr && resolve) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx, bool resolve) {
+ ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
+ ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
+ if (UNLIKELY(type == nullptr) && resolve) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ type = class_linker->ResolveType(type_idx, this);
CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
}
- return type;
+ return type.Ptr();
}
inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
@@ -333,9 +319,9 @@ inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
return GetDexFile()->GetCodeItem(GetCodeItemOffset());
}
-inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size) {
+inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx) {
DCHECK(!IsProxyMethod());
- return GetDexCacheResolvedType(type_idx, pointer_size) != nullptr;
+ return GetClassFromTypeIndex(type_idx, /* resolve */ false) != nullptr;
}
inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
@@ -435,18 +421,13 @@ inline void ArtMethod::SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_c
SetNativePointer(DexCacheResolvedTypesOffset(pointer_size), new_dex_cache_types, pointer_size);
}
-inline mirror::Class* ArtMethod::GetReturnType(bool resolve, PointerSize pointer_size) {
+inline mirror::Class* ArtMethod::GetReturnType(bool resolve) {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
- mirror::Class* type = GetDexCacheResolvedType(return_type_idx, pointer_size);
- if (type == nullptr && resolve) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
- CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
- }
- return type;
+ return GetClassFromTypeIndex(return_type_idx, resolve);
}
inline bool ArtMethod::HasSingleImplementation() {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index dfc7837aea..d7d39afa8f 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -236,7 +236,6 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
// Default to handler not found.
uint32_t found_dex_pc = DexFile::kDexNoIndex;
// Iterate over the catch handlers associated with dex_pc.
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
@@ -245,9 +244,7 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
break;
}
// Does this catch exception type apply?
- mirror::Class* iter_exception_type = GetClassFromTypeIndex(iter_type_idx,
- true /* resolve */,
- pointer_size);
+ mirror::Class* iter_exception_type = GetClassFromTypeIndex(iter_type_idx, true /* resolve */);
if (UNLIKELY(iter_exception_type == nullptr)) {
// Now have a NoClassDefFoundError as exception. Ignore in case the exception class was
// removed by a pro-guard like tool.
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 11dcc35df5..912df85815 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -322,6 +322,9 @@ class ArtMethod FINAL {
// 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) {
@@ -348,9 +351,6 @@ class ArtMethod FINAL {
bool HasSameDexCacheResolvedMethods(ArtMethod** other_cache, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- template <bool kWithCheck = true>
- mirror::Class* GetDexCacheResolvedType(dex::TypeIndex type_idx, PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
void SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_cache_types,
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -361,9 +361,7 @@ class ArtMethod FINAL {
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the Class* from the type index into this method's dex cache.
- mirror::Class* GetClassFromTypeIndex(dex::TypeIndex type_idx,
- bool resolve,
- PointerSize pointer_size)
+ mirror::Class* GetClassFromTypeIndex(dex::TypeIndex type_idx, bool resolve)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method has the same name and signature of the other method.
@@ -555,8 +553,7 @@ class ArtMethod FINAL {
const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
- bool IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsResolvedTypeIdx(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
int32_t GetLineNumFromDexPC(uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -577,8 +574,7 @@ class ArtMethod FINAL {
// May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
// number of bugs at call sites.
- mirror::Class* GetReturnType(bool resolve, PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ mirror::Class* GetReturnType(bool resolve) REQUIRES_SHARED(Locks::mutator_lock_);
mirror::ClassLoader* GetClassLoader() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index e4972da13d..18a53c916e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -90,7 +90,7 @@ ADD_TEST_EQ(THREAD_SELF_OFFSET,
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_POS_OFFSET,
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 + 159) * __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-inl.h b/runtime/class_linker-inl.h
index 5fc5f1a2f5..2e17dd85e6 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -25,7 +25,6 @@
#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/iftable.h"
-#include "mirror/throwable.h"
#include "mirror/object_array.h"
#include "handle_scope-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -90,25 +89,16 @@ inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMetho
if (kIsDebugBuild) {
Thread::Current()->AssertNoPendingException();
}
- ObjPtr<mirror::Class> resolved_type =
- referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
+ ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
if (UNLIKELY(resolved_type == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
- // There could be an out of bounds exception from GetDexCacheResolvedType, don't call
- // ResolveType for this case.
- if (LIKELY(!hs.Self()->IsExceptionPending())) {
- ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
- // Note: We cannot check here to see whether we added the type to the cache. The type
- // might be an erroneous class, which results in it being hidden from us.
- } else {
- // Make sure its an array out of bounds exception.
- DCHECK(hs.Self()->GetException()->GetClass()->DescriptorEquals(
- "Ljava/lang/ArrayIndexOutOfBoundsException;"));
- }
+ ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ // Note: We cannot check here to see whether we added the type to the cache. The type
+ // might be an erroneous class, which results in it being hidden from us.
}
return resolved_type.Ptr();
}
@@ -256,8 +246,8 @@ ArtMethod* ClassLinker::FindMethodForProxy(ObjPtr<mirror::Class> proxy_class,
// Locate the dex cache of the original interface/Object
for (const DexCacheData& data : dex_caches_) {
if (!self->IsJWeakCleared(data.weak_root) &&
- proxy_method->HasSameDexCacheResolvedTypes(data.resolved_types,
- image_pointer_size_)) {
+ proxy_method->HasSameDexCacheResolvedMethods(data.resolved_methods,
+ image_pointer_size_)) {
ObjPtr<mirror::DexCache> dex_cache =
ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
if (dex_cache != nullptr) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 129c93f575..07c6eda03f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2711,10 +2711,6 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
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
@@ -3307,7 +3303,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
DexCacheData data;
data.weak_root = dex_cache_jweak;
data.dex_file = dex_cache->GetDexFile();
- data.resolved_types = dex_cache->GetResolvedTypes();
+ data.resolved_methods = dex_cache->GetResolvedMethods();
dex_caches_.push_back(data);
}
@@ -4377,8 +4373,7 @@ void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) cons
CHECK_STREQ(np->GetName(), prototype->GetName());
CHECK_STREQ(np->GetShorty(), prototype->GetShorty());
// More complex sanity - via dex cache
- CHECK_EQ(np->GetReturnType(true /* resolve */, image_pointer_size_),
- prototype->GetReturnType(true /* resolve */, image_pointer_size_));
+ CHECK_EQ(np->GetReturnType(true /* resolve */), prototype->GetReturnType(true /* resolve */));
}
bool ClassLinker::CanWeInitializeClass(ObjPtr<mirror::Class> klass, bool can_init_statics,
@@ -4840,7 +4835,6 @@ static void ThrowSignatureMismatch(Handle<mirror::Class> klass,
}
static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
- PointerSize pointer_size,
Handle<mirror::Class> klass,
Handle<mirror::Class> super_klass,
ArtMethod* method1,
@@ -4848,14 +4842,12 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
REQUIRES_SHARED(Locks::mutator_lock_) {
{
StackHandleScope<1> hs(self);
- Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType(true /* resolve */,
- pointer_size)));
+ Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType(true /* resolve */)));
if (UNLIKELY(return_type.Get() == nullptr)) {
ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1);
return false;
}
- ObjPtr<mirror::Class> other_return_type = method2->GetReturnType(true /* resolve */,
- pointer_size);
+ ObjPtr<mirror::Class> other_return_type = method2->GetReturnType(true /* resolve */);
if (UNLIKELY(other_return_type == nullptr)) {
ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2);
return false;
@@ -4900,7 +4892,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
StackHandleScope<1> hs(self);
dex::TypeIndex param_type_idx = types1->GetTypeItem(i).type_idx_;
Handle<mirror::Class> param_type(hs.NewHandle(
- method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
+ method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */)));
if (UNLIKELY(param_type.Get() == nullptr)) {
ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
method1, i, param_type_idx);
@@ -4908,7 +4900,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
}
dex::TypeIndex other_param_type_idx = types2->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> other_param_type =
- method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
+ method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */);
if (UNLIKELY(other_param_type == nullptr)) {
ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
method2, i, other_param_type_idx);
@@ -4944,9 +4936,11 @@ bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
auto* m = klass->GetVTableEntry(i, image_pointer_size_);
auto* super_m = klass->GetSuperClass()->GetVTableEntry(i, image_pointer_size_);
if (m != super_m) {
- if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
- klass, super_klass,
- m, super_m))) {
+ if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self,
+ klass,
+ super_klass,
+ m,
+ super_m))) {
self->AssertPendingException();
return false;
}
@@ -4962,9 +4956,11 @@ bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
j, image_pointer_size_);
auto* super_m = super_klass->GetVirtualMethod(j, image_pointer_size_);
if (m != super_m) {
- if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
- klass, super_klass,
- m, super_m))) {
+ if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self,
+ klass,
+ super_klass,
+ m,
+ super_m))) {
self->AssertPendingException();
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 580acb7068..823848b3bc 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -645,6 +645,10 @@ class ClassLinker {
mirror::Class* GetHoldingClassOfCopiedMethod(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns null if not found.
+ ClassTable* ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
struct DexCacheData {
// Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may
// not work properly.
@@ -653,7 +657,7 @@ class ClassLinker {
// jweak decode that triggers read barriers (and mark them alive unnecessarily and mess with
// class unloading.)
const DexFile* dex_file;
- GcRoot<mirror::Class>* resolved_types;
+ ArtMethod** resolved_methods;
};
private:
@@ -1039,10 +1043,6 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::classlinker_classes_lock_);
- // Returns null if not found.
- ClassTable* ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Insert a new class table if not found.
ClassTable* InsertClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 42108d8621..bbe7280bb3 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -460,7 +460,6 @@ class ClassLinkerMethodHandlesTest : public ClassLinkerTest {
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 MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
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 @@ TEST_F(ClassLinkerTest, LookupResolvedType) {
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/debugger.cc b/runtime/debugger.cc
index df4413d52c..006476bafc 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3985,9 +3985,7 @@ JDWP::JdwpError Dbg::PrepareInvokeMethod(uint32_t request_id, JDWP::ObjectId thr
if (shorty[i + 1] == 'L') {
// Did we really get an argument of an appropriate reference type?
mirror::Class* parameter_type =
- m->GetClassFromTypeIndex(types->GetTypeItem(i).type_idx_,
- true /* resolve */,
- kRuntimePointerSize);
+ m->GetClassFromTypeIndex(types->GetTypeItem(i).type_idx_, true /* resolve */);
mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i], &error);
if (error != JDWP::ERR_NONE) {
return JDWP::ERR_INVALID_OBJECT;
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 9504e8bd29..16a447b0a6 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -608,7 +608,7 @@ mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
return nullptr;
}
Handle<mirror::Class> method_return(hs.NewHandle(
- annotation_method->GetReturnType(true /* resolve */, pointer_size)));
+ annotation_method->GetReturnType(true /* resolve */)));
DexFile::AnnotationValue annotation_value;
if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return,
@@ -948,9 +948,7 @@ mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) {
DexFile::AnnotationValue annotation_value;
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::Class> h_klass(hs.NewHandle(klass));
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- Handle<mirror::Class> return_type(hs.NewHandle(
- method->GetReturnType(true /* resolve */, pointer_size)));
+ Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */)));
if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type,
DexFile::kAllObjects)) {
return nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 5ff95b480f..87046bc09d 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -52,21 +52,19 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
// 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 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
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;
}
@@ -256,10 +241,9 @@ inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
*slow_path = true;
return nullptr; // Failure
}
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- PointerSize pointer_size = class_linker->GetImagePointerSize();
- mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, pointer_size);
+ mirror::Class* klass = method->GetDexCache()->GetResolvedType(type_idx);
if (UNLIKELY(klass == nullptr)) { // Not in dex cache so try to resolve
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
klass = class_linker->ResolveType(type_idx, method);
*slow_path = true;
if (klass == nullptr) { // Error
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index b17e1a8ab1..25fd727968 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -38,98 +38,13 @@
namespace art {
-static inline mirror::Class* CheckFilledNewArrayAlloc(dex::TypeIndex type_idx,
- int32_t component_count,
- ArtMethod* referrer,
- Thread* self,
- bool access_check)
- REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
- if (UNLIKELY(component_count < 0)) {
- ThrowNegativeArraySizeException(component_count);
- return nullptr; // Failure
- }
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- PointerSize pointer_size = class_linker->GetImagePointerSize();
- mirror::Class* klass = referrer->GetDexCacheResolvedType<false>(type_idx, pointer_size);
- if (UNLIKELY(klass == nullptr)) { // Not in dex cache so try to resolve
- klass = class_linker->ResolveType(type_idx, referrer);
- if (klass == nullptr) { // Error
- DCHECK(self->IsExceptionPending());
- return nullptr; // Failure
- }
- }
- if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
- if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
- ThrowRuntimeException("Bad filled array request for type %s",
- klass->PrettyDescriptor().c_str());
- } else {
- self->ThrowNewExceptionF(
- "Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but 'int'",
- klass->PrettyDescriptor().c_str());
- }
- return nullptr; // Failure
- }
- if (access_check) {
- mirror::Class* referrer_klass = referrer->GetDeclaringClass();
- if (UNLIKELY(!referrer_klass->CanAccess(klass))) {
- ThrowIllegalAccessErrorClass(referrer_klass, klass);
- return nullptr; // Failure
- }
- }
- DCHECK(klass->IsArrayClass()) << klass->PrettyClass();
- return klass;
-}
-
-// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
- int32_t component_count,
- ArtMethod* referrer,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
- mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
- access_check);
- if (UNLIKELY(klass == nullptr)) {
- return nullptr;
- }
- // Always go slow path for now, filled new array is not common.
- gc::Heap* heap = Runtime::Current()->GetHeap();
- // Use the current allocator type in case CheckFilledNewArrayAlloc caused us to suspend and then
- // the heap switched the allocator type while we were suspended.
- return mirror::Array::Alloc<false>(self, klass, component_count,
- klass->GetComponentSizeShift(),
- heap->GetCurrentAllocator());
-}
-
-// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(
- dex::TypeIndex type_idx,
- int32_t component_count,
- ArtMethod* referrer,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
- mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
- access_check);
- if (UNLIKELY(klass == nullptr)) {
- return nullptr;
- }
- gc::Heap* heap = Runtime::Current()->GetHeap();
- // Use the current allocator type in case CheckFilledNewArrayAlloc caused us to suspend and then
- // the heap switched the allocator type while we were suspended.
- return mirror::Array::Alloc<true>(self, klass, component_count,
- klass->GetComponentSizeShift(),
- heap->GetCurrentAllocator());
-}
-
void CheckReferenceResult(Handle<mirror::Object> o, Thread* self) {
if (o.Get() == nullptr) {
return;
}
// Make sure that the result is an instance of the type this method was expected to return.
ArtMethod* method = self->GetCurrentMethod(nullptr);
- mirror::Class* return_type = method->GetReturnType(true /* resolve */, kRuntimePointerSize);
+ mirror::Class* return_type = method->GetReturnType(true /* resolve */);
if (!o->InstanceOf(return_type)) {
Runtime::Current()->GetJavaVM()->JniAbortF(nullptr,
@@ -192,8 +107,7 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons
ArtMethod* interface_method =
soa.Decode<mirror::Method>(interface_method_jobj)->GetArtMethod();
// This can cause thread suspension.
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */, pointer_size);
+ mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */);
ObjPtr<mirror::Object> result_ref = soa.Decode<mirror::Object>(result);
JValue result_unboxed;
if (!UnboxPrimitiveForResult(result_ref.Ptr(), result_type, &result_unboxed)) {
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index d4cf83c8de..b427c0717f 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -102,24 +102,6 @@ ALWAYS_INLINE inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* kl
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
- int32_t component_count,
- ArtMethod* method,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Roles::uninterruptible_);
-
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex type_idx,
- int32_t component_count,
- ArtMethod* method,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Roles::uninterruptible_);
-
// Type of find field operation for fast and slow case.
enum FindFieldType {
InstanceObjectRead,
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 2d06508069..23a99a06c6 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -109,46 +109,6 @@ extern "C" mirror::Array* artAllocArrayFromCodeWithAccessCheck##suffix##suffix2(
self, \
allocator_type); \
} \
-extern "C" mirror::Array* artCheckAndAllocArrayFromCode##suffix##suffix2( \
- uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
- REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
- component_count, \
- method, \
- self, \
- false, \
- allocator_type); \
- } else { \
- return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
- component_count, \
- method, \
- self, \
- false, \
- allocator_type); \
- } \
-} \
-extern "C" mirror::Array* artCheckAndAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
- uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
- REQUIRES_SHARED(Locks::mutator_lock_) { \
- ScopedQuickEntrypointChecks sqec(self); \
- if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
- component_count, \
- method, \
- self, \
- true, \
- allocator_type); \
- } else { \
- return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
- component_count, \
- method, \
- self, \
- true, \
- allocator_type); \
- } \
-} \
extern "C" mirror::String* artAllocStringFromBytesFromCode##suffix##suffix2( \
mirror::ByteArray* byte_array, int32_t high, int32_t offset, int32_t byte_count, \
Thread* self) \
@@ -219,8 +179,6 @@ void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrument
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \
qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix##_instrumented; \
- qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix##_instrumented; \
- qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented; \
qpoints->pAllocStringFromBytes = art_quick_alloc_string_from_bytes##suffix##_instrumented; \
qpoints->pAllocStringFromChars = art_quick_alloc_string_from_chars##suffix##_instrumented; \
qpoints->pAllocStringFromString = art_quick_alloc_string_from_string##suffix##_instrumented; \
@@ -231,8 +189,6 @@ void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrument
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \
qpoints->pAllocObjectWithChecks = art_quick_alloc_object_with_checks##suffix; \
- qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix; \
- qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix; \
qpoints->pAllocStringFromBytes = art_quick_alloc_string_from_bytes##suffix; \
qpoints->pAllocStringFromChars = art_quick_alloc_string_from_chars##suffix; \
qpoints->pAllocStringFromString = art_quick_alloc_string_from_string##suffix; \
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 8ce61c1021..6481b97ae1 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -66,10 +66,7 @@ void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints)
qpoints->pGetObjStatic = art_quick_get_obj_static;
// Array
- qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check;
- qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check;
qpoints->pAputObject = art_quick_aput_obj;
- qpoints->pHandleFillArrayData = art_quick_handle_fill_data;
// JNI
qpoints->pJniMethodStart = JniMethodStart;
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 4d5d6de41d..0e75e94d52 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -26,8 +26,6 @@
V(AllocObjectResolved, void*, mirror::Class*) \
V(AllocObjectInitialized, void*, mirror::Class*) \
V(AllocObjectWithChecks, void*, mirror::Class*) \
- V(CheckAndAllocArray, void*, uint32_t, int32_t, ArtMethod*) \
- V(CheckAndAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*) \
V(AllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t) \
V(AllocStringFromChars, void*, int32_t, int32_t, void*) \
V(AllocStringFromString, void*, void*) \
@@ -65,10 +63,7 @@
V(GetObjInstance, void*, uint32_t, void*) \
V(GetObjStatic, void*, uint32_t) \
\
- V(AputObjectWithNullAndBoundCheck, void, mirror::Array*, int32_t, mirror::Object*) \
- V(AputObjectWithBoundCheck, void, mirror::Array*, int32_t, mirror::Object*) \
V(AputObject, void, mirror::Array*, int32_t, mirror::Object*) \
- V(HandleFillArrayData, void, void*, void*) \
\
V(JniMethodStart, uint32_t, Thread*) \
V(JniMethodFastStart, uint32_t, Thread*) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 96e17daa08..b9caf0f555 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -117,15 +117,14 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
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));
-
- // Skip across the entrypoints structures.
+ 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_start, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_objects, 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));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, mterp_current_ibase, sizeof(size_t));
+ // Skip across the entrypoints structures.
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*));
@@ -162,12 +161,8 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectInitialized, pAllocObjectWithChecks,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectWithChecks, pCheckAndAllocArray,
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectWithChecks, pAllocStringFromBytes,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckAndAllocArray, pCheckAndAllocArrayWithAccessCheck,
- sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckAndAllocArrayWithAccessCheck,
- pAllocStringFromBytes, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocStringFromBytes, pAllocStringFromChars,
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocStringFromChars, pAllocStringFromString,
@@ -206,13 +201,8 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Instance, pGet64Static, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Static, pGetObjInstance, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjInstance, pGetObjStatic, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjStatic, pAputObjectWithNullAndBoundCheck,
- sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObjectWithNullAndBoundCheck,
- pAputObjectWithBoundCheck, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObjectWithBoundCheck, pAputObject, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObject, pHandleFillArrayData, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pHandleFillArrayData, pJniMethodStart, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjStatic, pAputObject, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObject, pJniMethodStart, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodStart, pJniMethodFastStart,
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodFastStart, pJniMethodStartSynchronized,
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ca26207093..76777d938b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -751,16 +751,14 @@ static inline bool DoCallCommon(ArtMethod* called_method,
case 'L': {
ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
if (do_assignability_check && o != nullptr) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
- ObjPtr<mirror::Class> arg_type = method->GetDexCacheResolvedType(type_idx,
- pointer_size);
+ ObjPtr<mirror::Class> arg_type = method->GetDexCache()->GetResolvedType(type_idx);
if (arg_type == nullptr) {
StackHandleScope<1> hs(self);
// Preserve o since it is used below and GetClassFromTypeIndex may cause thread
// suspension.
HandleWrapperObjPtr<mirror::Object> h = hs.NewHandleWrapper(&o);
- arg_type = method->GetClassFromTypeIndex(type_idx, true /* resolve */, pointer_size);
+ arg_type = method->GetClassFromTypeIndex(type_idx, true /* resolve */);
if (arg_type == nullptr) {
CHECK(self->IsExceptionPending());
return false;
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index d7dfcd4408..a77a3fc2b3 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -285,9 +285,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
const size_t ref_idx = inst->VRegA_11x(inst_data);
ObjPtr<mirror::Object> obj_result = shadow_frame.GetVRegReference(ref_idx);
if (do_assignability_check && obj_result != nullptr) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- ObjPtr<mirror::Class> return_type = method->GetReturnType(true /* resolve */,
- pointer_size);
+ ObjPtr<mirror::Class> return_type = method->GetReturnType(true /* resolve */);
// Re-load since it might have moved.
obj_result = shadow_frame.GetVRegReference(ref_idx);
if (return_type == nullptr) {
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 916f1cf1ef..8f978e122c 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -35,7 +35,6 @@ class DexCacheMethodHandlesTest : public DexCacheTest {
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 d607040486..978cc32320 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -195,6 +195,7 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
// 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 d83a53652b..ddd84a167d 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -81,6 +81,10 @@ class MANAGED EmulatedStackFrame : public Object {
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 @@ class MANAGED EmulatedStackFrame : public Object {
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/mirror/object_test.cc b/runtime/mirror/object_test.cc
index a6f56aee42..6a4ec9dca7 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -306,23 +306,6 @@ TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) {
}
-TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
- // pretend we are trying to call 'new char[3]' from String.toCharArray
- ScopedObjectAccess soa(Thread::Current());
- Class* java_util_Arrays = class_linker_->FindSystemClass(soa.Self(), "Ljava/util/Arrays;");
- ArtMethod* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V", kRuntimePointerSize);
- const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId("[I");
- ASSERT_TRUE(type_id != nullptr);
- dex::TypeIndex type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
- Object* array = CheckAndAllocArrayFromCodeInstrumented(
- type_idx, 3, sort, Thread::Current(), false,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
- EXPECT_TRUE(array->IsArrayInstance());
- EXPECT_EQ(3, array->AsArray()->GetLength());
- EXPECT_TRUE(array->GetClass()->IsArrayClass());
- EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
-}
-
TEST_F(ObjectTest, CreateMultiArray) {
ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3341f531e4..5438a6ddb4 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -428,6 +428,10 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT
}
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 f2d457c2ee..90a9c150b1 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@ class InstructionSetFeatures;
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', '9', '\0' }; // Remove old entrypoints
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
index 4bd21b4c2f..af027f6ba6 100644
--- a/runtime/openjdkjvmti/Android.bp
+++ b/runtime/openjdkjvmti/Android.bp
@@ -30,6 +30,8 @@ cc_defaults {
"ti_stack.cc",
"ti_redefine.cc",
"ti_thread.cc",
+ "ti_threadgroup.cc",
+ "ti_timers.cc",
"transform.cc"],
include_dirs: ["art/runtime"],
shared_libs: [
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 8674e6cae7..d9aea01ef8 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"
@@ -56,6 +58,8 @@
#include "ti_redefine.h"
#include "ti_stack.h"
#include "ti_thread.h"
+#include "ti_threadgroup.h"
+#include "ti_timers.h"
#include "transform.h"
// TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton
@@ -202,13 +206,13 @@ class JvmtiFunctions {
static jvmtiError GetTopThreadGroups(jvmtiEnv* env,
jint* group_count_ptr,
jthreadGroup** groups_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadGroupUtil::GetTopThreadGroups(env, group_count_ptr, groups_ptr);
}
static jvmtiError GetThreadGroupInfo(jvmtiEnv* env,
jthreadGroup group,
jvmtiThreadGroupInfo* info_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadGroupUtil::GetThreadGroupInfo(env, group, info_ptr);
}
static jvmtiError GetThreadGroupChildren(jvmtiEnv* env,
@@ -217,7 +221,12 @@ class JvmtiFunctions {
jthread** threads_ptr,
jint* group_count_ptr,
jthreadGroup** groups_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadGroupUtil::GetThreadGroupChildren(env,
+ group,
+ thread_count_ptr,
+ threads_ptr,
+ group_count_ptr,
+ groups_ptr);
}
static jvmtiError GetStackTrace(jvmtiEnv* env,
@@ -535,7 +544,7 @@ class JvmtiFunctions {
jobject initiating_loader,
jint* class_count_ptr,
jclass** classes_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ClassUtil::GetClassLoaderClasses(env, initiating_loader, class_count_ptr, classes_ptr);
}
static jvmtiError GetClassSignature(jvmtiEnv* env,
@@ -1031,15 +1040,15 @@ class JvmtiFunctions {
}
static jvmtiError GetTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return TimerUtil::GetTimerInfo(env, info_ptr);
}
static jvmtiError GetTime(jvmtiEnv* env, jlong* nanos_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return TimerUtil::GetTime(env, nanos_ptr);
}
static jvmtiError GetAvailableProcessors(jvmtiEnv* env, jint* processor_count_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return TimerUtil::GetAvailableProcessors(env, processor_count_ptr);
}
static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment) {
@@ -1168,7 +1177,57 @@ class JvmtiFunctions {
}
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/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 0d1704ca4d..d1324bc13f 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -32,7 +32,10 @@
#include "ti_class.h"
#include "art_jvmti.h"
+#include "class_table-inl.h"
+#include "class_linker.h"
#include "jni_internal.h"
+#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -328,4 +331,90 @@ jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED,
return ERR(NONE);
}
+jvmtiError ClassUtil::GetClassLoaderClasses(jvmtiEnv* env,
+ jobject initiating_loader,
+ jint* class_count_ptr,
+ jclass** classes_ptr) {
+ UNUSED(env, initiating_loader, class_count_ptr, classes_ptr);
+
+ if (class_count_ptr == nullptr || classes_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+ art::Thread* self = art::Thread::Current();
+ if (!self->GetJniEnv()->IsInstanceOf(initiating_loader,
+ art::WellKnownClasses::java_lang_ClassLoader)) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ if (self->GetJniEnv()->IsInstanceOf(initiating_loader,
+ art::WellKnownClasses::java_lang_BootClassLoader)) {
+ // Need to use null for the BootClassLoader.
+ initiating_loader = nullptr;
+ }
+
+ art::ScopedObjectAccess soa(self);
+ art::ObjPtr<art::mirror::ClassLoader> class_loader =
+ soa.Decode<art::mirror::ClassLoader>(initiating_loader);
+
+ art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+
+ art::ReaderMutexLock mu(self, *art::Locks::classlinker_classes_lock_);
+
+ art::ClassTable* class_table = class_linker->ClassTableForClassLoader(class_loader);
+ if (class_table == nullptr) {
+ // Nothing loaded.
+ *class_count_ptr = 0;
+ *classes_ptr = nullptr;
+ return ERR(NONE);
+ }
+
+ struct ClassTableCount {
+ bool operator()(art::ObjPtr<art::mirror::Class> klass) {
+ DCHECK(klass != nullptr);
+ ++count;
+ return true;
+ }
+
+ size_t count = 0;
+ };
+ ClassTableCount ctc;
+ class_table->Visit(ctc);
+
+ if (ctc.count == 0) {
+ // Nothing loaded.
+ *class_count_ptr = 0;
+ *classes_ptr = nullptr;
+ return ERR(NONE);
+ }
+
+ unsigned char* data;
+ jvmtiError data_result = env->Allocate(ctc.count * sizeof(jclass), &data);
+ if (data_result != ERR(NONE)) {
+ return data_result;
+ }
+ jclass* class_array = reinterpret_cast<jclass*>(data);
+
+ struct ClassTableFill {
+ bool operator()(art::ObjPtr<art::mirror::Class> klass)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ DCHECK(klass != nullptr);
+ DCHECK_LT(count, ctc_ref.count);
+ local_class_array[count++] = soa_ptr->AddLocalReference<jclass>(klass);
+ return true;
+ }
+
+ jclass* local_class_array;
+ const ClassTableCount& ctc_ref;
+ art::ScopedObjectAccess* soa_ptr;
+ size_t count;
+ };
+ ClassTableFill ctf = { class_array, ctc, &soa, 0 };
+ class_table->Visit(ctf);
+ DCHECK_EQ(ctc.count, ctf.count);
+
+ *class_count_ptr = ctc.count;
+ *classes_ptr = class_array;
+
+ return ERR(NONE);
+}
+
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h
index 577fc8e866..7a0fafbc83 100644
--- a/runtime/openjdkjvmti/ti_class.h
+++ b/runtime/openjdkjvmti/ti_class.h
@@ -65,6 +65,11 @@ class ClassUtil {
static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr);
+ static jvmtiError GetClassLoaderClasses(jvmtiEnv* env,
+ jobject initiating_loader,
+ jint* class_count_ptr,
+ jclass** classes_ptr);
+
static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr);
static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr);
};
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index f7f63bd19c..2bcdd8cda1 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -35,11 +35,14 @@
#include "art_jvmti.h"
#include "base/logging.h"
#include "base/mutex.h"
+#include "gc/system_weak.h"
+#include "gc_root-inl.h"
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "obj_ptr.h"
+#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "thread_list.h"
@@ -400,7 +403,43 @@ jvmtiError ThreadUtil::GetAllThreads(jvmtiEnv* env,
*threads_count_ptr = static_cast<jint>(peers.size());
*threads_ptr = threads;
}
+ return ERR(NONE);
+}
+
+jvmtiError ThreadUtil::SetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jthread thread,
+ const void* data) {
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Thread* self = GetNativeThread(thread, soa);
+ if (self == nullptr && thread == nullptr) {
+ return ERR(INVALID_THREAD);
+ }
+ if (self == nullptr) {
+ return ERR(THREAD_NOT_ALIVE);
+ }
+
+ self->SetCustomTLS(data);
+
+ return ERR(NONE);
+}
+
+jvmtiError ThreadUtil::GetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jthread thread,
+ void** data_ptr) {
+ if (data_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Thread* self = GetNativeThread(thread, soa);
+ if (self == nullptr && thread == nullptr) {
+ return ERR(INVALID_THREAD);
+ }
+ if (self == nullptr) {
+ return ERR(THREAD_NOT_ALIVE);
+ }
+ *data_ptr = const_cast<void*>(self->GetCustomTLS());
return ERR(NONE);
}
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
index fca42ad2b5..290e9d49b2 100644
--- a/runtime/openjdkjvmti/ti_thread.h
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -46,6 +46,9 @@ class ThreadUtil {
static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr);
static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr);
+
+ static jvmtiError SetThreadLocalStorage(jvmtiEnv* env, jthread thread, const void* data);
+ static jvmtiError GetThreadLocalStorage(jvmtiEnv* env, jthread thread, void** data_ptr);
};
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_threadgroup.cc b/runtime/openjdkjvmti/ti_threadgroup.cc
new file mode 100644
index 0000000000..35b1bfd920
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_threadgroup.cc
@@ -0,0 +1,285 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "ti_threadgroup.h"
+
+#include "art_field.h"
+#include "art_jvmti.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "handle_scope-inl.h"
+#include "jni_internal.h"
+#include "mirror/class.h"
+#include "mirror/object-inl.h"
+#include "mirror/string.h"
+#include "obj_ptr.h"
+#include "object_lock.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
+#include "thread_list.h"
+#include "well_known_classes.h"
+
+namespace openjdkjvmti {
+
+
+jvmtiError ThreadGroupUtil::GetTopThreadGroups(jvmtiEnv* env,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr) {
+ // We only have a single top group. So we can take the current thread and move upwards.
+ if (group_count_ptr == nullptr || groups_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::Runtime* runtime = art::Runtime::Current();
+ if (runtime == nullptr) {
+ // Must be starting the runtime, or dying.
+ return ERR(WRONG_PHASE);
+ }
+
+ jobject sys_thread_group = runtime->GetSystemThreadGroup();
+ if (sys_thread_group == nullptr) {
+ // Seems we're still starting up.
+ return ERR(WRONG_PHASE);
+ }
+
+ unsigned char* data;
+ jvmtiError result = env->Allocate(sizeof(jthreadGroup), &data);
+ if (result != ERR(NONE)) {
+ return result;
+ }
+
+ jthreadGroup* groups = reinterpret_cast<jthreadGroup*>(data);
+ *groups =
+ reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv())->NewLocalRef(sys_thread_group);
+ *groups_ptr = groups;
+ *group_count_ptr = 1;
+
+ return ERR(NONE);
+}
+
+jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env,
+ jthreadGroup group,
+ jvmtiThreadGroupInfo* info_ptr) {
+ if (group == nullptr) {
+ return ERR(INVALID_THREAD_GROUP);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup) == JNI_FALSE) {
+ return ERR(INVALID_THREAD_GROUP);
+ }
+
+ art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(group);
+
+ // Do the name first. It's the only thing that can fail.
+ {
+ art::ArtField* name_field =
+ art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_name);
+ CHECK(name_field != nullptr);
+ art::ObjPtr<art::mirror::String> name_obj =
+ art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj));
+ std::string tmp_str;
+ const char* tmp_cstr;
+ if (name_obj == nullptr) {
+ tmp_cstr = "";
+ } else {
+ tmp_str = name_obj->ToModifiedUtf8();
+ tmp_cstr = tmp_str.c_str();
+ }
+ jvmtiError result =
+ CopyString(env, tmp_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
+ if (result != ERR(NONE)) {
+ return result;
+ }
+ }
+
+ // Parent.
+ {
+ art::ArtField* parent_field =
+ art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_parent);
+ CHECK(parent_field != nullptr);
+ art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj);
+ info_ptr->parent = parent_group == nullptr
+ ? nullptr
+ : soa.AddLocalReference<jthreadGroup>(parent_group);
+ }
+
+ // Max priority.
+ {
+ art::ArtField* prio_field = obj->GetClass()->FindDeclaredInstanceField("maxPriority", "I");
+ CHECK(prio_field != nullptr);
+ info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj));
+ }
+
+ // Daemon.
+ {
+ art::ArtField* daemon_field = obj->GetClass()->FindDeclaredInstanceField("daemon", "Z");
+ CHECK(daemon_field != nullptr);
+ info_ptr->is_daemon = daemon_field->GetBoolean(obj) == 0 ? JNI_FALSE : JNI_TRUE;
+ }
+
+ return ERR(NONE);
+}
+
+
+static bool IsInDesiredThreadGroup(art::Handle<art::mirror::Object> desired_thread_group,
+ art::ObjPtr<art::mirror::Object> peer)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ CHECK(desired_thread_group.Get() != nullptr);
+
+ art::ArtField* thread_group_field =
+ art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
+ DCHECK(thread_group_field != nullptr);
+ art::ObjPtr<art::mirror::Object> group = thread_group_field->GetObject(peer);
+ return (group == desired_thread_group.Get());
+}
+
+static void GetThreads(art::Handle<art::mirror::Object> thread_group,
+ std::vector<art::ObjPtr<art::mirror::Object>>* thread_peers)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!art::Locks::thread_list_lock_) {
+ CHECK(thread_group.Get() != nullptr);
+
+ art::MutexLock mu(art::Thread::Current(), *art::Locks::thread_list_lock_);
+ for (art::Thread* t : art::Runtime::Current()->GetThreadList()->GetList()) {
+ if (t->IsStillStarting()) {
+ continue;
+ }
+ art::ObjPtr<art::mirror::Object> peer = t->GetPeer();
+ if (peer == nullptr) {
+ continue;
+ }
+ if (IsInDesiredThreadGroup(thread_group, peer)) {
+ thread_peers->push_back(peer);
+ }
+ }
+}
+
+static void GetChildThreadGroups(art::Handle<art::mirror::Object> thread_group,
+ std::vector<art::ObjPtr<art::mirror::Object>>* thread_groups)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ CHECK(thread_group.Get() != nullptr);
+
+ // Get the ThreadGroup[] "groups" out of this thread group...
+ art::ArtField* groups_field =
+ art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_groups);
+ art::ObjPtr<art::mirror::Object> groups_array = groups_field->GetObject(thread_group.Get());
+
+ if (groups_array == nullptr) {
+ return;
+ }
+ CHECK(groups_array->IsObjectArray());
+
+ art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> groups_array_as_array =
+ groups_array->AsObjectArray<art::mirror::Object>();
+
+ // Copy all non-null elements.
+ for (int32_t i = 0; i < groups_array_as_array->GetLength(); ++i) {
+ art::ObjPtr<art::mirror::Object> entry = groups_array_as_array->Get(i);
+ if (entry != nullptr) {
+ thread_groups->push_back(entry);
+ }
+ }
+}
+
+jvmtiError ThreadGroupUtil::GetThreadGroupChildren(jvmtiEnv* env,
+ jthreadGroup group,
+ jint* thread_count_ptr,
+ jthread** threads_ptr,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr) {
+ if (group == nullptr) {
+ return ERR(INVALID_THREAD_GROUP);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+
+ if (!soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup)) {
+ return ERR(INVALID_THREAD_GROUP);
+ }
+
+ art::StackHandleScope<1> hs(soa.Self());
+ art::Handle<art::mirror::Object> thread_group = hs.NewHandle(
+ soa.Decode<art::mirror::Object>(group));
+
+ art::ObjectLock<art::mirror::Object> thread_group_lock(soa.Self(), thread_group);
+
+ std::vector<art::ObjPtr<art::mirror::Object>> thread_peers;
+ GetThreads(thread_group, &thread_peers);
+
+ std::vector<art::ObjPtr<art::mirror::Object>> thread_groups;
+ GetChildThreadGroups(thread_group, &thread_groups);
+
+ jthread* thread_data = nullptr;
+ JvmtiUniquePtr peers_uptr;
+ if (!thread_peers.empty()) {
+ unsigned char* data;
+ jvmtiError res = env->Allocate(sizeof(jthread) * thread_peers.size(), &data);
+ if (res != ERR(NONE)) {
+ return res;
+ }
+ thread_data = reinterpret_cast<jthread*>(data);
+ peers_uptr = MakeJvmtiUniquePtr(env, data);
+ }
+
+ jthreadGroup* group_data = nullptr;
+ if (!thread_groups.empty()) {
+ unsigned char* data;
+ jvmtiError res = env->Allocate(sizeof(jthreadGroup) * thread_groups.size(), &data);
+ if (res != ERR(NONE)) {
+ return res;
+ }
+ group_data = reinterpret_cast<jthreadGroup*>(data);
+ }
+
+ // Can't fail anymore from here on.
+
+ // Copy data into out buffers.
+ for (size_t i = 0; i != thread_peers.size(); ++i) {
+ thread_data[i] = soa.AddLocalReference<jthread>(thread_peers[i]);
+ }
+ for (size_t i = 0; i != thread_groups.size(); ++i) {
+ group_data[i] = soa.AddLocalReference<jthreadGroup>(thread_groups[i]);
+ }
+
+ *thread_count_ptr = static_cast<jint>(thread_peers.size());
+ *threads_ptr = thread_data;
+ *group_count_ptr = static_cast<jint>(thread_groups.size());
+ *groups_ptr = group_data;
+
+ // Everything's fine.
+ peers_uptr.release();
+
+ return ERR(NONE);
+}
+
+} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_threadgroup.h b/runtime/openjdkjvmti/ti_threadgroup.h
new file mode 100644
index 0000000000..c3a0ff5e15
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_threadgroup.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_
+#define ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class ThreadGroupUtil {
+ public:
+ static jvmtiError GetTopThreadGroups(jvmtiEnv* env,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr);
+
+ static jvmtiError GetThreadGroupInfo(jvmtiEnv* env,
+ jthreadGroup group,
+ jvmtiThreadGroupInfo* info_ptr);
+
+ static jvmtiError GetThreadGroupChildren(jvmtiEnv* env,
+ jthreadGroup group,
+ jint* thread_count_ptr,
+ jthread** threads_ptr,
+ jint* group_count_ptr,
+ jthreadGroup** groups_ptr);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_TI_THREADGROUP_H_
diff --git a/runtime/openjdkjvmti/ti_timers.cc b/runtime/openjdkjvmti/ti_timers.cc
new file mode 100644
index 0000000000..24fb0419ee
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_timers.cc
@@ -0,0 +1,93 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "ti_timers.h"
+
+#include <limits>
+
+#ifndef __APPLE__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include <unistd.h>
+
+#include "art_jvmti.h"
+#include "base/macros.h"
+
+namespace openjdkjvmti {
+
+jvmtiError TimerUtil::GetAvailableProcessors(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jint* processor_count_ptr) {
+ if (processor_count_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ *processor_count_ptr = static_cast<jint>(sysconf(_SC_NPROCESSORS_CONF));
+
+ return ERR(NONE);
+}
+
+jvmtiError TimerUtil::GetTimerInfo(jvmtiEnv* env ATTRIBUTE_UNUSED, jvmtiTimerInfo* info_ptr) {
+ if (info_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ info_ptr->max_value = static_cast<jlong>(std::numeric_limits<uint64_t>::max());
+ info_ptr->may_skip_forward = JNI_TRUE;
+ info_ptr->may_skip_backward = JNI_TRUE;
+ info_ptr->kind = jvmtiTimerKind::JVMTI_TIMER_ELAPSED;
+
+ return ERR(NONE);
+}
+
+jvmtiError TimerUtil::GetTime(jvmtiEnv* env ATTRIBUTE_UNUSED, jlong* nanos_ptr) {
+ if (nanos_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+#ifndef __APPLE__
+ // Use the same implementation as System.nanoTime.
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ *nanos_ptr = now.tv_sec * 1000000000LL + now.tv_nsec;
+#else
+ // No CLOCK_MONOTONIC support on older Mac OS.
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ *nanos_ptr = static_cast<jlong>(t.tv_sec)*1000000000LL + static_cast<jlong>(t.tv_usec)*1000LL;
+#endif
+
+ return ERR(NONE);
+}
+
+} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_timers.h b/runtime/openjdkjvmti/ti_timers.h
new file mode 100644
index 0000000000..6300678ff7
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_timers.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_
+#define ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class TimerUtil {
+ public:
+ static jvmtiError GetAvailableProcessors(jvmtiEnv* env, jint* processor_count_ptr);
+
+ static jvmtiError GetTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr);
+
+ static jvmtiError GetTime(jvmtiEnv* env, jlong* nanos_ptr);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_TI_TIMERS_H_
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index e1022b000b..a72159bc80 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -763,8 +763,6 @@ void ParsedOptions::Usage(const char* fmt, ...) {
"(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/reflection.cc b/runtime/reflection.cc
index 4d2450135e..75176f938e 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -227,11 +227,11 @@ class ArgArray {
for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
ObjPtr<mirror::Object> arg(args->Get(args_offset));
if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+ // Note: The method's parameter's type must have been previously resolved.
ObjPtr<mirror::Class> dst_class(
m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_,
- true /* resolve */,
- pointer_size));
+ false /* resolve */));
+ DCHECK(dst_class != nullptr) << m->PrettyMethod() << " arg #" << i;
if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
ThrowIllegalArgumentException(
StringPrintf("method %s argument %zd has type %s, got %s",
@@ -363,12 +363,9 @@ static void CheckMethodArguments(JavaVMExt* vm, ArtMethod* m, uint32_t* args)
}
// TODO: If args contain object references, it may cause problems.
Thread* const self = Thread::Current();
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (uint32_t i = 0; i < num_params; i++) {
dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
- ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
- true /* resolve*/,
- pointer_size));
+ ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx, true /* resolve */));
if (param_type == nullptr) {
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 8fc211c6a3..a87e1c136b 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -304,7 +304,7 @@ class Runtime {
}
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 d1970fe7a2..ecabf9adc5 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -117,7 +117,7 @@ RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10)
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 a7e7c21a42..9ebf9a7bdd 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 @@ void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
<< "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 @@ void InlineInfo::Dump(VariableIndentationOutputStream* vios,
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 5e556be286..15d7816031 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -35,6 +35,7 @@ static constexpr ssize_t kFrameSlotSize = 4;
// Size of Dex virtual registers.
static constexpr size_t kVRegSize = 4;
+class ArtMethod;
class CodeInfo;
class StackMapEncoding;
struct CodeInfoEncoding;
@@ -887,7 +888,7 @@ class InlineInfoEncoding {
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 @@ class InlineInfoEncoding {
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 @@ class InlineInfoEncoding {
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 @@ class InlineInfoEncoding {
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 @@ class InlineInfoEncoding {
/**
* 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 @@ class InlineInfo {
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 @@ class InlineInfo {
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 SetExtraDataAtDepth(const InlineInfoEncoding& encoding,
+ uint32_t depth,
+ uint32_t extra_data) {
+ encoding.GetExtraDataEncoding().Store(GetRegionAtDepth(encoding, depth), extra_data);
}
- ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
- uint32_t depth,
- uint32_t invoke_type) {
- encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
+ 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.cc b/runtime/thread.cc
index 40b6d73d94..016a379437 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2632,8 +2632,6 @@ void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset) {
QUICK_ENTRY_POINT_INFO(pAllocObjectResolved)
QUICK_ENTRY_POINT_INFO(pAllocObjectInitialized)
QUICK_ENTRY_POINT_INFO(pAllocObjectWithChecks)
- QUICK_ENTRY_POINT_INFO(pCheckAndAllocArray)
- QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayWithAccessCheck)
QUICK_ENTRY_POINT_INFO(pAllocStringFromBytes)
QUICK_ENTRY_POINT_INFO(pAllocStringFromChars)
QUICK_ENTRY_POINT_INFO(pAllocStringFromString)
@@ -2667,10 +2665,7 @@ void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset) {
QUICK_ENTRY_POINT_INFO(pGet64Static)
QUICK_ENTRY_POINT_INFO(pGetObjInstance)
QUICK_ENTRY_POINT_INFO(pGetObjStatic)
- QUICK_ENTRY_POINT_INFO(pAputObjectWithNullAndBoundCheck)
- QUICK_ENTRY_POINT_INFO(pAputObjectWithBoundCheck)
QUICK_ENTRY_POINT_INFO(pAputObject)
- QUICK_ENTRY_POINT_INFO(pHandleFillArrayData)
QUICK_ENTRY_POINT_INFO(pJniMethodStart)
QUICK_ENTRY_POINT_INFO(pJniMethodStartSynchronized)
QUICK_ENTRY_POINT_INFO(pJniMethodEnd)
diff --git a/runtime/thread.h b/runtime/thread.h
index d54a80df99..2b451bcaee 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1140,6 +1140,14 @@ class Thread {
return debug_disallow_read_barrier_;
}
+ const void* GetCustomTLS() const {
+ return custom_tls_;
+ }
+
+ void SetCustomTLS(const void* data) {
+ custom_tls_ = data;
+ }
+
// Returns true if the current thread is the jit sensitive thread.
bool IsJitSensitiveThread() const {
return this == jit_sensitive_thread_;
@@ -1418,7 +1426,7 @@ class Thread {
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),
@@ -1537,21 +1545,21 @@ class Thread {
// 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;
@@ -1600,6 +1608,10 @@ class Thread {
// Pending extra checkpoints if checkpoint_function_ is already used.
std::list<Closure*> checkpoint_overflow_ GUARDED_BY(Locks::thread_suspend_count_lock_);
+ // Custom TLS field that can be used by plugins.
+ // TODO: Generalize once we have more plugins.
+ const void* custom_tls_;
+
// True if the thread is allowed to call back into java (for e.g. during class resolution).
// By default this is true.
bool can_call_into_java_;
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 3b114a9f10..bb9844af65 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -61,7 +61,7 @@ class VdexFile {
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/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 25a179bd32..b915457557 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2901,9 +2901,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
ArtMethod* called_method = VerifyInvocationArgs(inst, type, is_range);
const RegType* return_type = nullptr;
if (called_method != nullptr) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_,
- pointer_size);
+ mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
return_type = &FromClass(called_method->GetReturnTypeDescriptor(),
return_type_class,
@@ -2946,9 +2944,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
} else {
is_constructor = called_method->IsConstructor();
return_type_descriptor = called_method->GetReturnTypeDescriptor();
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_,
- pointer_size);
+ mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
return_type = &FromClass(return_type_descriptor,
return_type_class,
@@ -5133,9 +5129,7 @@ InstructionFlags* MethodVerifier::CurrentInsnFlags() {
const RegType& MethodVerifier::GetMethodReturnType() {
if (return_type_ == nullptr) {
if (mirror_method_ != nullptr) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* return_type_class = mirror_method_->GetReturnType(can_load_classes_,
- pointer_size);
+ mirror::Class* return_type_class = mirror_method_->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
return_type_ = &FromClass(mirror_method_->GetReturnTypeDescriptor(),
return_type_class,
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index a5b275cc3b..507ea165e5 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -103,6 +103,7 @@ jmethodID WellKnownClasses::java_lang_reflect_Parameter_init;
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 @@ void WellKnownClasses::Init(JNIEnv* env) {
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 371be61f43..b3ce3d1597 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -113,6 +113,7 @@ struct WellKnownClasses {
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 904393bc3b..0967278314 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 0ae92a96dc..a6c18b75fc 100644
--- a/test/080-oom-throw/src/Main.java
+++ b/test/080-oom-throw/src/Main.java
@@ -53,6 +53,30 @@ public class Main {
}
}
+ 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 @@ public class Main {
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 @@ public class Main {
}
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/129-ThreadGetId/src/Main.java b/test/129-ThreadGetId/src/Main.java
index 6ba01ff0b5..4e48e0e1a6 100644
--- a/test/129-ThreadGetId/src/Main.java
+++ b/test/129-ThreadGetId/src/Main.java
@@ -23,7 +23,6 @@ public class Main implements Runnable {
public static void main(String[] args) throws Exception {
final Thread[] threads = new Thread[numberOfThreads];
- test_getStackTraces();
for (int t = 0; t < threads.length; t++) {
threads[t] = new Thread(new Main());
threads[t].start();
@@ -31,6 +30,9 @@ public class Main implements Runnable {
for (Thread t : threads) {
t.join();
}
+ // Do this test after the other part to leave some time for the heap task daemon to start
+ // up.
+ test_getStackTraces();
System.out.println("Finishing");
}
diff --git a/test/633-checker-rtp-getclass/expected.txt b/test/633-checker-rtp-getclass/expected.txt
new file mode 100644
index 0000000000..a178d0414b
--- /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 0000000000..e98a0acbbb
--- /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 0000000000..f29c139f63
--- /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 0000000000..557db03de9
--- /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 0000000000..e69de29bb2
--- /dev/null
+++ b/test/634-vdex-duplicate/info.txt
diff --git a/test/634-vdex-duplicate/run b/test/634-vdex-duplicate/run
new file mode 100644
index 0000000000..1ccb84150b
--- /dev/null
+++ b/test/634-vdex-duplicate/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+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 0000000000..228310697a
--- /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 0000000000..c32868cf37
--- /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 3a475c6fef..052fb9ac13 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 @@ jint OnLoad(JavaVM* vm,
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 414eb3b2ae..2aee99b25a 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 1ef6289559..775e5c2e0c 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/912-classes/classes.cc b/test/912-classes/classes.cc
index 69301c7925..a22d1d72d8 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -222,5 +222,24 @@ extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader(
return classloader;
}
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) {
+ jint count = 0;
+ jclass* classes = nullptr;
+ jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint i) {
+ return classes[i];
+ };
+ jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
+ if (classes != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
+ }
+ return ret;
+}
+
} // namespace Test912Classes
} // namespace art
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 44c861a3b7..a95a465860 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -43,3 +43,19 @@ class java.lang.String null
class [Ljava.lang.String; null
interface Main$InfA dalvik.system.PathClassLoader
class $Proxy0 dalvik.system.PathClassLoader
+
+boot <- src <- src-ex (A,B)
+912-classes-ex.jar+ -> 912-classes.jar+ ->
+[class A, class B, class java.lang.Object]
+912-classes.jar+ ->
+[class B, class java.lang.Object]
+
+boot <- src (B) <- src-ex (A, List)
+912-classes-ex.jar+ -> 912-classes.jar+ ->
+[class A, class java.lang.Object, interface java.util.List]
+912-classes.jar+ ->
+[class B, class java.lang.Object]
+
+boot <- src+src-ex (A,B)
+912-classes.jar+ ->
+[class A, class B, class java.lang.Object]
diff --git a/test/912-classes/run b/test/912-classes/run
index 4379349cb2..20dfc4b767 100755
--- a/test/912-classes/run
+++ b/test/912-classes/run
@@ -14,6 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# This test checks which classes are initiated by a classloader. App images preload classes.
+# In certain configurations, the app images may be valid even in a new classloader. Turn off
+# app images to avoid the issue.
+
./default-run "$@" --experimental agents \
--experimental runtime-plugins \
- --jvmti
+ --jvmti \
+ --no-app-image
diff --git a/test/912-classes/src-ex/A.java b/test/912-classes/src-ex/A.java
new file mode 100644
index 0000000000..64acb2fcfe
--- /dev/null
+++ b/test/912-classes/src-ex/A.java
@@ -0,0 +1,18 @@
+/*
+ * 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 A {
+} \ No newline at end of file
diff --git a/test/912-classes/src/B.java b/test/912-classes/src/B.java
new file mode 100644
index 0000000000..f1458c3bca
--- /dev/null
+++ b/test/912-classes/src/B.java
@@ -0,0 +1,18 @@
+/*
+ * 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 B {
+} \ No newline at end of file
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index e627d4227a..ea3c49c87b 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Arrays;
+import java.util.Comparator;
public class Main {
public static void main(String[] args) throws Exception {
@@ -76,6 +78,8 @@ public class Main {
testClassLoader(String[].class);
testClassLoader(InfA.class);
testClassLoader(getProxyClass());
+
+ testClassLoaderClasses();
}
private static Class<?> proxyClass = null;
@@ -151,6 +155,95 @@ public class Main {
}
}
+ private static void testClassLoaderClasses() throws Exception {
+ ClassLoader boot = ClassLoader.getSystemClassLoader().getParent();
+ while (boot.getParent() != null) {
+ boot = boot.getParent();
+ }
+
+ System.out.println();
+ System.out.println("boot <- src <- src-ex (A,B)");
+ ClassLoader cl1 = create(create(boot, DEX1), DEX2);
+ Class.forName("B", false, cl1);
+ Class.forName("A", false, cl1);
+ printClassLoaderClasses(cl1);
+
+ System.out.println();
+ System.out.println("boot <- src (B) <- src-ex (A, List)");
+ ClassLoader cl2 = create(create(boot, DEX1), DEX2);
+ Class.forName("A", false, cl2);
+ Class.forName("java.util.List", false, cl2);
+ Class.forName("B", false, cl2.getParent());
+ printClassLoaderClasses(cl2);
+
+ System.out.println();
+ System.out.println("boot <- src+src-ex (A,B)");
+ ClassLoader cl3 = create(boot, DEX1, DEX2);
+ Class.forName("B", false, cl3);
+ Class.forName("A", false, cl3);
+ printClassLoaderClasses(cl3);
+
+ // Check that the boot classloader dumps something non-empty.
+ Class<?>[] bootClasses = getClassLoaderClasses(boot);
+ if (bootClasses.length == 0) {
+ throw new RuntimeException("No classes initiated by boot classloader.");
+ }
+ // Check that at least java.util.List is loaded.
+ boolean foundList = false;
+ for (Class<?> c : bootClasses) {
+ if (c == java.util.List.class) {
+ foundList = true;
+ break;
+ }
+ }
+ if (!foundList) {
+ System.out.println(Arrays.toString(bootClasses));
+ throw new RuntimeException("Could not find class java.util.List.");
+ }
+ }
+
+ private static void printClassLoaderClasses(ClassLoader cl) {
+ for (;;) {
+ if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) {
+ break;
+ }
+
+ ClassLoader saved = cl;
+ for (;;) {
+ if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) {
+ break;
+ }
+ String s = cl.toString();
+ int index1 = s.indexOf("zip file");
+ int index2 = s.indexOf(']', index1);
+ if (index2 < 0) {
+ throw new RuntimeException("Unexpected classloader " + s);
+ }
+ String zip_file = s.substring(index1, index2);
+ int index3 = zip_file.indexOf('"');
+ int index4 = zip_file.indexOf('"', index3 + 1);
+ if (index4 < 0) {
+ throw new RuntimeException("Unexpected classloader " + s);
+ }
+ String paths = zip_file.substring(index3 + 1, index4);
+ String pathArray[] = paths.split(":");
+ for (String path : pathArray) {
+ int index5 = path.lastIndexOf('/');
+ System.out.print(path.substring(index5 + 1));
+ System.out.print('+');
+ }
+ System.out.print(" -> ");
+ cl = cl.getParent();
+ }
+ System.out.println();
+ Class<?> classes[] = getClassLoaderClasses(saved);
+ Arrays.sort(classes, new ClassNameComparator());
+ System.out.println(Arrays.toString(classes));
+
+ cl = saved.getParent();
+ }
+ }
+
private static native boolean isModifiableClass(Class<?> c);
private static native String[] getClassSignature(Class<?> c);
@@ -161,12 +254,14 @@ public class Main {
private static native Object[] getClassFields(Class<?> c);
private static native Object[] getClassMethods(Class<?> c);
- private static native Class[] getImplementedInterfaces(Class<?> c);
+ private static native Class<?>[] getImplementedInterfaces(Class<?> c);
private static native int getClassStatus(Class<?> c);
private static native Object getClassLoader(Class<?> c);
+ private static native Class<?>[] getClassLoaderClasses(ClassLoader cl);
+
private static class TestForNonInit {
public static double dummy = Math.random(); // So it can't be compile-time initialized.
}
@@ -188,4 +283,23 @@ public class Main {
}
public abstract static class ClassC implements InfA, InfC {
}
+
+ private static final String DEX1 = System.getenv("DEX_LOCATION") + "/912-classes.jar";
+ private static final String DEX2 = System.getenv("DEX_LOCATION") + "/912-classes-ex.jar";
+
+ private static ClassLoader create(ClassLoader parent, String... elements) throws Exception {
+ // Note: We use a PathClassLoader, as we do not care about code performance. We only load
+ // the classes, and they're empty.
+ Class<?> pathClassLoaderClass = Class.forName("dalvik.system.PathClassLoader");
+ Constructor<?> pathClassLoaderInit = pathClassLoaderClass.getConstructor(String.class,
+ ClassLoader.class);
+ String path = String.join(":", elements);
+ return (ClassLoader) pathClassLoaderInit.newInstance(path, parent);
+ }
+
+ private static class ClassNameComparator implements Comparator<Class<?>> {
+ public int compare(Class<?> c1, Class<?> c2) {
+ return c1.getName().compareTo(c2.getName());
+ }
+ }
}
diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java
index 74eb003d5c..1e43f7ee9d 100644
--- a/test/916-obsolete-jit/src/Main.java
+++ b/test/916-obsolete-jit/src/Main.java
@@ -157,38 +157,13 @@ public class Main {
doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
}
};
- // This does nothing.
- Runnable noop = () -> {};
// This just prints something out to show we are running the Runnable.
Runnable say_nothing = () -> { w.accept("Not doing anything here"); };
- // This checks to see if we have jitted the methods we are testing.
- Runnable check_interpreting = () -> {
- // TODO remove the second check when we remove the doCall function. We need to check that
- // both of these functions aren't being interpreted because if sayHi is the test doesn't do
- // anything and if doCall is then there will be a runtime call right above the sayHi
- // function preventing sayHi from being deoptimized.
- interpreting = has_jit && (Main.isInterpretedFunction(say_hi_method, true) ||
- Main.isInterpretedFunction(do_call_method, false));
- };
do {
- w.clear();
- // Wait for the methods to be jitted
- long j = 0;
- do {
- for (int i = 0; i < 10000; i++) {
- t.sayHi(noop, w);
- j++;
- // Clear so that we won't OOM if we go around a few times.
- w.clear();
- }
- t.sayHi(check_interpreting, w);
- if (j >= 1000000) {
- System.out.println("FAIL: Could not make sayHi be Jitted!");
- return;
- }
- j++;
- } while(interpreting);
- // Clear output. Now we try for real.
+ // Run ensureJitCompiled here since it might get GCd
+ ensureJitCompiled(Transform.class, "sayHi");
+ ensureJitCompiled(Main.class, "doCall");
+ // Clear output.
w.clear();
// Try and redefine.
t.sayHi(say_nothing, w);
@@ -203,6 +178,8 @@ public class Main {
private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable);
+ private static native void ensureJitCompiled(Class c, String name);
+
// Transforms the class
private static native void doCommonClassRedefinition(Class<?> target,
byte[] classfile,
diff --git a/test/953-invoke-polymorphic-compiler/run b/test/925-threadgroups/build
index a9f182288c..898e2e54a2 100755
--- a/test/953-invoke-polymorphic-compiler/run
+++ b/test/925-threadgroups/build
@@ -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
+./default-build "$@" --experimental agents
diff --git a/test/925-threadgroups/expected.txt b/test/925-threadgroups/expected.txt
new file mode 100644
index 0000000000..7d1a259c89
--- /dev/null
+++ b/test/925-threadgroups/expected.txt
@@ -0,0 +1,16 @@
+java.lang.ThreadGroup[name=main,maxpri=10]
+ java.lang.ThreadGroup[name=system,maxpri=10]
+ main
+ 10
+ false
+java.lang.ThreadGroup[name=system,maxpri=10]
+ null
+ system
+ 10
+ false
+main:
+ [Thread[main,5,main]]
+ []
+system:
+ [Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[Signal Catcher,5,system]]
+ [java.lang.ThreadGroup[name=main,maxpri=10]]
diff --git a/test/925-threadgroups/info.txt b/test/925-threadgroups/info.txt
new file mode 100644
index 0000000000..875a5f6ec1
--- /dev/null
+++ b/test/925-threadgroups/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/955-methodhandles-smali/run b/test/925-threadgroups/run
index a9f182288c..4379349cb2 100755
--- a/test/955-methodhandles-smali/run
+++ b/test/925-threadgroups/run
@@ -14,7 +14,6 @@
# 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
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/925-threadgroups/src/Main.java b/test/925-threadgroups/src/Main.java
new file mode 100644
index 0000000000..c59efe2f7b
--- /dev/null
+++ b/test/925-threadgroups/src/Main.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ private static void doTest() throws Exception {
+ Thread t1 = Thread.currentThread();
+ ThreadGroup curGroup = t1.getThreadGroup();
+
+ ThreadGroup rootGroup = curGroup;
+ while (rootGroup.getParent() != null) {
+ rootGroup = rootGroup.getParent();
+ }
+
+ ThreadGroup topGroups[] = getTopThreadGroups();
+ if (topGroups == null || topGroups.length != 1 || topGroups[0] != rootGroup) {
+ System.out.println(Arrays.toString(topGroups));
+ throw new RuntimeException("Unexpected topGroups");
+ }
+
+ printThreadGroupInfo(curGroup);
+ printThreadGroupInfo(rootGroup);
+
+ waitGroupChildren(rootGroup, 5 /* # daemons */, 30 /* timeout in seconds */);
+
+ checkChildren(curGroup);
+ }
+
+ private static void printThreadGroupInfo(ThreadGroup tg) {
+ Object[] threadGroupInfo = getThreadGroupInfo(tg);
+ if (threadGroupInfo == null || threadGroupInfo.length != 4) {
+ System.out.println(Arrays.toString(threadGroupInfo));
+ throw new RuntimeException("threadGroupInfo length wrong");
+ }
+
+ System.out.println(tg);
+ System.out.println(" " + threadGroupInfo[0]); // Parent
+ System.out.println(" " + threadGroupInfo[1]); // Name
+ System.out.println(" " + threadGroupInfo[2]); // Priority
+ System.out.println(" " + threadGroupInfo[3]); // Daemon
+ }
+
+ private static void checkChildren(ThreadGroup tg) {
+ Object[] data = getThreadGroupChildren(tg);
+ Thread[] threads = (Thread[])data[0];
+ ThreadGroup[] groups = (ThreadGroup[])data[1];
+
+ Arrays.sort(threads, THREAD_COMP);
+ Arrays.sort(groups, THREADGROUP_COMP);
+ System.out.println(tg.getName() + ":");
+ System.out.println(" " + Arrays.toString(threads));
+ System.out.println(" " + Arrays.toString(groups));
+
+ if (tg.getParent() != null) {
+ checkChildren(tg.getParent());
+ }
+ }
+
+ private static void waitGroupChildren(ThreadGroup tg, int expectedChildCount, int timeoutS)
+ throws Exception {
+ for (int i = 0; i < timeoutS; i++) {
+ Object[] data = getThreadGroupChildren(tg);
+ Thread[] threads = (Thread[])data[0];
+ if (threads.length == expectedChildCount) {
+ return;
+ }
+ Thread.sleep(1000);
+ }
+
+ Object[] data = getThreadGroupChildren(tg);
+ Thread[] threads = (Thread[])data[0];
+ System.out.println(Arrays.toString(threads));
+ throw new RuntimeException("Waited unsuccessfully for " + expectedChildCount + " children.");
+ }
+
+ private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
+ public int compare(Thread o1, Thread o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
+ private final static Comparator<ThreadGroup> THREADGROUP_COMP = new Comparator<ThreadGroup>() {
+ public int compare(ThreadGroup o1, ThreadGroup o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
+ private static native ThreadGroup[] getTopThreadGroups();
+ private static native Object[] getThreadGroupInfo(ThreadGroup tg);
+ // Returns an array where element 0 is an array of threads and element 1 is an array of groups.
+ private static native Object[] getThreadGroupChildren(ThreadGroup tg);
+}
diff --git a/test/925-threadgroups/threadgroups.cc b/test/925-threadgroups/threadgroups.cc
new file mode 100644
index 0000000000..6c6e835dd3
--- /dev/null
+++ b/test/925-threadgroups/threadgroups.cc
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "android-base/stringprintf.h"
+#include "base/macros.h"
+#include "base/logging.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedLocalRef.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test925ThreadGroups {
+
+// private static native Object[] getThreadGroupInfo();
+// // Returns an array where element 0 is an array of threads and element 1 is an array of groups.
+// private static native Object[] getThreadGroupChildren();
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getTopThreadGroups(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jthreadGroup* groups;
+ jint group_count;
+ jvmtiError result = jvmti_env->GetTopThreadGroups(&group_count, &groups);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint index) -> jobject {
+ return groups[index];
+ };
+ jobjectArray ret = CreateObjectArray(env, group_count, "java/lang/ThreadGroup", callback);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(groups));
+
+ return ret;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getThreadGroupInfo(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthreadGroup group) {
+ jvmtiThreadGroupInfo info;
+ jvmtiError result = jvmti_env->GetThreadGroupInfo(group, &info);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint index) -> jobject {
+ switch (index) {
+ // The parent.
+ case 0:
+ return info.parent;
+
+ // The name.
+ case 1:
+ return (info.name == nullptr) ? nullptr : env->NewStringUTF(info.name);
+
+ // The priority. Use a string for simplicity of construction.
+ case 2:
+ return env->NewStringUTF(android::base::StringPrintf("%d", info.max_priority).c_str());
+
+ // Whether it's a daemon. Use a string for simplicity of construction.
+ case 3:
+ return env->NewStringUTF(info.is_daemon == JNI_TRUE ? "true" : "false");
+ }
+ LOG(FATAL) << "Should not reach here";
+ UNREACHABLE();
+ };
+ return CreateObjectArray(env, 4, "java/lang/Object", callback);
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getThreadGroupChildren(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthreadGroup group) {
+ jint thread_count;
+ jthread* threads;
+ jint threadgroup_count;
+ jthreadGroup* groups;
+
+ jvmtiError result = jvmti_env->GetThreadGroupChildren(group,
+ &thread_count,
+ &threads,
+ &threadgroup_count,
+ &groups);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint component_index) -> jobject {
+ if (component_index == 0) {
+ // Threads.
+ auto inner_callback = [&](jint index) {
+ return threads[index];
+ };
+ return CreateObjectArray(env, thread_count, "java/lang/Thread", inner_callback);
+ } else {
+ // Groups.
+ auto inner_callback = [&](jint index) {
+ return groups[index];
+ };
+ return CreateObjectArray(env, threadgroup_count, "java/lang/ThreadGroup", inner_callback);
+ }
+ };
+ jobjectArray ret = CreateObjectArray(env, 2, "java/lang/Object", callback);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(threads));
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(groups));
+
+ return ret;
+}
+
+} // namespace Test925ThreadGroups
+} // namespace art
diff --git a/test/954-invoke-polymorphic-verifier/run b/test/927-timers/build
index a9f182288c..898e2e54a2 100755
--- a/test/954-invoke-polymorphic-verifier/run
+++ b/test/927-timers/build
@@ -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
+./default-build "$@" --experimental agents
diff --git a/test/927-timers/expected.txt b/test/927-timers/expected.txt
new file mode 100644
index 0000000000..a4ef4424b6
--- /dev/null
+++ b/test/927-timers/expected.txt
@@ -0,0 +1,3 @@
+availableProcessors OK
+[-1, true, true, 32]
+Time OK
diff --git a/test/927-timers/info.txt b/test/927-timers/info.txt
new file mode 100644
index 0000000000..875a5f6ec1
--- /dev/null
+++ b/test/927-timers/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/956-methodhandles/run b/test/927-timers/run
index a9f182288c..4379349cb2 100755
--- a/test/956-methodhandles/run
+++ b/test/927-timers/run
@@ -14,7 +14,6 @@
# 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
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/927-timers/src/Main.java b/test/927-timers/src/Main.java
new file mode 100644
index 0000000000..2f5c85cab5
--- /dev/null
+++ b/test/927-timers/src/Main.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ private static void doTest() {
+ int all1 = Runtime.getRuntime().availableProcessors();
+ int all2 = getAvailableProcessors();
+ if (all1 != all2) {
+ throw new RuntimeException("Available processors doesn't match: " + all1 + " vs " + all2);
+ }
+ System.out.println("availableProcessors OK");
+
+ Object info[] = getTimerInfo();
+ System.out.println(Arrays.toString(info));
+
+ // getTime checks.
+ // Note: there isn't really much to check independent from the implementation. So we check
+ // a few details of the ART implementation. This may fail on other runtimes.
+ long time1 = getTime();
+ long time2 = getTime();
+
+ // Under normal circumstances, time1 <= time2.
+ if (time2 < time1) {
+ throw new RuntimeException("Time unexpectedly decreased: " + time1 + " vs " + time2);
+ }
+
+ long time3 = System.nanoTime();
+ long time4 = getTime();
+
+ final long MINUTE = 60l * 1000 * 1000 * 1000;
+ if (time4 < time3 || (time4 - time3 > MINUTE)) {
+ throw new RuntimeException("Time unexpectedly divergent: " + time3 + " vs " + time4);
+ }
+
+ System.out.println("Time OK");
+ }
+
+ private static native int getAvailableProcessors();
+ private static native Object[] getTimerInfo();
+ private static native long getTime();
+}
diff --git a/test/927-timers/timers.cc b/test/927-timers/timers.cc
new file mode 100644
index 0000000000..58d5c271e6
--- /dev/null
+++ b/test/927-timers/timers.cc
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test926Timers {
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getAvailableProcessors(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jint count;
+ jvmtiError result = jvmti_env->GetAvailableProcessors(&count);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+ return count;
+}
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getTime(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jlong time;
+ jvmtiError result = jvmti_env->GetTime(&time);
+ if (JvmtiErrorToException(env, result)) {
+ return -1;
+ }
+ return time;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getTimerInfo(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jvmtiTimerInfo info;
+ jvmtiError result = jvmti_env->GetTimerInfo(&info);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint index) -> jobject {
+ switch (index) {
+ // Max value.
+ case 0:
+ return env->NewStringUTF(android::base::StringPrintf("%" PRId64, info.max_value).c_str());
+
+ // Skip forward.
+ case 1:
+ return env->NewStringUTF(info.may_skip_forward == JNI_TRUE ? "true" : "false");
+ // Skip backward.
+ case 2:
+ return env->NewStringUTF(info.may_skip_forward == JNI_TRUE ? "true" : "false");
+
+ // The kind.
+ case 3:
+ return env->NewStringUTF(
+ android::base::StringPrintf("%d", static_cast<jint>(info.kind)).c_str());
+ }
+ LOG(FATAL) << "Should not reach here";
+ UNREACHABLE();
+ };
+ return CreateObjectArray(env, 4, "java/lang/Object", callback);
+}
+
+} // namespace Test926Timers
+} // namespace art
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 17b56b4fd9..f8daba6239 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -76,6 +76,7 @@ public class Main {
testStringConstructors();
testReturnValueConversions();
testVariableArity();
+ testVariableArity_MethodHandles_bind();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -1466,4 +1467,23 @@ public class Main {
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 a9f182288c..0000000000
--- 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 9e79ff4c10..eebf55fb61 100644
--- a/test/957-methodhandle-transforms/src/Main.java
+++ b/test/957-methodhandle-transforms/src/Main.java
@@ -33,6 +33,7 @@ public class Main {
testBindTo();
testFilterReturnValue();
testPermuteArguments();
+ testInvokers();
}
public static void testThrowException() throws Throwable {
@@ -888,6 +889,38 @@ public class Main {
}
}
+ 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 a9f182288c..0000000000
--- 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 a9f182288c..0000000000
--- 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/Android.bp b/test/Android.bp
index b0f0e5a98d..c551b9de45 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -265,6 +265,8 @@ art_cc_defaults {
"922-properties/properties.cc",
"923-monitors/monitors.cc",
"924-threads/threads.cc",
+ "925-threadgroups/threadgroups.cc",
+ "927-timers/timers.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 60688760a4..9da96de6a6 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -303,7 +303,9 @@ TEST_ART_BROKEN_TARGET_TESTS += \
922-properties \
923-monitors \
924-threads \
+ 925-threadgroups \
926-multi-obsolescence \
+ 927-timers \
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -464,10 +466,12 @@ TEST_ART_BROKEN_FALLBACK_RUN_TESTS := \
629-vdex-speed
# This test fails without an image.
-# 964 often times out due to the large number of classes it tries to compile.
+# 018, 961, 964 often time out. b/34369284
TEST_ART_BROKEN_NO_IMAGE_RUN_TESTS := \
137-cfi \
138-duplicate-classes-check \
+ 018-stack-overflow \
+ 961-default-iface-resolution-gen \
964-default-iface-init
ifneq (,$(filter no-dex2oat,$(PREBUILD_TYPES)))
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 1b6fc7033a..a841f9e6a2 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -33,12 +33,18 @@ namespace art {
// public static native boolean hasJit();
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass) {
+static jit::Jit* GetJitIfEnabled() {
Runtime* runtime = Runtime::Current();
- return runtime != nullptr
+ bool can_jit =
+ runtime != nullptr
&& runtime->GetJit() != nullptr
&& runtime->GetInstrumentation()->GetCurrentInstrumentationLevel() !=
instrumentation::Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter;
+ return can_jit ? runtime->GetJit() : nullptr;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass) {
+ return GetJitIfEnabled() != nullptr;
}
// public static native boolean hasOatFile();
@@ -152,7 +158,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
jclass,
jclass cls,
jstring method_name) {
- jit::Jit* jit = Runtime::Current()->GetJit();
+ jit::Jit* jit = GetJitIfEnabled();
if (jit == nullptr) {
return;
}
@@ -166,6 +172,11 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
CHECK(chars.c_str() != nullptr);
method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
chars.c_str(), kRuntimePointerSize);
+ if (method == nullptr) {
+ method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
+ chars.c_str(), kRuntimePointerSize);
+ }
+ DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
}
jit::JitCodeCache* code_cache = jit->GetCodeCache();
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 4794f6b7c1..5f1071f658 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -62,6 +62,7 @@ DRY_RUN="n" # if y prepare to run the test but don't run it.
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 @@ while true; do
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 @@ if [ "$PREBUILD" = "y" ]; then
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 abe73c3159..a913e783d3 100755
--- a/test/run-test
+++ b/test/run-test
@@ -354,6 +354,11 @@ while true; do
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"