diff options
author | 2014-01-15 11:46:48 -0800 | |
---|---|---|
committer | 2014-01-23 15:29:12 -0800 | |
commit | be1ca55db3362f5b100c4c65da5342fd299520bb (patch) | |
tree | b9df6f5562d884698ed15f21764a704bb51e359e | |
parent | 9d8918fe97c235fdc6eb2c7f2d50a6673ab50329 (diff) |
Use direct class pointers at allocation sites in the compiled code.
- Rather than looking up a class from its type ID (and checking if
it's resolved/initialized, resolving/initializing if not), use
direct class pointers, if possible (boot-code-to-boot-class pointers
and app-code-to-boot-class pointers.)
- This results in a 1-2% speedup in Ritz MemAllocTest on Nexus 4.
- Embedding the object size (along with class pointers) caused a 1-2%
slowdown in MemAllocTest and isn't implemented in this change.
- TODO: do the same for array allocations.
- TODO: when/if an application gets its own image, implement
app-code-to-app-class pointers.
- Fix a -XX:gc bug.
cf. https://android-review.googlesource.com/79460/
- Add /tmp/android-data/dalvik-cache to the list of locations to
remove oat files in clean-oat-host.
cf. https://android-review.googlesource.com/79550
- Add back a dropped UNLIKELY in FindMethodFromCode().
cf. https://android-review.googlesource.com/74205
Bug: 9986565
Change-Id: I590b96bd21f7a7472f88e36752e675547559a5b1
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 16 | ||||
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 49 | ||||
-rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 11 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 2 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 89 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 127 | ||||
-rw-r--r-- | compiler/image_writer.cc | 66 | ||||
-rw-r--r-- | runtime/arch/quick_alloc_entrypoints.S | 4 | ||||
-rw-r--r-- | runtime/arch/quick_alloc_entrypoints.cc | 8 | ||||
-rw-r--r-- | runtime/arch/x86/quick_entrypoints_x86.S | 20 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 79 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_alloc_entrypoints.cc | 12 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_entrypoints.h | 2 | ||||
-rw-r--r-- | runtime/globals.h | 4 | ||||
-rw-r--r-- | runtime/runtime.cc | 2 | ||||
-rw-r--r-- | runtime/thread.cc | 2 |
17 files changed, 433 insertions, 61 deletions
diff --git a/Android.mk b/Android.mk index bdd26da5da..4d9f6225db 100644 --- a/Android.mk +++ b/Android.mk @@ -63,6 +63,7 @@ clean-oat-host: rm -f $(TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.odex rm -f $(TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/*.odex rm -rf /tmp/test-*/dalvik-cache/*@classes.dex + rm -rf /tmp/android-data/dalvik-cache/*@classes.dex .PHONY: clean-oat-target clean-oat-target: diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 29554c0977..2ce7ecdecc 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -440,6 +440,20 @@ void Mir2Lir::InstallLiteralPools() { PushPointer(code_buffer_, &id); data_lir = NEXT_LIR(data_lir); } + // Push class literals. + data_lir = class_literal_list_; + while (data_lir != NULL) { + uint32_t target = data_lir->operands[0]; + cu_->compiler_driver->AddClassPatch(cu_->dex_file, + cu_->class_def_idx, + cu_->method_idx, + target, + code_buffer_.size()); + const DexFile::TypeId& id = cu_->dex_file->GetTypeId(target); + // unique value based on target to ensure code deduplication works + PushPointer(code_buffer_, &id); + data_lir = NEXT_LIR(data_lir); + } } /* Write the switch tables to the output stream */ @@ -772,6 +786,7 @@ int Mir2Lir::AssignLiteralOffset(CodeOffset offset) { offset = AssignLiteralOffsetCommon(literal_list_, offset); offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset); offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset); + offset = AssignLiteralPointerOffsetCommon(class_literal_list_, offset); return offset; } @@ -960,6 +975,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena : Backend(arena), literal_list_(NULL), method_literal_list_(NULL), + class_literal_list_(NULL), code_literal_list_(NULL), first_fixup_(NULL), cu_(cu), diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 3bd0298a22..daf21df19d 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -19,6 +19,7 @@ #include "dex/quick/mir_to_lir-inl.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" +#include "mirror/object-inl.h" #include "verifier/method_verifier.h" namespace art { @@ -883,13 +884,53 @@ void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { // alloc will always check for resolution, do we also need to verify // access because the verifier was unable to? ThreadOffset func_offset(-1); - if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks( - cu_->method_idx, *cu_->dex_file, type_idx)) { - func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject); + const DexFile* dex_file = cu_->dex_file; + CompilerDriver* driver = cu_->compiler_driver; + if (driver->CanAccessInstantiableTypeWithoutChecks( + cu_->method_idx, *dex_file, type_idx)) { + bool is_type_initialized; + bool use_direct_type_ptr; + uintptr_t direct_type_ptr; + if (kEmbedClassInCode && + driver->CanEmbedTypeInCode(*dex_file, type_idx, + &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) { + // The fast path. + if (!use_direct_type_ptr) { + // Use the literal pool and a PC-relative load from a data word. + LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0); + if (data_target == nullptr) { + data_target = AddWordData(&class_literal_list_, type_idx); + } + LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target); + AppendLIR(load_pc_rel); + if (!is_type_initialized) { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved); + CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true); + } else { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized); + CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true); + } + } else { + // Use the direct pointer. + if (!is_type_initialized) { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved); + CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true); + } else { + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized); + CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true); + } + } + } else { + // The slow path. + DCHECK_EQ(func_offset.Int32Value(), -1); + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject); + CallRuntimeHelperImmMethod(func_offset, type_idx, true); + } + DCHECK_NE(func_offset.Int32Value(), -1); } else { func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectWithAccessCheck); + CallRuntimeHelperImmMethod(func_offset, type_idx, true); } - CallRuntimeHelperImmMethod(func_offset, type_idx, true); RegLocation rl_result = GetReturn(false); StoreValue(rl_dest, rl_result); } diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index d942a24a18..f865207fc7 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -142,6 +142,17 @@ void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, b CallHelper(r_tgt, helper_offset, safepoint_pc); } +void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) { + int r_tgt = CallHelperSetup(helper_offset); + DCHECK_NE(TargetReg(kArg1), arg0); + if (TargetReg(kArg0) != arg0) { + OpRegCopy(TargetReg(kArg0), arg0); + } + LoadCurrMethodDirect(TargetReg(kArg1)); + ClobberCallerSave(); + CallHelper(r_tgt, helper_offset, safepoint_pc); +} + void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0, RegLocation arg1, bool safepoint_pc) { int r_tgt = CallHelperSetup(helper_offset); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index c157327109..f9d9e9e2f4 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -529,6 +529,7 @@ class Mir2Lir : public Backend { bool safepoint_pc); void CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc); + void CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc); void CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0, RegLocation arg1, bool safepoint_pc); @@ -855,6 +856,7 @@ class Mir2Lir : public Backend { // TODO: add accessors for these. LIR* literal_list_; // Constants. LIR* method_literal_list_; // Method literals requiring patching. + LIR* class_literal_list_; // Class literals requiring patching. LIR* code_literal_list_; // Code literals requiring patching. LIR* first_fixup_; // Doubly-linked list of LIR nodes requiring fixups. diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index f713151dc5..f390b4143f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -439,6 +439,10 @@ CompilerDriver::~CompilerDriver() { MutexLock mu(self, compiled_methods_lock_); STLDeleteElements(&methods_to_patch_); } + { + MutexLock mu(self, compiled_methods_lock_); + STLDeleteElements(&classes_to_patch_); + } CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key"); typedef void (*UninitCompilerContextFn)(CompilerDriver&); UninitCompilerContextFn uninit_compiler_context; @@ -906,6 +910,51 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id return result; } +bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr) { + ScopedObjectAccess soa(Thread::Current()); + mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); + if (resolved_class == nullptr) { + return false; + } + const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot(); + if (compiling_boot) { + // boot -> boot class pointers. + // True if the class is in the image at boot compiling time. + const bool is_image_class = IsImage() && IsImageClass( + dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_)); + // True if pc relative load works. + const bool support_boot_image_fixup = GetSupportBootImageFixup(); + if (is_image_class && support_boot_image_fixup) { + *is_type_initialized = resolved_class->IsInitialized(); + *use_direct_type_ptr = false; + *direct_type_ptr = 0; + return true; + } else { + return false; + } + } else { + // True if the class is in the image at app compiling time. + const bool class_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace(); + if (class_in_image) { + // boot -> app class pointers. + *is_type_initialized = resolved_class->IsInitialized(); + *use_direct_type_ptr = true; + *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class); + return true; + } else { + // app -> app class pointers. + // Give up because app does not have an image and class + // isn't created at compile time. TODO: implement this + // if/when each app gets an image. + return false; + } + } +} + static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa, SirtRef<mirror::DexCache>& dex_cache, const DexCompilationUnit* mUnit) @@ -1291,13 +1340,13 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file, InvokeType target_invoke_type, size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); - code_to_patch_.push_back(new PatchInformation(dex_file, - referrer_class_def_idx, - referrer_method_idx, - referrer_invoke_type, - target_method_idx, - target_invoke_type, - literal_offset)); + code_to_patch_.push_back(new CallPatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + referrer_invoke_type, + target_method_idx, + target_invoke_type, + literal_offset)); } void CompilerDriver::AddMethodPatch(const DexFile* dex_file, uint16_t referrer_class_def_idx, @@ -1307,13 +1356,25 @@ void CompilerDriver::AddMethodPatch(const DexFile* dex_file, InvokeType target_invoke_type, size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); - methods_to_patch_.push_back(new PatchInformation(dex_file, - referrer_class_def_idx, - referrer_method_idx, - referrer_invoke_type, - target_method_idx, - target_invoke_type, - literal_offset)); + methods_to_patch_.push_back(new CallPatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + referrer_invoke_type, + target_method_idx, + target_invoke_type, + literal_offset)); +} +void CompilerDriver::AddClassPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_type_idx, + size_t literal_offset) { + MutexLock mu(Thread::Current(), compiled_methods_lock_); + classes_to_patch_.push_back(new TypePatchInformation(dex_file, + referrer_class_def_idx, + referrer_method_idx, + target_type_idx, + literal_offset)); } class ParallelCompilationManager { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 9e316242ba..eef94a1fc1 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -189,6 +189,10 @@ class CompilerDriver { uint32_t type_idx) LOCKS_EXCLUDED(Locks::mutator_lock_); + bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr); + // Can we fast path instance field access? Computes field's offset and volatility. bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, int* field_offset, bool* is_volatile) @@ -228,6 +232,12 @@ class CompilerDriver { InvokeType target_invoke_type, size_t literal_offset) LOCKS_EXCLUDED(compiled_methods_lock_); + void AddClassPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_method_idx, + size_t literal_offset) + LOCKS_EXCLUDED(compiled_methods_lock_); void SetBitcodeFileName(std::string const& filename); @@ -267,6 +277,8 @@ class CompilerDriver { return thread_count_; } + class CallPatchInformation; + class TypePatchInformation; class PatchInformation { public: const DexFile& GetDexFile() const { @@ -278,55 +290,127 @@ class CompilerDriver { uint32_t GetReferrerMethodIdx() const { return referrer_method_idx_; } - InvokeType GetReferrerInvokeType() const { - return referrer_invoke_type_; + size_t GetLiteralOffset() const { + return literal_offset_; } - uint32_t GetTargetMethodIdx() const { - return target_method_idx_; + + virtual bool IsCall() const { + return false; } - InvokeType GetTargetInvokeType() const { - return target_invoke_type_; + virtual bool IsType() const { + return false; } - size_t GetLiteralOffset() const {; - return literal_offset_; + virtual const CallPatchInformation* AsCall() const { + LOG(FATAL) << "Unreachable"; + return nullptr; + } + virtual const TypePatchInformation* AsType() const { + LOG(FATAL) << "Unreachable"; + return nullptr; } - private: + protected: PatchInformation(const DexFile* dex_file, uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, size_t literal_offset) : dex_file_(dex_file), referrer_class_def_idx_(referrer_class_def_idx), referrer_method_idx_(referrer_method_idx), - referrer_invoke_type_(referrer_invoke_type), - target_method_idx_(target_method_idx), - target_invoke_type_(target_invoke_type), literal_offset_(literal_offset) { CHECK(dex_file_ != NULL); } + virtual ~PatchInformation() {} const DexFile* const dex_file_; const uint16_t referrer_class_def_idx_; const uint32_t referrer_method_idx_; + const size_t literal_offset_; + + friend class CompilerDriver; + }; + + class CallPatchInformation : public PatchInformation { + public: + InvokeType GetReferrerInvokeType() const { + return referrer_invoke_type_; + } + uint32_t GetTargetMethodIdx() const { + return target_method_idx_; + } + InvokeType GetTargetInvokeType() const { + return target_invoke_type_; + } + + const CallPatchInformation* AsCall() const { + return this; + } + bool IsCall() const { + return true; + } + + private: + CallPatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) + : PatchInformation(dex_file, referrer_class_def_idx, + referrer_method_idx, literal_offset), + referrer_invoke_type_(referrer_invoke_type), + target_method_idx_(target_method_idx), + target_invoke_type_(target_invoke_type) { + } + const InvokeType referrer_invoke_type_; const uint32_t target_method_idx_; const InvokeType target_invoke_type_; - const size_t literal_offset_; friend class CompilerDriver; - DISALLOW_COPY_AND_ASSIGN(PatchInformation); + DISALLOW_COPY_AND_ASSIGN(CallPatchInformation); }; - const std::vector<const PatchInformation*>& GetCodeToPatch() const { + class TypePatchInformation : public PatchInformation { + public: + uint32_t GetTargetTypeIdx() const { + return target_type_idx_; + } + + bool IsType() const { + return true; + } + const TypePatchInformation* AsType() const { + return this; + } + + private: + TypePatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + uint32_t target_type_idx, + size_t literal_offset) + : PatchInformation(dex_file, referrer_class_def_idx, + referrer_method_idx, literal_offset), + target_type_idx_(target_type_idx) { + } + + const uint32_t target_type_idx_; + + friend class CompilerDriver; + DISALLOW_COPY_AND_ASSIGN(TypePatchInformation); + }; + + const std::vector<const CallPatchInformation*>& GetCodeToPatch() const { return code_to_patch_; } - const std::vector<const PatchInformation*>& GetMethodsToPatch() const { + const std::vector<const CallPatchInformation*>& GetMethodsToPatch() const { return methods_to_patch_; } + const std::vector<const TypePatchInformation*>& GetClassesToPatch() const { + return classes_to_patch_; + } // Checks if class specified by type_idx is one of the image_classes_ bool IsImageClass(const char* descriptor) const; @@ -398,8 +482,9 @@ class CompilerDriver { static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_); - std::vector<const PatchInformation*> code_to_patch_; - std::vector<const PatchInformation*> methods_to_patch_; + std::vector<const CallPatchInformation*> code_to_patch_; + std::vector<const CallPatchInformation*> methods_to_patch_; + std::vector<const TypePatchInformation*> classes_to_patch_; VerifiedMethodsData* verified_methods_data_; DexFileToMethodInlinerMap* method_inliner_map_; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 556dec25ad..09bb70cd2f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -734,7 +734,7 @@ void ImageWriter::FixupFields(const Object* orig, } } -static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) +static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Thread* self = Thread::Current(); @@ -757,15 +757,34 @@ static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) return method; } +static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Thread* self = Thread::Current(); + SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(patch->GetDexFile())); + SirtRef<mirror::ClassLoader> class_loader(self, nullptr); + Class* klass = class_linker->ResolveType(patch->GetDexFile(), + patch->GetTargetTypeIdx(), + dex_cache, + class_loader); + CHECK(klass != NULL) + << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx(); + CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass) + << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " " + << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " " + << PrettyClass(klass); + return klass; +} + void ImageWriter::PatchOatCodeAndMethods() { Thread* self = Thread::Current(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); - typedef std::vector<const CompilerDriver::PatchInformation*> Patches; - const Patches& code_to_patch = compiler_driver_.GetCodeToPatch(); + typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches; + const CallPatches& code_to_patch = compiler_driver_.GetCodeToPatch(); for (size_t i = 0; i < code_to_patch.size(); i++) { - const CompilerDriver::PatchInformation* patch = code_to_patch[i]; + const CompilerDriver::CallPatchInformation* patch = code_to_patch[i]; ArtMethod* target = GetTargetMethod(patch); uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target)); uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader()); @@ -773,13 +792,21 @@ void ImageWriter::PatchOatCodeAndMethods() { SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset))); } - const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); + const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); for (size_t i = 0; i < methods_to_patch.size(); i++) { - const CompilerDriver::PatchInformation* patch = methods_to_patch[i]; + const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; ArtMethod* target = GetTargetMethod(patch); SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); } + const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = + compiler_driver_.GetClassesToPatch(); + for (size_t i = 0; i < classes_to_patch.size(); i++) { + const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i]; + Class* target = GetTargetType(patch); + SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); + } + // Update the image header with the new checksum after patching ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum()); @@ -796,13 +823,26 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(oat_code) & ~0x1); uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset()); if (kIsDebugBuild) { - const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx()); - uint32_t expected = reinterpret_cast<uint32_t>(&id); - uint32_t actual = *patch_location; - CHECK(actual == expected || actual == value) << std::hex - << "actual=" << actual - << "expected=" << expected - << "value=" << value; + if (patch->IsCall()) { + const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall(); + const DexFile::MethodId& id = cpatch->GetDexFile().GetMethodId(cpatch->GetTargetMethodIdx()); + uint32_t expected = reinterpret_cast<uint32_t>(&id); + uint32_t actual = *patch_location; + CHECK(actual == expected || actual == value) << std::hex + << "actual=" << actual + << "expected=" << expected + << "value=" << value; + } + if (patch->IsType()) { + const CompilerDriver::TypePatchInformation* tpatch = patch->AsType(); + const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx()); + uint32_t expected = reinterpret_cast<uint32_t>(&id); + uint32_t actual = *patch_location; + CHECK(actual == expected || actual == value) << std::hex + << "actual=" << actual + << "expected=" << expected + << "value=" << value; + } } *patch_location = value; oat_header.UpdateChecksum(patch_location, sizeof(value)); diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S index d32f998336..4fdcb35930 100644 --- a/runtime/arch/quick_alloc_entrypoints.S +++ b/runtime/arch/quick_alloc_entrypoints.S @@ -17,6 +17,10 @@ .macro GENERATE_ALLOC_ENTRYPOINTS c_suffix, cxx_suffix // Called by managed code to allocate an object. TWO_ARG_DOWNCALL art_quick_alloc_object\c_suffix, artAllocObjectFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +// Called by managed code to allocate an object of a resolved class. +TWO_ARG_DOWNCALL art_quick_alloc_object_resolved\c_suffix, artAllocObjectFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +// Called by managed code to allocate an object of an initialized class. +TWO_ARG_DOWNCALL art_quick_alloc_object_initialized\c_suffix, artAllocObjectFromCodeInitialized\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO // Called by managed code to allocate an object when the caller doesn't know whether it has access // to the created type. TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check\c_suffix, artAllocObjectFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO diff --git a/runtime/arch/quick_alloc_entrypoints.cc b/runtime/arch/quick_alloc_entrypoints.cc index 457c73a2be..0fad82266c 100644 --- a/runtime/arch/quick_alloc_entrypoints.cc +++ b/runtime/arch/quick_alloc_entrypoints.cc @@ -21,12 +21,16 @@ extern "C" void* art_quick_alloc_array##suffix(uint32_t, void*, int32_t); \ extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \ extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, void* method); \ +extern "C" void* art_quick_alloc_object_resolved##suffix(void* klass, void* method); \ +extern "C" void* art_quick_alloc_object_initialized##suffix(void* klass, void* method); \ extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, void* method); \ extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, void*, int32_t); \ extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \ extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \ extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \ extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, void* method); \ +extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(void* klass, void* method); \ +extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(void* klass, void* method); \ extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, void* method); \ extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \ extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \ @@ -35,6 +39,8 @@ void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrument qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \ qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix##_instrumented; \ qpoints->pAllocObject = art_quick_alloc_object##suffix##_instrumented; \ + qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \ + qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix##_instrumented; \ qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##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; \ @@ -42,6 +48,8 @@ void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrument qpoints->pAllocArray = art_quick_alloc_array##suffix; \ qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix; \ qpoints->pAllocObject = art_quick_alloc_object##suffix; \ + qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \ + qpoints->pAllocObjectInitialized = art_quick_alloc_object_initialized##suffix; \ qpoints->pAllocObjectWithAccessCheck = art_quick_alloc_object_with_access_check##suffix; \ qpoints->pCheckAndAllocArray = art_quick_check_and_alloc_array##suffix; \ qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix; \ diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 3adc46a51d..0e794d4bfe 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -405,6 +405,10 @@ END_MACRO // multi-line macros that use each other (hence using 1 macro per newline below). #define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(c_suffix, cxx_suffix) \ TWO_ARG_DOWNCALL art_quick_alloc_object ## c_suffix, artAllocObjectFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(c_suffix, cxx_suffix) \ + TWO_ARG_DOWNCALL art_quick_alloc_object_resolved ## c_suffix, artAllocObjectFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(c_suffix, cxx_suffix) \ + TWO_ARG_DOWNCALL art_quick_alloc_object_initialized ## c_suffix, artAllocObjectFromCodeInitialized ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO #define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \ TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check ## c_suffix, artAllocObjectFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO #define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(c_suffix, cxx_suffix) \ @@ -417,6 +421,8 @@ END_MACRO THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check ## c_suffix, artCheckAndAllocArrayFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_dlmalloc, DlMalloc) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc, DlMalloc) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc, DlMalloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc) @@ -424,6 +430,8 @@ 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_OBJECT(_dlmalloc_instrumented, DlMallocInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc_instrumented, DlMallocInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc_instrumented, DlMallocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented) @@ -431,6 +439,8 @@ GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallo GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc, RosAlloc) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc, RosAlloc) @@ -438,6 +448,8 @@ 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_OBJECT(_rosalloc_instrumented, RosAllocInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc_instrumented, RosAllocInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc_instrumented, RosAllocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc_instrumented, RosAllocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented) @@ -445,6 +457,8 @@ GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_rosalloc_instrumented, RosAllo GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_bump_pointer, BumpPointer) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_bump_pointer, BumpPointer) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer, BumpPointer) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer, BumpPointer) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer) @@ -452,6 +466,8 @@ 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_OBJECT(_bump_pointer_instrumented, BumpPointerInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_bump_pointer_instrumented, BumpPointerInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer_instrumented, BumpPointerInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer_instrumented, BumpPointerInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented) @@ -459,6 +475,8 @@ GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_bump_pointer_instrumented, Bum GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB) @@ -466,6 +484,8 @@ 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_OBJECT(_tlab_instrumented, TLABInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab_instrumented, TLABInstrumented) +GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab_instrumented, TLABInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab_instrumented, TLABInstrumented) GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented) diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 09be56e8a4..5ee750fa7f 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -74,21 +74,48 @@ ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx, } if (UNLIKELY(!klass->IsInitialized())) { SirtRef<mirror::Class> sirt_klass(self, klass); - // The class initializer might cause a GC. + // EnsureInitialized (the class initializer) might cause a GC. + // may cause us to suspend meaning that another thread may try to + // change the allocator while we are stuck in the entrypoints of + // an old allocator. Also, the class initialization may fail. To + // handle these cases we mark the slow path boolean as true so + // that the caller knows to check the allocator type to see if it + // has changed and to null-check the return value in case the + // initialization fails. + *slow_path = true; if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { DCHECK(self->IsExceptionPending()); return nullptr; // Failure } - // TODO: EnsureInitialized may cause us to suspend meaning that another thread may try to - // change the allocator while we are stuck in the entrypoints of an old allocator. To handle - // this case we mark the slow path boolean as true so that the caller knows to check the - // allocator type to see if it has changed. - *slow_path = true; return sirt_klass.get(); } return klass; } +// TODO: Fix no thread safety analysis when annotalysis is smarter. +ALWAYS_INLINE static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass, + Thread* self, bool* slow_path) + NO_THREAD_SAFETY_ANALYSIS { + if (UNLIKELY(!klass->IsInitialized())) { + SirtRef<mirror::Class> sirt_class(self, klass); + // EnsureInitialized (the class initializer) might cause a GC. + // may cause us to suspend meaning that another thread may try to + // change the allocator while we are stuck in the entrypoints of + // an old allocator. Also, the class initialization may fail. To + // handle these cases we mark the slow path boolean as true so + // that the caller knows to check the allocator type to see if it + // has changed and to null-check the return value in case the + // initialization fails. + *slow_path = true; + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_class, true, true)) { + DCHECK(self->IsExceptionPending()); + return nullptr; // Failure + } + return sirt_class.get(); + } + return klass; +} + // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it // cannot be resolved, throw an error. If it can, use it to create an instance. // When verification/compiler hasn't been able to verify access, optionally perform an access @@ -112,6 +139,40 @@ ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCode(uint32_t type_id return klass->Alloc<kInstrumented>(self, allocator_type); } +// Given the context of a calling Method and a resolved class, create an instance. +// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. +template <bool kInstrumented> +ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass, + mirror::ArtMethod* method, + Thread* self, + gc::AllocatorType allocator_type) + NO_THREAD_SAFETY_ANALYSIS { + DCHECK(klass != nullptr); + bool slow_path = false; + klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path); + if (UNLIKELY(slow_path)) { + if (klass == nullptr) { + return nullptr; + } + gc::Heap* heap = Runtime::Current()->GetHeap(); + return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator()); + } + return klass->Alloc<kInstrumented>(self, allocator_type); +} + +// Given the context of a calling Method and an initialized class, create an instance. +// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. +template <bool kInstrumented> +ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass, + mirror::ArtMethod* method, + Thread* self, + gc::AllocatorType allocator_type) + NO_THREAD_SAFETY_ANALYSIS { + DCHECK(klass != nullptr); + return klass->Alloc<kInstrumented>(self, allocator_type); +} + + // TODO: Fix no thread safety analysis when GCC can handle template specialization. template <bool kAccessCheck> ALWAYS_INLINE static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx, @@ -316,8 +377,10 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror: } mirror::Class* methods_class = resolved_method->GetDeclaringClass(); mirror::Class* referring_class = referrer->GetDeclaringClass(); - if (!referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method, - method_idx)) { + bool can_access_resolved_method = + referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method, + method_idx); + if (UNLIKELY(!can_access_resolved_method)) { DCHECK(self->IsExceptionPending()); // Throw exception and unwind. return nullptr; // Failure. } diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index b1dca774eb..5657092d8d 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -30,6 +30,18 @@ extern "C" mirror::Object* artAllocObjectFromCode ##suffix##suffix2( \ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \ return AllocObjectFromCode<false, instrumented_bool>(type_idx, method, self, allocator_type); \ } \ +extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \ + mirror::Class* klass, mirror::ArtMethod* method, Thread* self, mirror::ArtMethod** sp) \ + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \ + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \ + return AllocObjectFromCodeResolved<instrumented_bool>(klass, method, self, allocator_type); \ +} \ +extern "C" mirror::Object* artAllocObjectFromCodeInitialized##suffix##suffix2( \ + mirror::Class* klass, mirror::ArtMethod* method, Thread* self, mirror::ArtMethod** sp) \ + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \ + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \ + return AllocObjectFromCodeInitialized<instrumented_bool>(klass, method, self, allocator_type); \ +} \ extern "C" mirror::Object* artAllocObjectFromCodeWithAccessCheck##suffix##suffix2( \ uint32_t type_idx, mirror::ArtMethod* method, Thread* self, mirror::ArtMethod** sp) \ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \ diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index 1ba206629e..bbbc8f24e0 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -42,6 +42,8 @@ struct PACKED(4) QuickEntryPoints { void* (*pAllocArray)(uint32_t, void*, int32_t); void* (*pAllocArrayWithAccessCheck)(uint32_t, void*, int32_t); void* (*pAllocObject)(uint32_t, void*); + void* (*pAllocObjectResolved)(void*, void*); + void* (*pAllocObjectInitialized)(void*, void*); void* (*pAllocObjectWithAccessCheck)(uint32_t, void*); void* (*pCheckAndAllocArray)(uint32_t, void*, int32_t); void* (*pCheckAndAllocArrayWithAccessCheck)(uint32_t, void*, int32_t); diff --git a/runtime/globals.h b/runtime/globals.h index a0d7e48823..b1ccbdcea2 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -88,6 +88,10 @@ static constexpr bool kMovingFields = false; // True if we allow moving methods. static constexpr bool kMovingMethods = false; +// If true, the quick compiler embeds class pointers in the compiled +// code, if possible. +static constexpr bool kEmbedClassInCode = true; + } // namespace art #endif // ART_RUNTIME_GLOBALS_H_ diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 90bfc9be62..25912247b3 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -594,7 +594,7 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b for (const std::string& gc_option : gc_options) { gc::CollectorType collector_type = ParseCollectorType(gc_option); if (collector_type != gc::kCollectorTypeNone) { - parsed->collector_type_ = gc::kCollectorTypeGSS; + parsed->collector_type_ = collector_type; } else if (gc_option == "preverify") { parsed->verify_pre_gc_heap_ = true; } else if (gc_option == "nopreverify") { diff --git a/runtime/thread.cc b/runtime/thread.cc index 621e350e7c..e7fd660ae8 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1626,6 +1626,8 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { QUICK_ENTRY_POINT_INFO(pAllocArray), QUICK_ENTRY_POINT_INFO(pAllocArrayWithAccessCheck), QUICK_ENTRY_POINT_INFO(pAllocObject), + QUICK_ENTRY_POINT_INFO(pAllocObjectResolved), + QUICK_ENTRY_POINT_INFO(pAllocObjectInitialized), QUICK_ENTRY_POINT_INFO(pAllocObjectWithAccessCheck), QUICK_ENTRY_POINT_INFO(pCheckAndAllocArray), QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayWithAccessCheck), |