diff options
216 files changed, 4850 insertions, 2924 deletions
diff --git a/compiler/buffered_output_stream.cc b/compiler/buffered_output_stream.cc index 81a58f6284..0940a80cc1 100644 --- a/compiler/buffered_output_stream.cc +++ b/compiler/buffered_output_stream.cc @@ -23,7 +23,7 @@ namespace art { BufferedOutputStream::BufferedOutputStream(OutputStream* out) : OutputStream(out->GetLocation()), out_(out), used_(0) {} -bool BufferedOutputStream::WriteFully(const void* buffer, int64_t byte_count) { +bool BufferedOutputStream::WriteFully(const void* buffer, size_t byte_count) { if (byte_count > kBufferSize) { Flush(); return out_->WriteFully(buffer, byte_count); diff --git a/compiler/buffered_output_stream.h b/compiler/buffered_output_stream.h index 7d874fbc5c..75a3f24c70 100644 --- a/compiler/buffered_output_stream.h +++ b/compiler/buffered_output_stream.h @@ -31,7 +31,7 @@ class BufferedOutputStream : public OutputStream { delete out_; } - virtual bool WriteFully(const void* buffer, int64_t byte_count); + virtual bool WriteFully(const void* buffer, size_t byte_count); virtual off_t Seek(off_t offset, Whence whence); diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 29ff390678..f6d724ab56 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -20,14 +20,16 @@ namespace art { CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, - const std::vector<uint8_t>& code) - : compiler_driver_(compiler_driver), instruction_set_(instruction_set), code_(nullptr) { - SetCode(code); + const std::vector<uint8_t>& quick_code) + : compiler_driver_(compiler_driver), instruction_set_(instruction_set), + portable_code_(nullptr), quick_code_(nullptr) { + SetCode(&quick_code, nullptr); } CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, const std::string& elf_object, const std::string& symbol) - : compiler_driver_(compiler_driver), instruction_set_(instruction_set), symbol_(symbol) { + : compiler_driver_(compiler_driver), instruction_set_(instruction_set), + portable_code_(nullptr), quick_code_(nullptr), symbol_(symbol) { CHECK_NE(elf_object.size(), 0U); CHECK_NE(symbol.size(), 0U); std::vector<uint8_t> temp_code(elf_object.size()); @@ -38,12 +40,41 @@ CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instr // change to have different kinds of compiled methods. This is // being deferred until we work on hybrid execution or at least // until we work on batch compilation. - SetCode(temp_code); + SetCode(nullptr, &temp_code); } -void CompiledCode::SetCode(const std::vector<uint8_t>& code) { - CHECK(!code.empty()); - code_ = compiler_driver_->DeduplicateCode(code); +void CompiledCode::SetCode(const std::vector<uint8_t>* quick_code, + const std::vector<uint8_t>* portable_code) { + if (portable_code != nullptr) { + CHECK(!portable_code->empty()); + portable_code_ = compiler_driver_->DeduplicateCode(*portable_code); + } + if (quick_code != nullptr) { + CHECK(!quick_code->empty()); + quick_code_ = compiler_driver_->DeduplicateCode(*quick_code); + } +} + +bool CompiledCode::operator==(const CompiledCode& rhs) const { + if (quick_code_ != nullptr) { + if (rhs.quick_code_ == nullptr) { + return false; + } else if (quick_code_->size() != rhs.quick_code_->size()) { + return false; + } else { + return std::equal(quick_code_->begin(), quick_code_->end(), rhs.quick_code_->begin()); + } + } else if (portable_code_ != nullptr) { + if (rhs.portable_code_ == nullptr) { + return false; + } else if (portable_code_->size() != rhs.portable_code_->size()) { + return false; + } else { + return std::equal(portable_code_->begin(), portable_code_->end(), + rhs.portable_code_->begin()); + } + } + return (rhs.quick_code_ == nullptr) && (rhs.portable_code_ == nullptr); } uint32_t CompiledCode::AlignCode(uint32_t offset) const { @@ -100,7 +131,6 @@ const void* CompiledCode::CodePointer(const void* code_pointer, } } -#if defined(ART_USE_PORTABLE_COMPILER) const std::string& CompiledCode::GetSymbol() const { CHECK_NE(0U, symbol_.size()); return symbol_; @@ -114,18 +144,17 @@ const std::vector<uint32_t>& CompiledCode::GetOatdataOffsetsToCompliledCodeOffse void CompiledCode::AddOatdataOffsetToCompliledCodeOffset(uint32_t offset) { oatdata_offsets_to_compiled_code_offset_.push_back(offset); } -#endif CompiledMethod::CompiledMethod(CompilerDriver& driver, InstructionSet instruction_set, - const std::vector<uint8_t>& code, + const std::vector<uint8_t>& quick_code, const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const std::vector<uint8_t>& mapping_table, const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map) - : CompiledCode(&driver, instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes), + : CompiledCode(&driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), mapping_table_(driver.DeduplicateMappingTable(mapping_table)), vmap_table_(driver.DeduplicateVMapTable(vmap_table)), diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index e4fedf1ab4..611230509a 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -36,7 +36,7 @@ class CompiledCode { public: // For Quick to supply an code blob CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, - const std::vector<uint8_t>& code); + const std::vector<uint8_t>& quick_code); // For Portable to supply an ELF object CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, @@ -46,16 +46,18 @@ class CompiledCode { return instruction_set_; } - const std::vector<uint8_t>& GetCode() const { - return *code_; + const std::vector<uint8_t>* GetPortableCode() const { + return portable_code_; } - void SetCode(const std::vector<uint8_t>& code); - - bool operator==(const CompiledCode& rhs) const { - return (code_ == rhs.code_); + const std::vector<uint8_t>* GetQuickCode() const { + return quick_code_; } + void SetCode(const std::vector<uint8_t>* quick_code, const std::vector<uint8_t>* portable_code); + + bool operator==(const CompiledCode& rhs) const; + // To align an offset from a page-aligned value to make it suitable // for code storage. For example on ARM, to ensure that PC relative // valu computations work out as expected. @@ -72,19 +74,20 @@ class CompiledCode { static const void* CodePointer(const void* code_pointer, InstructionSet instruction_set); -#if defined(ART_USE_PORTABLE_COMPILER) const std::string& GetSymbol() const; const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const; void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset); -#endif private: - CompilerDriver* compiler_driver_; + CompilerDriver* const compiler_driver_; const InstructionSet instruction_set_; - // Used to store the PIC code for Quick and an ELF image for portable. - std::vector<uint8_t>* code_; + // The ELF image for portable. + std::vector<uint8_t>* portable_code_; + + // Used to store the PIC code for Quick. + std::vector<uint8_t>* quick_code_; // Used for the Portable ELF symbol name. const std::string symbol_; @@ -101,7 +104,7 @@ class CompiledMethod : public CompiledCode { // Constructs a CompiledMethod for the non-LLVM compilers. CompiledMethod(CompilerDriver& driver, InstructionSet instruction_set, - const std::vector<uint8_t>& code, + const std::vector<uint8_t>& quick_code, const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, @@ -109,10 +112,10 @@ class CompiledMethod : public CompiledCode { const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map); - // Constructs a CompiledMethod for the JniCompiler. + // Constructs a CompiledMethod for the QuickJniCompiler. CompiledMethod(CompilerDriver& driver, InstructionSet instruction_set, - const std::vector<uint8_t>& code, + const std::vector<uint8_t>& quick_code, const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask); diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc index 132831c3ef..8d24439277 100644 --- a/compiler/dex/arena_allocator.cc +++ b/compiler/dex/arena_allocator.cc @@ -52,7 +52,8 @@ Arena::Arena(size_t size) next_(nullptr) { if (kUseMemMap) { std::string error_msg; - map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, &error_msg); + map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, false, + &error_msg); CHECK(map_ != nullptr) << error_msg; memory_ = map_->Begin(); size_ = map_->Size(); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 6382dd6608..6aaad6694c 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -453,7 +453,7 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, if (cu->instruction_set != kX86) { if (direct_code == 0) { cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(), cg->TargetReg(kInvokeTgt)); } break; @@ -506,7 +506,7 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt] if (cu->instruction_set != kX86) { cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(), cg->TargetReg(kInvokeTgt)); break; } @@ -561,7 +561,7 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, case 5: // Get the compiled code address [use kArg0, set kInvokeTgt] if (cu->instruction_set != kX86) { cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(), cg->TargetReg(kInvokeTgt)); break; } @@ -1437,7 +1437,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) { } else { if (fast_path) { call_inst = OpMem(kOpBlx, TargetReg(kArg0), - mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value()); + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); } else { ThreadOffset trampoline(-1); switch (info->type) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 37b668f455..9f48351645 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -556,12 +556,15 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel( } } -void CompilerDriver::CompileOne(const mirror::ArtMethod* method, TimingLogger& timings) { +void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings) { DCHECK(!Runtime::Current()->IsStarted()); Thread* self = Thread::Current(); jobject jclass_loader; const DexFile* dex_file; uint16_t class_def_idx; + uint32_t method_idx = method->GetDexMethodIndex(); + uint32_t access_flags = method->GetAccessFlags(); + InvokeType invoke_type = method->GetInvokeType(); { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef<jobject> @@ -573,6 +576,7 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, TimingLogger& t dex_file = &mh.GetDexFile(); class_def_idx = mh.GetClassDefIndex(); } + const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); self->TransitionFromRunnableToSuspended(kNative); std::vector<const DexFile*> dex_files; @@ -581,8 +585,6 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, TimingLogger& t UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U)); PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings); - uint32_t method_idx = method->GetDexMethodIndex(); - const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); // Can we run DEX-to-DEX compiler on this class ? DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { @@ -592,8 +594,8 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, TimingLogger& t soa.Decode<mirror::ClassLoader*>(jclass_loader)); dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, *dex_file, class_def); } - CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(), - class_def_idx, method_idx, jclass_loader, *dex_file, dex_to_dex_compilation_level); + CompileMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, jclass_loader, + *dex_file, dex_to_dex_compilation_level); self->GetJniEnv()->DeleteGlobalRef(jclass_loader); @@ -1009,7 +1011,7 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field, - *dex_cache, field_idx); + dex_cache.get(), field_idx); bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() && fields_class != referrer_class; if (access_ok && !is_write_to_final_from_wrong_class) { @@ -1056,7 +1058,7 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila return true; // fast path } else { bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field, - *dex_cache, field_idx); + dex_cache.get(), field_idx); bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal(); if (access_ok && !is_write_to_final_from_wrong_class) { // We have the resolved field, we must make it into a index for the referrer @@ -1198,13 +1200,23 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType CHECK(!method->IsAbstract()); *type = sharp_type; *direct_method = reinterpret_cast<uintptr_t>(method); - *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); + if (compiler_backend_ == kQuick) { + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()); + } else { + CHECK_EQ(compiler_backend_, kPortable); + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode()); + } target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); target_method->dex_method_index = method->GetDexMethodIndex(); } else if (!must_use_direct_pointers) { // Set the code and rely on the dex cache for the method. *type = sharp_type; - *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); + if (compiler_backend_ == kQuick) { + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()); + } else { + CHECK_EQ(compiler_backend_, kPortable); + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode()); + } } else { // Direct pointers were required but none were available. VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); @@ -1239,8 +1251,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); - if (referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, - *dex_cache, target_method->dex_method_index)) { + if (referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, dex_cache.get(), + target_method->dex_method_index)) { const bool enableFinalBasedSharpening = enable_devirtualization; // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index a8110e71d7..4307212256 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -106,8 +106,8 @@ class CompilerDriver { TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); - // Compile a single Method - void CompileOne(const mirror::ArtMethod* method, TimingLogger& timings) + // Compile a single Method. + void CompileOne(mirror::ArtMethod* method, TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); VerificationResults* GetVerificationResults() const { diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index a5eb94f0e9..0d0c204d0a 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -122,7 +122,11 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { EXPECT_TRUE(method != NULL) << "method_idx=" << i << " " << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) << " " << dex->GetMethodName(dex->GetMethodId(i)); - EXPECT_TRUE(method->GetEntryPointFromCompiledCode() != NULL) << "method_idx=" << i + EXPECT_TRUE(method->GetEntryPointFromQuickCompiledCode() != NULL) << "method_idx=" << i + << " " + << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) + << " " << dex->GetMethodName(dex->GetMethodId(i)); + EXPECT_TRUE(method->GetEntryPointFromPortableCompiledCode() != NULL) << "method_idx=" << i << " " << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) << " " << dex->GetMethodName(dex->GetMethodId(i)); diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc index c5712880c1..66c8da1dd8 100644 --- a/compiler/elf_fixup.cc +++ b/compiler/elf_fixup.cc @@ -177,7 +177,7 @@ bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) { if (elf_dyn_needs_fixup) { uint32_t d_ptr = elf_dyn.d_un.d_ptr; if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, d_ptr, d_ptr + base_address); } @@ -196,7 +196,7 @@ bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) { continue; } if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, sh.sh_addr, sh.sh_addr + base_address); } @@ -213,7 +213,7 @@ bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) { CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1)))) << elf_file.GetFile().GetPath() << " i=" << i; if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, ph.p_vaddr, ph.p_vaddr + base_address); } @@ -238,7 +238,7 @@ bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dyna ::llvm::ELF::Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i); if (symbol.st_value != 0) { if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, symbol.st_value, symbol.st_value + base_address); } @@ -255,7 +255,7 @@ bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) { for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) { llvm::ELF::Elf32_Rel& rel = elf_file.GetRel(sh, i); if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, rel.r_offset, rel.r_offset + base_address); } @@ -265,7 +265,7 @@ bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) { for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) { llvm::ELF::Elf32_Rela& rela = elf_file.GetRela(sh, i); if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08x", + LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR, elf_file.GetFile().GetPath().c_str(), i, rela.r_offset, rela.r_offset + base_address); } diff --git a/compiler/file_output_stream.cc b/compiler/file_output_stream.cc index 0e4a2949ed..3ee16f53e8 100644 --- a/compiler/file_output_stream.cc +++ b/compiler/file_output_stream.cc @@ -25,7 +25,7 @@ namespace art { FileOutputStream::FileOutputStream(File* file) : OutputStream(file->GetPath()), file_(file) {} -bool FileOutputStream::WriteFully(const void* buffer, int64_t byte_count) { +bool FileOutputStream::WriteFully(const void* buffer, size_t byte_count) { return file_->WriteFully(buffer, byte_count); } diff --git a/compiler/file_output_stream.h b/compiler/file_output_stream.h index bde9e68eaa..76b00fe129 100644 --- a/compiler/file_output_stream.h +++ b/compiler/file_output_stream.h @@ -29,7 +29,7 @@ class FileOutputStream : public OutputStream { virtual ~FileOutputStream() {} - virtual bool WriteFully(const void* buffer, int64_t byte_count); + virtual bool WriteFully(const void* buffer, size_t byte_count); virtual off_t Seek(off_t offset, Whence whence); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 09bb70cd2f..67cd51bc54 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -208,12 +208,12 @@ void ImageWriter::AssignImageOffset(mirror::Object* object) { DCHECK_LT(image_end_, image_->Size()); } -bool ImageWriter::IsImageOffsetAssigned(const mirror::Object* object) const { +bool ImageWriter::IsImageOffsetAssigned(mirror::Object* object) const { DCHECK(object != nullptr); return object->GetLockWord().GetState() == LockWord::kForwardingAddress; } -size_t ImageWriter::GetImageOffset(const mirror::Object* object) const { +size_t ImageWriter::GetImageOffset(mirror::Object* object) const { DCHECK(object != nullptr); DCHECK(IsImageOffsetAssigned(object)); LockWord lock_word = object->GetLockWord(); @@ -226,7 +226,7 @@ bool ImageWriter::AllocMemory() { size_t length = RoundUp(Runtime::Current()->GetHeap()->GetTotalMemory(), kPageSize); std::string error_msg; image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, PROT_READ | PROT_WRITE, - &error_msg)); + true, &error_msg)); if (UNLIKELY(image_.get() == nullptr)) { LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg; return false; @@ -281,7 +281,7 @@ void ImageWriter::ComputeEagerResolvedStrings() SHARED_LOCKS_REQUIRED(Locks::mut Runtime::Current()->GetHeap()->VisitObjects(ComputeEagerResolvedStringsCallback, this); } -bool ImageWriter::IsImageClass(const Class* klass) { +bool ImageWriter::IsImageClass(Class* klass) { return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor()); } @@ -447,7 +447,7 @@ void ImageWriter::WalkInstanceFields(mirror::Object* obj, mirror::Class* klass) for (size_t i = 0; i < num_reference_fields; ++i) { mirror::ArtField* field = sirt_class->GetInstanceField(i); MemberOffset field_offset = field->GetOffset(); - mirror::Object* value = obj->GetFieldObject<mirror::Object*>(field_offset, false); + mirror::Object* value = obj->GetFieldObject<mirror::Object>(field_offset, false); if (value != nullptr) { WalkFieldsInOrder(value); } @@ -470,7 +470,7 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { for (size_t i = 0; i < num_static_fields; ++i) { mirror::ArtField* field = klass->GetStaticField(i); MemberOffset field_offset = field->GetOffset(); - mirror::Object* value = sirt_obj->GetFieldObject<mirror::Object*>(field_offset, false); + mirror::Object* value = sirt_obj->GetFieldObject<mirror::Object>(field_offset, false); if (value != nullptr) { WalkFieldsInOrder(value); } @@ -527,16 +527,16 @@ void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_d const size_t heap_bytes_per_bitmap_byte = kBitsPerByte * gc::accounting::SpaceBitmap::kAlignment; const size_t bitmap_bytes = RoundUp(image_end_, heap_bytes_per_bitmap_byte) / heap_bytes_per_bitmap_byte; - ImageHeader image_header(reinterpret_cast<uint32_t>(image_begin_), + ImageHeader image_header(PointerToLowMemUInt32(image_begin_), static_cast<uint32_t>(image_end_), RoundUp(image_end_, kPageSize), RoundUp(bitmap_bytes, kPageSize), - reinterpret_cast<uint32_t>(GetImageAddress(image_roots.get())), + PointerToLowMemUInt32(GetImageAddress(image_roots.get())), oat_file_->GetOatHeader().GetChecksum(), - reinterpret_cast<uint32_t>(oat_file_begin), - reinterpret_cast<uint32_t>(oat_data_begin_), - reinterpret_cast<uint32_t>(oat_data_end), - reinterpret_cast<uint32_t>(oat_file_end)); + PointerToLowMemUInt32(oat_file_begin), + PointerToLowMemUInt32(oat_data_begin_), + PointerToLowMemUInt32(oat_data_end), + PointerToLowMemUInt32(oat_file_end)); memcpy(image_->Begin(), &image_header, sizeof(image_header)); // Note that image_end_ is left at end of used space @@ -578,7 +578,7 @@ void ImageWriter::CopyAndFixupObjectsCallback(Object* obj, void* arg) { image_writer->FixupObject(obj, copy); } -void ImageWriter::FixupObject(const Object* orig, Object* copy) { +void ImageWriter::FixupObject(Object* orig, Object* copy) { DCHECK(orig != NULL); DCHECK(copy != NULL); copy->SetClass(down_cast<Class*>(GetImageAddress(orig->GetClass()))); @@ -594,12 +594,12 @@ void ImageWriter::FixupObject(const Object* orig, Object* copy) { } } -void ImageWriter::FixupClass(const Class* orig, Class* copy) { +void ImageWriter::FixupClass(Class* orig, Class* copy) { FixupInstanceFields(orig, copy); FixupStaticFields(orig, copy); } -void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { +void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) { FixupInstanceFields(orig, copy); // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to @@ -607,43 +607,36 @@ void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { // The resolution method has a special trampoline to call. if (UNLIKELY(orig == Runtime::Current()->GetResolutionMethod())) { -#if defined(ART_USE_PORTABLE_COMPILER) - copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); -#else - copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); -#endif + copy->SetEntryPointFromPortableCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); + copy->SetEntryPointFromQuickCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); } else if (UNLIKELY(orig == Runtime::Current()->GetImtConflictMethod())) { -#if defined(ART_USE_PORTABLE_COMPILER) - copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_imt_conflict_trampoline_offset_)); -#else - copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_imt_conflict_trampoline_offset_)); -#endif + copy->SetEntryPointFromPortableCompiledCode(GetOatAddress(portable_imt_conflict_trampoline_offset_)); + copy->SetEntryPointFromQuickCompiledCode(GetOatAddress(quick_imt_conflict_trampoline_offset_)); } else { // We assume all methods have code. If they don't currently then we set them to the use the // resolution trampoline. Abstract methods never have code and so we need to make sure their // use results in an AbstractMethodError. We use the interpreter to achieve this. if (UNLIKELY(orig->IsAbstract())) { -#if defined(ART_USE_PORTABLE_COMPILER) - copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_to_interpreter_bridge_offset_)); -#else - copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_to_interpreter_bridge_offset_)); -#endif + copy->SetEntryPointFromPortableCompiledCode(GetOatAddress(portable_to_interpreter_bridge_offset_)); + copy->SetEntryPointFromQuickCompiledCode(GetOatAddress(quick_to_interpreter_bridge_offset_)); copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*> - (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_)))); + (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_)))); } else { copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*> - (const_cast<byte*>(GetOatAddress(interpreter_to_compiled_code_bridge_offset_)))); + (const_cast<byte*>(GetOatAddress(interpreter_to_compiled_code_bridge_offset_)))); // Use original code if it exists. Otherwise, set the code pointer to the resolution // trampoline. - const byte* code = GetOatAddress(orig->GetOatCodeOffset()); - if (code != NULL) { - copy->SetEntryPointFromCompiledCode(code); + const byte* quick_code = GetOatAddress(orig->GetQuickOatCodeOffset()); + if (quick_code != nullptr) { + copy->SetEntryPointFromQuickCompiledCode(quick_code); } else { -#if defined(ART_USE_PORTABLE_COMPILER) - copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); -#else - copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); -#endif + copy->SetEntryPointFromQuickCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); + } + const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset()); + if (portable_code != nullptr) { + copy->SetEntryPointFromPortableCompiledCode(portable_code); + } else { + copy->SetEntryPointFromPortableCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); } if (orig->IsNative()) { // The native method's pointer is set to a stub to lookup via dlsym. @@ -667,14 +660,14 @@ void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { } } -void ImageWriter::FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy) { +void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) { for (int32_t i = 0; i < orig->GetLength(); ++i) { - const Object* element = orig->Get(i); - copy->SetPtrWithoutChecks(i, GetImageAddress(element)); + Object* element = orig->Get(i); + copy->SetWithoutChecksAndWriteBarrier(i, GetImageAddress(element)); } } -void ImageWriter::FixupInstanceFields(const Object* orig, Object* copy) { +void ImageWriter::FixupInstanceFields(Object* orig, Object* copy) { DCHECK(orig != NULL); DCHECK(copy != NULL); Class* klass = orig->GetClass(); @@ -682,13 +675,13 @@ void ImageWriter::FixupInstanceFields(const Object* orig, Object* copy) { FixupFields(orig, copy, klass->GetReferenceInstanceOffsets(), false); } -void ImageWriter::FixupStaticFields(const Class* orig, Class* copy) { +void ImageWriter::FixupStaticFields(Class* orig, Class* copy) { DCHECK(orig != NULL); DCHECK(copy != NULL); FixupFields(orig, copy, orig->GetReferenceStaticOffsets(), true); } -void ImageWriter::FixupFields(const Object* orig, +void ImageWriter::FixupFields(Object* orig, Object* copy, uint32_t ref_offsets, bool is_static) { @@ -697,9 +690,10 @@ void ImageWriter::FixupFields(const Object* orig, while (ref_offsets != 0) { size_t right_shift = CLZ(ref_offsets); MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift); - const Object* ref = orig->GetFieldObject<const Object*>(byte_offset, false); - // Use SetFieldPtr to avoid card marking since we are writing to the image. - copy->SetFieldPtr(byte_offset, GetImageAddress(ref), false); + Object* ref = orig->GetFieldObject<Object>(byte_offset, false); + // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the + // image. + copy->SetFieldObjectWithoutWriteBarrier(byte_offset, GetImageAddress(ref), false); ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift); } } else { @@ -707,7 +701,7 @@ void ImageWriter::FixupFields(const Object* orig, // walk up the class inheritance hierarchy and find reference // offsets the hard way. In the static case, just consider this // class. - for (const Class *klass = is_static ? orig->AsClass() : orig->GetClass(); + for (Class *klass = is_static ? orig->AsClass() : orig->GetClass(); klass != NULL; klass = is_static ? NULL : klass->GetSuperClass()) { size_t num_reference_fields = (is_static @@ -718,9 +712,10 @@ void ImageWriter::FixupFields(const Object* orig, ? klass->GetStaticField(i) : klass->GetInstanceField(i)); MemberOffset field_offset = field->GetOffset(); - const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false); - // Use SetFieldPtr to avoid card marking since we are writing to the image. - copy->SetFieldPtr(field_offset, GetImageAddress(ref), false); + Object* ref = orig->GetFieldObject<Object>(field_offset, false); + // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the + // image. + copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false); } } } @@ -728,9 +723,10 @@ void ImageWriter::FixupFields(const Object* orig, // Fix-up referent, that isn't marked as an object field, for References. ArtField* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;"); MemberOffset field_offset = field->GetOffset(); - const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false); - // Use SetFieldPtr to avoid card marking since we are writing to the image. - copy->SetFieldPtr(field_offset, GetImageAddress(ref), false); + Object* ref = orig->GetFieldObject<Object>(field_offset, false); + // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the + // image. + copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false); } } @@ -786,17 +782,17 @@ void ImageWriter::PatchOatCodeAndMethods() { for (size_t i = 0; i < code_to_patch.size(); 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()); - uint32_t code_offset = code - code_base; - SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset))); + uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target)); + uintptr_t code_base = reinterpret_cast<uintptr_t>(&oat_file_->GetOatHeader()); + uintptr_t code_offset = quick_code - code_base; + SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset))); } const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); for (size_t i = 0; i < methods_to_patch.size(); i++) { const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i]; ArtMethod* target = GetTargetMethod(patch); - SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); + SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target))); } const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch = @@ -804,7 +800,7 @@ void ImageWriter::PatchOatCodeAndMethods() { 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))); + SetPatchLocation(patch, PointerToLowMemUInt32(GetImageAddress(target))); } // Update the image header with the new checksum after patching @@ -815,18 +811,18 @@ void ImageWriter::PatchOatCodeAndMethods() { void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - const void* oat_code = class_linker->GetOatCodeFor(patch->GetDexFile(), - patch->GetReferrerClassDefIdx(), - patch->GetReferrerMethodIdx()); + const void* quick_oat_code = class_linker->GetQuickOatCodeFor(patch->GetDexFile(), + patch->GetReferrerClassDefIdx(), + patch->GetReferrerMethodIdx()); OatHeader& oat_header = const_cast<OatHeader&>(oat_file_->GetOatHeader()); // TODO: make this Thumb2 specific - uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(oat_code) & ~0x1); + uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(quick_oat_code) & ~0x1); uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset()); if (kIsDebugBuild) { 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); + uintptr_t expected = reinterpret_cast<uintptr_t>(&id); uint32_t actual = *patch_location; CHECK(actual == expected || actual == value) << std::hex << "actual=" << actual @@ -836,7 +832,7 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch 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); + uintptr_t expected = reinterpret_cast<uintptr_t>(&id); uint32_t actual = *patch_location; CHECK(actual == expected || actual == value) << std::hex << "actual=" << actual diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 695f59b40e..a1504eeca8 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -66,17 +66,17 @@ class ImageWriter { void AssignImageOffset(mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetImageOffset(mirror::Object* object, size_t offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsImageOffsetAssigned(const mirror::Object* object) const; - size_t GetImageOffset(const mirror::Object* object) const; + bool IsImageOffsetAssigned(mirror::Object* object) const; + size_t GetImageOffset(mirror::Object* object) const; - mirror::Object* GetImageAddress(const mirror::Object* object) const { + mirror::Object* GetImageAddress(mirror::Object* object) const { if (object == NULL) { return NULL; } return reinterpret_cast<mirror::Object*>(image_begin_ + GetImageOffset(object)); } - mirror::Object* GetLocalAddress(const mirror::Object* object) const { + mirror::Object* GetLocalAddress(mirror::Object* object) const { size_t offset = GetImageOffset(object); byte* dst = image_->Begin() + offset; return reinterpret_cast<mirror::Object*>(dst); @@ -96,7 +96,7 @@ class ImageWriter { } // Returns true if the class was in the original requested image classes list. - bool IsImageClass(const mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsImageClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Debug aid that list of requested image classes. void DumpImageClasses(); @@ -141,20 +141,20 @@ class ImageWriter { void CopyAndFixupObjects(); static void CopyAndFixupObjectsCallback(mirror::Object* obj, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupClass(const mirror::Class* orig, mirror::Class* copy) + void FixupClass(mirror::Class* orig, mirror::Class* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupMethod(const mirror::ArtMethod* orig, mirror::ArtMethod* copy) + void FixupMethod(mirror::ArtMethod* orig, mirror::ArtMethod* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupObject(const mirror::Object* orig, mirror::Object* copy) + void FixupObject(mirror::Object* orig, mirror::Object* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupObjectArray(const mirror::ObjectArray<mirror::Object>* orig, + void FixupObjectArray(mirror::ObjectArray<mirror::Object>* orig, mirror::ObjectArray<mirror::Object>* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupInstanceFields(const mirror::Object* orig, mirror::Object* copy) + void FixupInstanceFields(mirror::Object* orig, mirror::Object* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupStaticFields(const mirror::Class* orig, mirror::Class* copy) + void FixupStaticFields(mirror::Class* orig, mirror::Class* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupFields(const mirror::Object* orig, mirror::Object* copy, uint32_t ref_offsets, + void FixupFields(mirror::Object* orig, mirror::Object* copy, uint32_t ref_offsets, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 1c8714a6c3..c77d319330 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -58,11 +58,14 @@ class JniCompilerTest : public CommonTest { method = c->FindVirtualMethod(method_name, method_sig); } ASSERT_TRUE(method != NULL) << method_name << " " << method_sig; - if (method->GetEntryPointFromCompiledCode() != NULL) { - return; + if (method->GetEntryPointFromQuickCompiledCode() == nullptr) { + ASSERT_TRUE(method->GetEntryPointFromPortableCompiledCode() == nullptr); + CompileMethod(method); + ASSERT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr) + << method_name << " " << method_sig; + ASSERT_TRUE(method->GetEntryPointFromPortableCompiledCode() != nullptr) + << method_name << " " << method_sig; } - CompileMethod(method); - ASSERT_TRUE(method->GetEntryPointFromCompiledCode() != NULL) << method_name << " " << method_sig; } void SetUpForTest(bool direct, const char* method_name, const char* method_sig, @@ -122,19 +125,19 @@ jobject JniCompilerTest::class_loader_; int gJava_MyClassNatives_foo_calls = 0; void Java_MyClassNatives_foo(JNIEnv* env, jobject thisObj) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); Locks::mutator_lock_->AssertNotHeld(Thread::Current()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_foo_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); } TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) { TEST_DISABLED_FOR_PORTABLE(); - SetUpForTest(false, "foo", "()V", - reinterpret_cast<void*>(&Java_MyClassNatives_foo)); + SetUpForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClassNatives_foo)); EXPECT_EQ(0, gJava_MyClassNatives_foo_calls); env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_); @@ -178,12 +181,13 @@ TEST_F(JniCompilerTest, CompileAndRunStaticIntMethodThroughStub) { int gJava_MyClassNatives_fooI_calls = 0; jint Java_MyClassNatives_fooI(JNIEnv* env, jobject thisObj, jint x) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooI_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x; } @@ -204,12 +208,13 @@ TEST_F(JniCompilerTest, CompileAndRunIntMethod) { int gJava_MyClassNatives_fooII_calls = 0; jint Java_MyClassNatives_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooII_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x - y; // non-commutative operator } @@ -231,12 +236,13 @@ TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) { int gJava_MyClassNatives_fooJJ_calls = 0; jlong Java_MyClassNatives_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooJJ_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x - y; // non-commutative operator } @@ -259,12 +265,13 @@ TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) { int gJava_MyClassNatives_fooDD_calls = 0; jdouble Java_MyClassNatives_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooDD_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x - y; // non-commutative operator } @@ -288,12 +295,13 @@ TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) { int gJava_MyClassNatives_fooJJ_synchronized_calls = 0; jlong Java_MyClassNatives_fooJJ_synchronized(JNIEnv* env, jobject thisObj, jlong x, jlong y) { // 1 = thisObj - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooJJ_synchronized_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x | y; } @@ -314,12 +322,13 @@ int gJava_MyClassNatives_fooIOO_calls = 0; jobject Java_MyClassNatives_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject y, jobject z) { // 3 = this + y + z - EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_)); gJava_MyClassNatives_fooIOO_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); switch (x) { case 1: return y; @@ -365,12 +374,13 @@ TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) { int gJava_MyClassNatives_fooSII_calls = 0; jint Java_MyClassNatives_fooSII(JNIEnv* env, jclass klass, jint x, jint y) { // 1 = klass - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass)); gJava_MyClassNatives_fooSII_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x + y; } @@ -388,12 +398,13 @@ TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) { int gJava_MyClassNatives_fooSDD_calls = 0; jdouble Java_MyClassNatives_fooSDD(JNIEnv* env, jclass klass, jdouble x, jdouble y) { // 1 = klass - EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass)); gJava_MyClassNatives_fooSDD_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(1U, Thread::Current()->NumStackReferences()); return x - y; // non-commutative operator } @@ -417,12 +428,13 @@ int gJava_MyClassNatives_fooSIOO_calls = 0; jobject Java_MyClassNatives_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y, jobject z) { // 3 = klass + y + z - EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass)); gJava_MyClassNatives_fooSIOO_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); switch (x) { case 1: return y; @@ -469,12 +481,13 @@ TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) { int gJava_MyClassNatives_fooSSIOO_calls = 0; jobject Java_MyClassNatives_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject y, jobject z) { // 3 = klass + y + z - EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); EXPECT_EQ(kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass)); gJava_MyClassNatives_fooSSIOO_calls++; + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ(3U, Thread::Current()->NumStackReferences()); switch (x) { case 1: return y; diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 94408bb39c..6563eb5475 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -126,7 +126,7 @@ LlvmCompilationUnit* CompilerLLVM::AllocateCompilationUnit() { MutexLock GUARD(Thread::Current(), next_cunit_id_lock_); LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, next_cunit_id_++); if (!bitcode_filename_.empty()) { - cunit->SetBitcodeFileName(StringPrintf("%s-%zu", + cunit->SetBitcodeFileName(StringPrintf("%s-%u", bitcode_filename_.c_str(), cunit->GetCompilationUnitId())); } diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index 6423cd7dca..8f22a97968 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -897,7 +897,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { } else { code_addr = irb_.LoadFromObjectOffset(callee_method_object_addr, - art::mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value(), func_type->getPointerTo(), kTBAARuntimeInfo); } @@ -1234,7 +1234,7 @@ llvm::Value* GBCExpanderPass::Expand_Invoke(llvm::CallInst& call_inst) { llvm::Value* code_addr = irb_.LoadFromObjectOffset(callee_method_object_addr, - art::mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value(), callee_method_type->getPointerTo(), kTBAARuntimeInfo); diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc index 038f5dc4eb..d23706d9f4 100644 --- a/compiler/llvm/llvm_compilation_unit.cc +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -151,7 +151,7 @@ static std::string DumpDirectory() { void LlvmCompilationUnit::DumpBitcodeToFile() { std::string bitcode; DumpBitcodeToString(bitcode); - std::string filename(StringPrintf("%s/Art%u.bc", DumpDirectory().c_str(), cunit_id_)); + std::string filename(StringPrintf("%s/Art%zu.bc", DumpDirectory().c_str(), cunit_id_)); UniquePtr<File> output(OS::CreateEmptyFile(filename.c_str())); output->WriteFully(bitcode.data(), bitcode.size()); LOG(INFO) << ".bc file written successfully: " << filename; @@ -178,7 +178,7 @@ bool LlvmCompilationUnit::Materialize() { const bool kDumpELF = false; if (kDumpELF) { // Dump the ELF image for debugging - std::string filename(StringPrintf("%s/Art%u.o", DumpDirectory().c_str(), cunit_id_)); + std::string filename(StringPrintf("%s/Art%zu.o", DumpDirectory().c_str(), cunit_id_)); UniquePtr<File> output(OS::CreateEmptyFile(filename.c_str())); output->WriteFully(elf_object_.data(), elf_object_.size()); LOG(INFO) << ".o file written successfully: " << filename; diff --git a/compiler/llvm/llvm_compilation_unit.h b/compiler/llvm/llvm_compilation_unit.h index ced9f812c0..58aa6fd545 100644 --- a/compiler/llvm/llvm_compilation_unit.h +++ b/compiler/llvm/llvm_compilation_unit.h @@ -101,10 +101,10 @@ class LlvmCompilationUnit { private: LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, - uint32_t cunit_id); + size_t cunit_id); const CompilerLLVM* compiler_llvm_; - const uint32_t cunit_id_; + const size_t cunit_id_; UniquePtr< ::llvm::LLVMContext> context_; UniquePtr<IRBuilder> irb_; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index fc454127c3..b3070b6f48 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -39,29 +39,42 @@ class OatTest : public CommonTest { method->GetDexMethodIndex())); if (compiled_method == NULL) { - EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " - << oat_method.GetCode(); -#if !defined(ART_USE_PORTABLE_COMPILER) - EXPECT_EQ(oat_method.GetFrameSizeInBytes(), kCompile ? kStackAlignment : 0); + EXPECT_TRUE(oat_method.GetQuickCode() == NULL) << PrettyMethod(method) << " " + << oat_method.GetQuickCode(); + EXPECT_TRUE(oat_method.GetPortableCode() == NULL) << PrettyMethod(method) << " " + << oat_method.GetPortableCode(); + EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U); EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U); EXPECT_EQ(oat_method.GetFpSpillMask(), 0U); -#endif } else { - const void* oat_code = oat_method.GetCode(); - EXPECT_TRUE(oat_code != NULL) << PrettyMethod(method); - uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2); - oat_code = reinterpret_cast<const void*>(oat_code_aligned); - - const std::vector<uint8_t>& code = compiled_method->GetCode(); - size_t code_size = code.size() * sizeof(code[0]); - EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size)) - << PrettyMethod(method) << " " << code_size; - CHECK_EQ(0, memcmp(oat_code, &code[0], code_size)); -#if !defined(ART_USE_PORTABLE_COMPILER) - EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes()); - EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask()); - EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask()); -#endif + const void* quick_oat_code = oat_method.GetQuickCode(); + if (quick_oat_code != nullptr) { + EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes()); + EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask()); + EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask()); + uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2); + quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned); + const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); + EXPECT_TRUE(quick_code != nullptr); + size_t code_size = quick_code->size() * sizeof(quick_code[0]); + EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size)) + << PrettyMethod(method) << " " << code_size; + CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size)); + } else { + const void* portable_oat_code = oat_method.GetPortableCode(); + EXPECT_TRUE(portable_oat_code != nullptr) << PrettyMethod(method); + EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U); + EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U); + EXPECT_EQ(oat_method.GetFpSpillMask(), 0U); + uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(portable_oat_code), 2); + portable_oat_code = reinterpret_cast<const void*>(oat_code_aligned); + const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode(); + EXPECT_TRUE(portable_code != nullptr); + size_t code_size = portable_code->size() * sizeof(portable_code[0]); + EXPECT_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size)) + << PrettyMethod(method) << " " << code_size; + CHECK_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size)); + } } } }; @@ -70,12 +83,8 @@ TEST_F(OatTest, WriteRead) { TimingLogger timings("CommonTest::WriteRead", false, false); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - // TODO: make selectable -#if defined(ART_USE_PORTABLE_COMPILER) - CompilerBackend compiler_backend = kPortable; -#else - CompilerBackend compiler_backend = kQuick; -#endif + // TODO: make selectable. + CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick; InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; InstructionSetFeatures insn_features; diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 7a902d86d6..7c5669a3ab 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -39,7 +39,7 @@ namespace art { OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_begin, + uintptr_t image_file_location_oat_begin, const std::string& image_file_location, const CompilerDriver* compiler, TimingLogger* timings) @@ -348,8 +348,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, bool __attribute__((unused)) is_native, InvokeType invoke_type, uint32_t method_idx, const DexFile& dex_file) { - // derived from CompiledMethod if available - uint32_t code_offset = 0; + // Derived from CompiledMethod if available. + uint32_t quick_code_offset = 0; uint32_t frame_size_in_bytes = kStackAlignment; uint32_t core_spill_mask = 0; uint32_t fp_spill_mask = 0; @@ -358,36 +358,38 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, uint32_t gc_map_offset = 0; OatClass* oat_class = oat_classes_[oat_class_index]; -#if defined(ART_USE_PORTABLE_COMPILER) - size_t oat_method_offsets_offset = - oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); -#endif - CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + if (compiled_method != NULL) { -#if defined(ART_USE_PORTABLE_COMPILER) - compiled_method->AddOatdataOffsetToCompliledCodeOffset( - oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); -#else - const std::vector<uint8_t>& code = compiled_method->GetCode(); - offset = compiled_method->AlignCode(offset); - DCHECK_ALIGNED(offset, kArmAlignment); - uint32_t code_size = code.size() * sizeof(code[0]); - CHECK_NE(code_size, 0U); - uint32_t thumb_offset = compiled_method->CodeDelta(); - code_offset = offset + sizeof(code_size) + thumb_offset; - - // Deduplicate code arrays - SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); - if (code_iter != code_offsets_.end()) { - code_offset = code_iter->second; + const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode(); + const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); + if (portable_code != nullptr) { + CHECK(quick_code == nullptr); + size_t oat_method_offsets_offset = + oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); + compiled_method->AddOatdataOffsetToCompliledCodeOffset( + oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); } else { - code_offsets_.Put(&code, code_offset); - offset += sizeof(code_size); // code size is prepended before code - offset += code_size; - oat_header_->UpdateChecksum(&code[0], code_size); + CHECK(quick_code != nullptr); + offset = compiled_method->AlignCode(offset); + DCHECK_ALIGNED(offset, kArmAlignment); + uint32_t code_size = quick_code->size() * sizeof(uint8_t); + CHECK_NE(code_size, 0U); + uint32_t thumb_offset = compiled_method->CodeDelta(); + quick_code_offset = offset + sizeof(code_size) + thumb_offset; + + // Deduplicate code arrays + SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = + code_offsets_.find(quick_code); + if (code_iter != code_offsets_.end()) { + quick_code_offset = code_iter->second; + } else { + code_offsets_.Put(quick_code, quick_code_offset); + offset += sizeof(code_size); // code size is prepended before code + offset += code_size; + oat_header_->UpdateChecksum(&(*quick_code)[0], code_size); + } } -#endif frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); core_spill_mask = compiled_method->GetCoreSpillMask(); fp_spill_mask = compiled_method->GetFpSpillMask(); @@ -456,7 +458,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, } oat_class->method_offsets_[*method_offsets_index] = - OatMethodOffsets(code_offset, + OatMethodOffsets(quick_code_offset, frame_size_in_bytes, core_spill_mask, fp_spill_mask, @@ -483,9 +485,11 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, // Don't overwrite static method trampoline if (!method->IsStatic() || method->IsConstructor() || method->GetDeclaringClass()->IsInitialized()) { - method->SetOatCodeOffset(code_offset); + // TODO: record portable code offsets: method->SetPortableOatCodeOffset(portable_code_offset); + method->SetQuickOatCodeOffset(quick_code_offset); } else { - method->SetEntryPointFromCompiledCode(NULL); + method->SetEntryPointFromPortableCompiledCode(nullptr); + method->SetEntryPointFromQuickCompiledCode(nullptr); } method->SetOatVmapTableOffset(vmap_table_offset); method->SetOatNativeGcMapOffset(gc_map_offset); @@ -753,52 +757,52 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset, if (compiled_method != NULL) { // ie. not an abstract method const OatMethodOffsets method_offsets = oat_class->method_offsets_[*method_offsets_index]; (*method_offsets_index)++; - -#if !defined(ART_USE_PORTABLE_COMPILER) - uint32_t aligned_offset = compiled_method->AlignCode(relative_offset); - uint32_t aligned_code_delta = aligned_offset - relative_offset; - if (aligned_code_delta != 0) { - off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); - size_code_alignment_ += aligned_code_delta; - uint32_t expected_offset = file_offset + aligned_offset; - if (static_cast<uint32_t>(new_offset) != expected_offset) { - PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset - << " Expected: " << expected_offset << " File: " << out.GetLocation(); - return 0; + const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); + if (quick_code != nullptr) { + CHECK(compiled_method->GetPortableCode() == nullptr); + uint32_t aligned_offset = compiled_method->AlignCode(relative_offset); + uint32_t aligned_code_delta = aligned_offset - relative_offset; + if (aligned_code_delta != 0) { + off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); + size_code_alignment_ += aligned_code_delta; + uint32_t expected_offset = file_offset + aligned_offset; + if (static_cast<uint32_t>(new_offset) != expected_offset) { + PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset + << " Expected: " << expected_offset << " File: " << out.GetLocation(); + return 0; + } + relative_offset += aligned_code_delta; + DCHECK_OFFSET(); } - relative_offset += aligned_code_delta; - DCHECK_OFFSET(); - } - DCHECK_ALIGNED(relative_offset, kArmAlignment); - const std::vector<uint8_t>& code = compiled_method->GetCode(); - uint32_t code_size = code.size() * sizeof(code[0]); - CHECK_NE(code_size, 0U); - - // Deduplicate code arrays - size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta(); - SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); - if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) { - DCHECK(code_iter->second == method_offsets.code_offset_) - << PrettyMethod(method_idx, dex_file); - } else { - DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); - if (!out.WriteFully(&code_size, sizeof(code_size))) { - ReportWriteFailure("method code size", method_idx, dex_file, out); - return 0; + DCHECK_ALIGNED(relative_offset, kArmAlignment); + uint32_t code_size = quick_code->size() * sizeof(uint8_t); + CHECK_NE(code_size, 0U); + + // Deduplicate code arrays + size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta(); + SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = + code_offsets_.find(quick_code); + if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) { + DCHECK(code_iter->second == method_offsets.code_offset_) + << PrettyMethod(method_idx, dex_file); + } else { + DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); + if (!out.WriteFully(&code_size, sizeof(code_size))) { + ReportWriteFailure("method code size", method_idx, dex_file, out); + return 0; + } + size_code_size_ += sizeof(code_size); + relative_offset += sizeof(code_size); + DCHECK_OFFSET(); + if (!out.WriteFully(&(*quick_code)[0], code_size)) { + ReportWriteFailure("method code", method_idx, dex_file, out); + return 0; + } + size_code_ += code_size; + relative_offset += code_size; } - size_code_size_ += sizeof(code_size); - relative_offset += sizeof(code_size); DCHECK_OFFSET(); - if (!out.WriteFully(&code[0], code_size)) { - ReportWriteFailure("method code", method_idx, dex_file, out); - return 0; - } - size_code_ += code_size; - relative_offset += code_size; } - DCHECK_OFFSET(); -#endif - const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable(); size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); @@ -994,7 +998,6 @@ OatWriter::OatClass::~OatClass() { delete compiled_methods_; } -#if defined(ART_USE_PORTABLE_COMPILER) size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader( size_t class_def_method_index_) const { uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); @@ -1008,7 +1011,6 @@ size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass( size_t class_def_method_index_) const { return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_]; } -#endif size_t OatWriter::OatClass::SizeOf() const { return sizeof(status_) diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 64275e6bbb..067c78971f 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -65,7 +65,7 @@ class OatWriter { public: OatWriter(const std::vector<const DexFile*>& dex_files, uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_begin, + uintptr_t image_file_location_oat_begin, const std::string& image_file_location, const CompilerDriver* compiler, TimingLogger* timings); @@ -150,10 +150,8 @@ class OatWriter { uint32_t num_non_null_compiled_methods, mirror::Class::Status status); ~OatClass(); -#if defined(ART_USE_PORTABLE_COMPILER) size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const; size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const; -#endif size_t SizeOf() const; void UpdateChecksum(OatHeader& oat_header) const; bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const; @@ -217,7 +215,7 @@ class OatWriter { // dependencies on the image. uint32_t image_file_location_oat_checksum_; - uint32_t image_file_location_oat_begin_; + uintptr_t image_file_location_oat_begin_; std::string image_file_location_; // data to write diff --git a/compiler/output_stream.h b/compiler/output_stream.h index 112dcfca74..478a854f26 100644 --- a/compiler/output_stream.h +++ b/compiler/output_stream.h @@ -41,7 +41,7 @@ class OutputStream { return location_; } - virtual bool WriteFully(const void* buffer, int64_t byte_count) = 0; + virtual bool WriteFully(const void* buffer, size_t byte_count) = 0; virtual off_t Seek(off_t offset, Whence whence) = 0; diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index 638e0ec457..7cc253ccdb 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -62,7 +62,9 @@ class DedupeSet { explicit DedupeSet(const char* set_name) { for (HashType i = 0; i < kShard; ++i) { - lock_name_[i] = StringPrintf("%s lock %d", set_name, i); + std::ostringstream oss; + oss << set_name << " lock " << i; + lock_name_[i] = oss.str(); lock_[i].reset(new Mutex(lock_name_[i].c_str())); } } diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index 2be3d56cfa..fdd2bab4da 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -23,18 +23,6 @@ namespace art { namespace mips { -#if 0 -class DirectCallRelocation : public AssemblerFixup { - public: - void Process(const MemoryRegion& region, int position) { - // Direct calls are relative to the following instruction on mips. - int32_t pointer = region.Load<int32_t>(position); - int32_t start = reinterpret_cast<int32_t>(region.start()); - int32_t delta = start + position + sizeof(int32_t); - region.Store<int32_t>(position, pointer - delta); - } -}; -#endif std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { if (rhs >= D0 && rhs < kNumberOfDRegisters) { diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 9095180246..136d2486df 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -24,17 +24,6 @@ namespace art { namespace x86 { -class DirectCallRelocation : public AssemblerFixup { - public: - void Process(const MemoryRegion& region, int position) { - // Direct calls are relative to the following instruction on x86. - int32_t pointer = region.Load<int32_t>(position); - int32_t start = reinterpret_cast<int32_t>(region.start()); - int32_t delta = start + position + sizeof(int32_t); - region.Store<int32_t>(position, pointer - delta); - } -}; - std::ostream& operator<<(std::ostream& os, const XmmRegister& reg) { return os << "XMM" << static_cast<int>(reg); } @@ -1304,15 +1293,6 @@ void X86Assembler::Bind(Label* label) { } -void X86Assembler::Stop(const char* message) { - // Emit the message address as immediate operand in the test rax instruction, - // followed by the int3 instruction. - // Execution can be resumed with the 'cont' command in gdb. - testl(EAX, Immediate(reinterpret_cast<int32_t>(message))); - int3(); -} - - void X86Assembler::EmitOperand(int reg_or_opcode, const Operand& operand) { CHECK_GE(reg_or_opcode, 0); CHECK_LT(reg_or_opcode, 8); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index 4ba03d1bd3..0fa8e0086c 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -452,9 +452,6 @@ class X86Assembler : public Assembler { void Align(int alignment, int offset); void Bind(Label* label); - // Debugging and bringup support. - void Stop(const char* message); - // // Overridden common assembler high-level functionality // diff --git a/compiler/vector_output_stream.h b/compiler/vector_output_stream.h index a3f82262af..09daa12e02 100644 --- a/compiler/vector_output_stream.h +++ b/compiler/vector_output_stream.h @@ -31,7 +31,7 @@ class VectorOutputStream : public OutputStream { virtual ~VectorOutputStream() {} - bool WriteFully(const void* buffer, int64_t byte_count) { + bool WriteFully(const void* buffer, size_t byte_count) { if (static_cast<size_t>(offset_) == vector_.size()) { const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer); vector_.insert(vector_.end(), &start[0], &start[byte_count]); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 582a0e9051..5ac01f2902 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -291,13 +291,13 @@ class Dex2Oat { timings.NewSplit("dex2oat OatWriter"); std::string image_file_location; uint32_t image_file_location_oat_checksum = 0; - uint32_t image_file_location_oat_data_begin = 0; + uintptr_t image_file_location_oat_data_begin = 0; if (!driver->IsImage()) { TimingLogger::ScopedSplit split("Loading image checksum", &timings); gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum(); image_file_location_oat_data_begin = - reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin()); + reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin()); image_file_location = image_space->GetImageFilename(); if (host_prefix != NULL && StartsWith(image_file_location, host_prefix->c_str())) { image_file_location = image_file_location.substr(host_prefix->size()); @@ -683,11 +683,7 @@ static int dex2oat(int argc, char** argv) { std::string android_root; std::vector<const char*> runtime_args; int thread_count = sysconf(_SC_NPROCESSORS_CONF); -#if defined(ART_USE_PORTABLE_COMPILER) - CompilerBackend compiler_backend = kPortable; -#else - CompilerBackend compiler_backend = kQuick; -#endif + CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick; // Take the default set of instruction features from the build. InstructionSetFeatures instruction_set_features = @@ -700,7 +696,7 @@ static int dex2oat(int argc, char** argv) { #elif defined(__mips__) InstructionSet instruction_set = kMips; #else -#error "Unsupported architecture" + InstructionSet instruction_set = kNone; #endif @@ -777,6 +773,8 @@ static int dex2oat(int argc, char** argv) { instruction_set = kMips; } else if (instruction_set_str == "x86") { instruction_set = kX86; + } else if (instruction_set_str == "x86_64") { + instruction_set = kX86_64; } } else if (option.starts_with("--instruction-set-features=")) { StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index 68626f6d5c..3e6e33fe45 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -16,6 +16,8 @@ #include "disassembler_arm.h" +#include <inttypes.h> + #include <iostream> #include "base/logging.h" @@ -711,7 +713,7 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) if (Rn.r == 15 && U == 1) { intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr); lit_adr = RoundDown(lit_adr, 4) + 4 + (imm8 << 2); - args << StringPrintf(" ; 0x%llx", *reinterpret_cast<int64_t*>(lit_adr)); + args << StringPrintf(" ; 0x%" PRIx64, *reinterpret_cast<int64_t*>(lit_adr)); } } else if (Rn.r == 13 && W == 1 && U == L) { // VPUSH/VPOP opcode << (L == 1 ? "vpop" : "vpush"); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 9bde30d90b..53b07f9d12 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -49,6 +49,7 @@ #include "runtime.h" #include "safe_map.h" #include "scoped_thread_state_change.h" +#include "verifier/dex_gc_map.h" #include "verifier/method_verifier.h" #include "vmap_table.h" @@ -162,12 +163,11 @@ class OatDumper { reinterpret_cast<const byte*>(oat_data) > oat_file_.End()) { return 0; // Address not in oat file } - uint32_t begin_offset = reinterpret_cast<size_t>(oat_data) - - reinterpret_cast<size_t>(oat_file_.Begin()); - typedef std::set<uint32_t>::iterator It; - It it = offsets_.upper_bound(begin_offset); + uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) - + reinterpret_cast<uintptr_t>(oat_file_.Begin()); + auto it = offsets_.upper_bound(begin_offset); CHECK(it != offsets_.end()); - uint32_t end_offset = *it; + uintptr_t end_offset = *it; return end_offset - begin_offset; } @@ -175,7 +175,7 @@ class OatDumper { return oat_file_.GetOatHeader().GetInstructionSet(); } - const void* GetOatCode(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const void* GetQuickOatCode(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { MethodHelper mh(m); for (size_t i = 0; i < oat_dex_files_.size(); i++) { const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; @@ -193,7 +193,7 @@ class OatDumper { const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); CHECK(oat_class != NULL); size_t method_index = m->GetMethodIndex(); - return oat_class->GetOatMethod(method_index).GetCode(); + return oat_class->GetOatMethod(method_index).GetQuickCode(); } } } @@ -216,7 +216,7 @@ class OatDumper { << "': " << error_msg; continue; } - offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader())); + offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader())); for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index)); @@ -240,7 +240,7 @@ class OatDumper { // If the last thing in the file is code for a method, there won't be an offset for the "next" // thing. Instead of having a special case in the upper_bound code, let's just add an entry // for the end of the file. - offsets_.insert(static_cast<uint32_t>(oat_file_.Size())); + offsets_.insert(oat_file_.Size()); } void AddOffsets(const OatFile::OatMethod& oat_method) { @@ -374,11 +374,17 @@ class OatDumper { } } { + const void* code = oat_method.GetQuickCode(); + uint32_t code_size = oat_method.GetQuickCodeSize(); + if (code == nullptr) { + code = oat_method.GetPortableCode(); + code_size = oat_method.GetPortableCodeSize(); + } indent1_os << StringPrintf("CODE: %p (offset=0x%08x size=%d)%s\n", - oat_method.GetCode(), + code, oat_method.GetCodeOffset(), - oat_method.GetCodeSize(), - oat_method.GetCode() != NULL ? "..." : ""); + code_size, + code != nullptr ? "..." : ""); Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); @@ -468,42 +474,60 @@ class OatDumper { } } + void DumpGcMapRegisters(std::ostream& os, const OatFile::OatMethod& oat_method, + const DexFile::CodeItem* code_item, + size_t num_regs, const uint8_t* reg_bitmap) { + bool first = true; + for (size_t reg = 0; reg < num_regs; reg++) { + if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) { + if (first) { + os << " v" << reg << " ("; + DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); + os << ")"; + first = false; + } else { + os << ", v" << reg << " ("; + DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); + os << ")"; + } + } + } + if (first) { + os << "No registers in GC map\n"; + } else { + os << "\n"; + } + } void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item) { const uint8_t* gc_map_raw = oat_method.GetNativeGcMap(); - if (gc_map_raw == NULL) { - return; + if (gc_map_raw == nullptr) { + return; // No GC map. } - NativePcOffsetToReferenceMap map(gc_map_raw); - const void* code = oat_method.GetCode(); - for (size_t entry = 0; entry < map.NumEntries(); entry++) { - const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + - map.GetNativePcOffset(entry); - os << StringPrintf("%p", native_pc); - size_t num_regs = map.RegWidth() * 8; - const uint8_t* reg_bitmap = map.GetBitMap(entry); - bool first = true; - for (size_t reg = 0; reg < num_regs; reg++) { - if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) { - if (first) { - os << " v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - first = false; - } else { - os << ", v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - } - } + const void* quick_code = oat_method.GetQuickCode(); + if (quick_code != nullptr) { + NativePcOffsetToReferenceMap map(gc_map_raw); + for (size_t entry = 0; entry < map.NumEntries(); entry++) { + const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) + + map.GetNativePcOffset(entry); + os << StringPrintf("%p", native_pc); + DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry)); + } + } else { + const void* portable_code = oat_method.GetPortableCode(); + CHECK(portable_code != nullptr); + verifier::DexPcToReferenceMap map(gc_map_raw); + for (size_t entry = 0; entry < map.NumEntries(); entry++) { + uint32_t dex_pc = map.GetDexPc(entry); + os << StringPrintf("0x%08x", dex_pc); + DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry)); } - os << "\n"; } } void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) { - const void* code = oat_method.GetCode(); - if (code == NULL) { + const void* quick_code = oat_method.GetQuickCode(); + if (quick_code == nullptr) { return; } MappingTable table(oat_method.GetMappingTable()); @@ -645,31 +669,37 @@ class OatDumper { void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier, const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item) { - const void* code = oat_method.GetCode(); - size_t code_size = oat_method.GetCodeSize(); - if (code == NULL || code_size == 0) { + const void* portable_code = oat_method.GetPortableCode(); + const void* quick_code = oat_method.GetQuickCode(); + + size_t code_size = oat_method.GetQuickCodeSize(); + if ((code_size == 0) || ((portable_code == nullptr) && (quick_code == nullptr))) { os << "NO CODE!\n"; return; - } - const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code); - size_t offset = 0; - while (offset < code_size) { - DumpMappingAtOffset(os, oat_method, offset, false); - offset += disassembler_->Dump(os, native_pc + offset); - uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true); - if (dex_pc != DexFile::kDexNoIndex) { - DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); - if (verifier != nullptr) { - DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc); + } else if (quick_code != nullptr) { + const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); + size_t offset = 0; + while (offset < code_size) { + DumpMappingAtOffset(os, oat_method, offset, false); + offset += disassembler_->Dump(os, quick_native_pc + offset); + uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true); + if (dex_pc != DexFile::kDexNoIndex) { + DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); + if (verifier != nullptr) { + DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc); + } } } + } else { + CHECK(portable_code != nullptr); + CHECK_EQ(code_size, 0U); // TODO: disassembly of portable is currently not supported. } } const std::string host_prefix_; const OatFile& oat_file_; std::vector<const OatFile::OatDexFile*> oat_dex_files_; - std::set<uint32_t> offsets_; + std::set<uintptr_t> offsets_; UniquePtr<Disassembler> disassembler_; }; @@ -856,7 +886,7 @@ class ImageDumper { if (descriptor[0] != 'L' && descriptor[0] != '[') { mirror::Class* type = fh.GetType(); if (type->IsPrimitiveLong()) { - os << StringPrintf("%lld (0x%llx)\n", field->Get64(obj), field->Get64(obj)); + os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj)); } else if (type->IsPrimitiveDouble()) { os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj)); } else if (type->IsPrimitiveFloat()) { @@ -902,34 +932,34 @@ class ImageDumper { return image_space_.Contains(object); } - const void* GetOatCodeBegin(mirror::ArtMethod* m) + const void* GetQuickOatCodeBegin(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const void* code = m->GetEntryPointFromCompiledCode(); - if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) { - code = oat_dumper_->GetOatCode(m); + const void* quick_code = m->GetEntryPointFromQuickCompiledCode(); + if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker())) { + quick_code = oat_dumper_->GetQuickOatCode(m); } if (oat_dumper_->GetInstructionSet() == kThumb2) { - code = reinterpret_cast<void*>(reinterpret_cast<uint32_t>(code) & ~0x1); + quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1); } - return code; + return quick_code; } - uint32_t GetOatCodeSize(mirror::ArtMethod* m) + uint32_t GetQuickOatCodeSize(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetOatCodeBegin(m)); - if (oat_code_begin == NULL) { + const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m)); + if (oat_code_begin == nullptr) { return 0; } return oat_code_begin[-1]; } - const void* GetOatCodeEnd(mirror::ArtMethod* m) + const void* GetQuickOatCodeEnd(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetOatCodeBegin(m)); + const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m)); if (oat_code_begin == NULL) { return NULL; } - return oat_code_begin + GetOatCodeSize(m); + return oat_code_begin + GetQuickOatCodeSize(m); } static void Callback(mirror::Object* obj, void* arg) @@ -1006,17 +1036,18 @@ class ImageDumper { } else if (obj->IsArtMethod()) { mirror::ArtMethod* method = obj->AsArtMethod(); if (method->IsNative()) { - DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); - DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); + // TODO: portable dumping. + DCHECK(method->GetNativeGcMap() == nullptr) << PrettyMethod(method); + DCHECK(method->GetMappingTable() == nullptr) << PrettyMethod(method); bool first_occurrence; - const void* oat_code = state->GetOatCodeBegin(method); - uint32_t oat_code_size = state->GetOatCodeSize(method); - state->ComputeOatSize(oat_code, &first_occurrence); + const void* quick_oat_code = state->GetQuickOatCodeBegin(method); + uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method); + state->ComputeOatSize(quick_oat_code, &first_occurrence); if (first_occurrence) { - state->stats_.native_to_managed_code_bytes += oat_code_size; + state->stats_.native_to_managed_code_bytes += quick_oat_code_size; } - if (oat_code != method->GetEntryPointFromCompiledCode()) { - indent_os << StringPrintf("OAT CODE: %p\n", oat_code); + if (quick_oat_code != method->GetEntryPointFromQuickCompiledCode()) { + indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code); } } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || method->IsResolutionMethod() || method->IsImtConflictMethod() || @@ -1050,33 +1081,34 @@ class ImageDumper { state->stats_.vmap_table_bytes += vmap_table_bytes; } - const void* oat_code_begin = state->GetOatCodeBegin(method); - const void* oat_code_end = state->GetOatCodeEnd(method); - uint32_t oat_code_size = state->GetOatCodeSize(method); - state->ComputeOatSize(oat_code_begin, &first_occurrence); + // TODO: portable dumping. + const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method); + const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method); + uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method); + state->ComputeOatSize(quick_oat_code_begin, &first_occurrence); if (first_occurrence) { - state->stats_.managed_code_bytes += oat_code_size; + state->stats_.managed_code_bytes += quick_oat_code_size; if (method->IsConstructor()) { if (method->IsStatic()) { - state->stats_.class_initializer_code_bytes += oat_code_size; + state->stats_.class_initializer_code_bytes += quick_oat_code_size; } else if (dex_instruction_bytes > kLargeConstructorDexBytes) { - state->stats_.large_initializer_code_bytes += oat_code_size; + state->stats_.large_initializer_code_bytes += quick_oat_code_size; } } else if (dex_instruction_bytes > kLargeMethodDexBytes) { - state->stats_.large_method_code_bytes += oat_code_size; + state->stats_.large_method_code_bytes += quick_oat_code_size; } } - state->stats_.managed_code_bytes_ignoring_deduplication += oat_code_size; + state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size; - indent_os << StringPrintf("OAT CODE: %p-%p\n", oat_code_begin, oat_code_end); + indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end); indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n", dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes); size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes + - vmap_table_bytes + oat_code_size + object_bytes; + vmap_table_bytes + quick_oat_code_size + object_bytes; double expansion = - static_cast<double>(oat_code_size) / static_cast<double>(dex_instruction_bytes); + static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes); state->stats_.ComputeOutliers(total_size, expansion, method); } } diff --git a/runtime/Android.mk b/runtime/Android.mk index d735051a9f..223ae7c16f 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -215,12 +215,13 @@ LIBART_LDFLAGS += -Wl,--no-fatal-warnings else # TARGET_ARCH != x86 ifeq ($(TARGET_ARCH),x86_64) LIBART_TARGET_SRC_FILES += \ - arch/x86/context_x86.cc \ - arch/x86/entrypoints_init_x86.cc \ - arch/x86/jni_entrypoints_x86.S \ - arch/x86/portable_entrypoints_x86.S \ - arch/x86/quick_entrypoints_x86.S \ - arch/x86/thread_x86.cc + arch/x86_64/context_x86_64.cc \ + arch/x86_64/entrypoints_init_x86_64.cc \ + arch/x86_64/jni_entrypoints_x86_64.S \ + arch/x86_64/portable_entrypoints_x86_64.S \ + arch/x86_64/quick_entrypoints_x86_64.S \ + arch/x86_64/thread_x86_64.cc \ + monitor_pool.cc LIBART_LDFLAGS += -Wl,--no-fatal-warnings else # TARGET_ARCH != x86_64 ifeq ($(TARGET_ARCH),mips) @@ -255,6 +256,16 @@ LIBART_HOST_SRC_FILES := \ thread_linux.cc ifeq ($(HOST_ARCH),x86) +ifneq ($(BUILD_HOST_64bit),) +LIBART_HOST_SRC_FILES += \ + arch/x86_64/context_x86_64.cc \ + arch/x86_64/entrypoints_init_x86_64.cc \ + arch/x86_64/jni_entrypoints_x86_64.S \ + arch/x86_64/portable_entrypoints_x86_64.S \ + arch/x86_64/quick_entrypoints_x86_64.S \ + arch/x86_64/thread_x86_64.cc \ + monitor_pool.cc +else LIBART_HOST_SRC_FILES += \ arch/x86/context_x86.cc \ arch/x86/entrypoints_init_x86.cc \ @@ -262,6 +273,7 @@ LIBART_HOST_SRC_FILES += \ arch/x86/portable_entrypoints_x86.S \ arch/x86/quick_entrypoints_x86.S \ arch/x86/thread_x86.cc +endif else # HOST_ARCH != x86 $(error unsupported HOST_ARCH=$(HOST_ARCH)) endif # HOST_ARCH != x86 diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h index 00651ffb80..020cae0a5e 100644 --- a/runtime/arch/arm/context_arm.h +++ b/runtime/arch/arm/context_arm.h @@ -35,7 +35,7 @@ class ArmContext : public Context { virtual void Reset(); - virtual void FillCalleeSaves(const StackVisitor& fr); + virtual void FillCalleeSaves(const StackVisitor& fr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void SetSP(uintptr_t new_sp) { SetGPR(SP, new_sp); diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S index ac519d55bb..98d17dc830 100644 --- a/runtime/arch/arm/portable_entrypoints_arm.S +++ b/runtime/arch/arm/portable_entrypoints_arm.S @@ -53,7 +53,7 @@ ENTRY art_portable_invoke_stub mov ip, #0 @ set ip to 0 str ip, [sp] @ store NULL for method* at bottom of frame add sp, #16 @ first 4 args are not passed on stack for portable - ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code + ldr ip, [r0, #METHOD_PORTABLE_CODE_OFFSET] @ get pointer to the code blx ip @ call the method mov sp, r11 @ restore the stack pointer ldr ip, [sp, #24] @ load the result pointer diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 34de93fb4d..0e5c60ae8d 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -302,7 +302,7 @@ ENTRY art_quick_invoke_stub ldr r3, [sp, #12] @ copy arg value for r3 mov ip, #0 @ set ip to 0 str ip, [sp] @ store NULL for method* at bottom of frame - ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code + ldr ip, [r0, #METHOD_QUICK_CODE_OFFSET] @ get pointer to the code blx ip @ call the method mov sp, r11 @ restore the stack pointer ldr ip, [sp, #24] @ load the result pointer diff --git a/runtime/arch/context.cc b/runtime/arch/context.cc index 7075e42575..5eaf80954a 100644 --- a/runtime/arch/context.cc +++ b/runtime/arch/context.cc @@ -22,6 +22,10 @@ #include "mips/context_mips.h" #elif defined(__i386__) #include "x86/context_x86.h" +#elif defined(__x86_64__) +#include "x86_64/context_x86_64.h" +#else +#include "base/logging.h" #endif namespace art { @@ -33,8 +37,11 @@ Context* Context::Create() { return new mips::MipsContext(); #elif defined(__i386__) return new x86::X86Context(); +#elif defined(__x86_64__) + return new x86_64::X86_64Context(); #else UNIMPLEMENTED(FATAL); + return nullptr; #endif } diff --git a/runtime/arch/context.h b/runtime/arch/context.h index 91e0cd69db..3d111785d7 100644 --- a/runtime/arch/context.h +++ b/runtime/arch/context.h @@ -20,6 +20,8 @@ #include <stddef.h> #include <stdint.h> +#include "locks.h" + namespace art { class StackVisitor; @@ -38,7 +40,8 @@ class Context { // Read values from callee saves in the given frame. The frame also holds // the method that holds the layout. - virtual void FillCalleeSaves(const StackVisitor& fr) = 0; + virtual void FillCalleeSaves(const StackVisitor& fr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; // Set the stack pointer value virtual void SetSP(uintptr_t new_sp) = 0; diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h index 5595f8631e..4145cd3d74 100644 --- a/runtime/arch/mips/context_mips.h +++ b/runtime/arch/mips/context_mips.h @@ -33,7 +33,7 @@ class MipsContext : public Context { virtual void Reset(); - virtual void FillCalleeSaves(const StackVisitor& fr); + virtual void FillCalleeSaves(const StackVisitor& fr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void SetSP(uintptr_t new_sp) { SetGPR(SP, new_sp); diff --git a/runtime/arch/mips/portable_entrypoints_mips.S b/runtime/arch/mips/portable_entrypoints_mips.S index 9208a8a4f5..7545ce0d6c 100644 --- a/runtime/arch/mips/portable_entrypoints_mips.S +++ b/runtime/arch/mips/portable_entrypoints_mips.S @@ -61,5 +61,73 @@ ENTRY art_portable_proxy_invoke_handler .cfi_adjust_cfa_offset -64 END art_portable_proxy_invoke_handler + /* + * Invocation stub for portable code. + * On entry: + * a0 = method pointer + * a1 = argument array or NULL for no argument methods + * a2 = size of argument array in bytes + * a3 = (managed) thread pointer + * [sp + 16] = JValue* result + * [sp + 20] = result type char + */ +ENTRY art_portable_invoke_stub + GENERATE_GLOBAL_POINTER + sw $a0, 0($sp) # save out a0 + addiu $sp, $sp, -16 # spill s0, s1, fp, ra + .cfi_adjust_cfa_offset 16 + sw $ra, 12($sp) + .cfi_rel_offset 31, 12 + sw $fp, 8($sp) + .cfi_rel_offset 30, 8 + sw $s1, 4($sp) + .cfi_rel_offset 17, 4 + sw $s0, 0($sp) + .cfi_rel_offset 16, 0 + move $fp, $sp # save sp in fp + .cfi_def_cfa_register 30 + move $s1, $a3 # move managed thread pointer into s1 + addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval + addiu $t0, $a2, 16 # create space for method pointer in frame + srl $t0, $t0, 3 # shift the frame size right 3 + sll $t0, $t0, 3 # shift the frame size left 3 to align to 16 bytes + subu $sp, $sp, $t0 # reserve stack space for argument array + addiu $a0, $sp, 4 # pass stack pointer + method ptr as dest for memcpy + jal memcpy # (dest, src, bytes) + addiu $sp, $sp, -16 # make space for argument slots for memcpy + addiu $sp, $sp, 16 # restore stack after memcpy + lw $a0, 16($fp) # restore method* + lw $a1, 4($sp) # copy arg value for a1 + lw $a2, 8($sp) # copy arg value for a2 + lw $a3, 12($sp) # copy arg value for a3 + lw $t9, METHOD_PORTABLE_CODE_OFFSET($a0) # get pointer to the code + jalr $t9 # call the method + sw $zero, 0($sp) # store NULL for method* at bottom of frame + move $sp, $fp # restore the stack + lw $s0, 0($sp) + .cfi_restore 16 + lw $s1, 4($sp) + .cfi_restore 17 + lw $fp, 8($sp) + .cfi_restore 30 + lw $ra, 12($sp) + .cfi_restore 31 + addiu $sp, $sp, 16 + .cfi_adjust_cfa_offset -16 + lw $t0, 16($sp) # get result pointer + lw $t1, 20($sp) # get result type char + li $t2, 68 # put char 'D' into t2 + beq $t1, $t2, 1f # branch if result type char == 'D' + li $t3, 70 # put char 'F' into t3 + beq $t1, $t3, 1f # branch if result type char == 'F' + sw $v0, 0($t0) # store the result + jr $ra + sw $v1, 4($t0) # store the other half of the result +1: + s.s $f0, 0($t0) # store floating point result + jr $ra + s.s $f1, 4($t0) # store other half of floating point result +END art_portable_invoke_stub + UNIMPLEMENTED art_portable_resolution_trampoline UNIMPLEMENTED art_portable_to_interpreter_bridge diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 2d1e87aa68..c60bca0e5e 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -449,7 +449,7 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck /* - * Common invocation stub for portable and quick. + * Invocation stub for quick code. * On entry: * a0 = method pointer * a1 = argument array or NULL for no argument methods @@ -458,9 +458,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvo * [sp + 16] = JValue* result * [sp + 20] = result type char */ - .type art_portable_invoke_stub, %function - .global art_portable_invoke_stub -art_portable_invoke_stub: ENTRY art_quick_invoke_stub GENERATE_GLOBAL_POINTER sw $a0, 0($sp) # save out a0 @@ -490,7 +487,7 @@ ENTRY art_quick_invoke_stub lw $a1, 4($sp) # copy arg value for a1 lw $a2, 8($sp) # copy arg value for a2 lw $a3, 12($sp) # copy arg value for a3 - lw $t9, METHOD_CODE_OFFSET($a0) # get pointer to the code + lw $t9, METHOD_QUICK_CODE_OFFSET($a0) # get pointer to the code jalr $t9 # call the method sw $zero, 0($sp) # store NULL for method* at bottom of frame move $sp, $fp # restore the stack @@ -518,7 +515,6 @@ ENTRY art_quick_invoke_stub jr $ra s.s $f1, 4($t0) # store other half of floating point result END art_quick_invoke_stub - .size art_portable_invoke_stub, .-art_portable_invoke_stub /* * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc index 66a51f7492..d7dca6455a 100644 --- a/runtime/arch/x86/context_x86.cc +++ b/runtime/arch/x86/context_x86.cc @@ -23,7 +23,7 @@ namespace art { namespace x86 { -static const uint32_t gZero = 0; +static const uintptr_t gZero = 0; void X86Context::Reset() { for (int i = 0; i < kNumberOfCpuRegisters; i++) { @@ -55,8 +55,8 @@ void X86Context::FillCalleeSaves(const StackVisitor& fr) { void X86Context::SmashCallerSaves() { // This needs to be 0 because we want a null/zero return value. - gprs_[EAX] = const_cast<uint32_t*>(&gZero); - gprs_[EDX] = const_cast<uint32_t*>(&gZero); + gprs_[EAX] = const_cast<uintptr_t*>(&gZero); + gprs_[EDX] = const_cast<uintptr_t*>(&gZero); gprs_[ECX] = NULL; gprs_[EBX] = NULL; } @@ -89,7 +89,7 @@ void X86Context::DoLongJump() { : "g"(&gprs[0]) // input. :); // clobber. #else - UNIMPLEMENTED(FATAL); + UNIMPLEMENTED(FATAL); #endif } diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h index d7d22101cc..598314daa4 100644 --- a/runtime/arch/x86/context_x86.h +++ b/runtime/arch/x86/context_x86.h @@ -33,7 +33,7 @@ class X86Context : public Context { virtual void Reset(); - virtual void FillCalleeSaves(const StackVisitor& fr); + virtual void FillCalleeSaves(const StackVisitor& fr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void SetSP(uintptr_t new_sp) { SetGPR(ESP, new_sp); diff --git a/runtime/arch/x86/jni_entrypoints_x86.S b/runtime/arch/x86/jni_entrypoints_x86.S index 72047d52d5..2eb5ada4e3 100644 --- a/runtime/arch/x86/jni_entrypoints_x86.S +++ b/runtime/arch/x86/jni_entrypoints_x86.S @@ -17,7 +17,7 @@ #include "asm_support_x86.S" /* - * Portable resolution trampoline. + * Jni dlsym lookup stub. */ DEFINE_FUNCTION art_jni_dlsym_lookup_stub subl LITERAL(4), %esp // align stack diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S index 48de7c133d..4bd6173f04 100644 --- a/runtime/arch/x86/portable_entrypoints_x86.S +++ b/runtime/arch/x86/portable_entrypoints_x86.S @@ -46,7 +46,7 @@ DEFINE_FUNCTION art_portable_invoke_stub addl LITERAL(12), %esp // pop arguments to memcpy mov 12(%ebp), %eax // move method pointer into eax mov %eax, (%esp) // push method pointer onto stack - call *METHOD_CODE_OFFSET(%eax) // call the method + call *METHOD_PORTABLE_CODE_OFFSET(%eax) // call the method mov %ebp, %esp // restore stack pointer POP ebx // pop ebx POP ebp // pop ebp diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 74ec761f5b..9c3eb30736 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -275,7 +275,7 @@ DEFINE_FUNCTION art_quick_invoke_stub mov 4(%esp), %ecx // copy arg1 into ecx mov 8(%esp), %edx // copy arg2 into edx mov 12(%esp), %ebx // copy arg3 into ebx - call *METHOD_CODE_OFFSET(%eax) // call the method + call *METHOD_QUICK_CODE_OFFSET(%eax) // call the method mov %ebp, %esp // restore stack pointer CFI_DEF_CFA_REGISTER(esp) POP ebx // pop ebx diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S new file mode 100644 index 0000000000..b59c0cbe50 --- /dev/null +++ b/runtime/arch/x86_64/asm_support_x86_64.S @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ +#define ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ + +#include "asm_support_x86_64.h" + +#if defined(__APPLE__) + // Mac OS' as(1) doesn't let you name macro parameters. + #define MACRO0(macro_name) .macro macro_name + #define MACRO1(macro_name, macro_arg1) .macro macro_name + #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name + #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name + #define END_MACRO .endmacro + + // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names + // are mangled with an extra underscore prefix. The use of $x for arguments + // mean that literals need to be represented with $$x in macros. + #define SYMBOL(name) _ ## name + #define PLT_SYMBOL(name) _ ## name + #define VAR(name,index) SYMBOL($index) + #define PLT_VAR(name, index) SYMBOL($index) + #define REG_VAR(name,index) %$index + #define CALL_MACRO(name,index) $index + #define LITERAL(value) $value + #define MACRO_LITERAL(value) $$value + + // Mac OS' doesn't like cfi_* directives + #define CFI_STARTPROC + #define CFI_ENDPROC + #define CFI_ADJUST_CFA_OFFSET(size) + #define CFI_DEF_CFA(reg,size) + #define CFI_DEF_CFA_REGISTER(reg) + #define CFI_RESTORE(reg) + #define CFI_REL_OFFSET(reg,size) + + // Mac OS' doesn't support certain directives + #define FUNCTION_TYPE(name) + #define SIZE(name) +#else + // Regular gas(1) lets you name macro parameters. + #define MACRO0(macro_name) .macro macro_name + #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1 + #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2 + #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3 + #define END_MACRO .endm + + // Regular gas(1) uses \argument_name for macro arguments. + // We need to turn on alternate macro syntax so we can use & instead or the preprocessor + // will screw us by inserting a space between the \ and the name. Even in this mode there's + // no special meaning to $, so literals are still just $x. The use of altmacro means % is a + // special character meaning care needs to be taken when passing registers as macro arguments. + .altmacro + #define SYMBOL(name) name + #define PLT_SYMBOL(name) name@PLT + #define VAR(name,index) name& + #define PLT_VAR(name, index) name&@PLT + #define REG_VAR(name,index) %name + #define CALL_MACRO(name,index) name& + #define LITERAL(value) $value + #define MACRO_LITERAL(value) $value + + // CFI support + #define CFI_STARTPROC .cfi_startproc + #define CFI_ENDPROC .cfi_endproc + #define CFI_ADJUST_CFA_OFFSET(size) .cfi_adjust_cfa_offset size + #define CFI_DEF_CFA(reg,size) .cfi_def_cfa reg,size + #define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg + #define CFI_RESTORE(reg) .cfi_restore reg + #define CFI_REL_OFFSET(reg,size) .cfi_rel_offset reg,size + + #define FUNCTION_TYPE(name) .type name&, @function + #define SIZE(name) .size name, .-name +#endif + + /* Cache alignment for function entry */ +MACRO0(ALIGN_FUNCTION_ENTRY) + .balign 16 +END_MACRO + +MACRO1(DEFINE_FUNCTION, c_name) + FUNCTION_TYPE(\c_name) + .globl VAR(c_name, 0) + ALIGN_FUNCTION_ENTRY +VAR(c_name, 0): + CFI_STARTPROC +END_MACRO + +MACRO1(END_FUNCTION, c_name) + CFI_ENDPROC + SIZE(\c_name) +END_MACRO + +MACRO1(PUSH, reg) + pushq REG_VAR(reg, 0) + CFI_ADJUST_CFA_OFFSET(8) + CFI_REL_OFFSET(REG_VAR(reg, 0), 0) +END_MACRO + +MACRO1(POP, reg) + popq REG_VAR(reg,0) + CFI_ADJUST_CFA_OFFSET(-8) + CFI_RESTORE(REG_VAR(reg,0)) +END_MACRO + +MACRO1(UNIMPLEMENTED,name) + FUNCTION_TYPE(\name) + .globl VAR(name, 0) + ALIGN_FUNCTION_ENTRY +VAR(name, 0): + CFI_STARTPROC + int3 + int3 + CFI_ENDPROC + SIZE(\name) +END_MACRO + +MACRO0(SETUP_GOT_NOSAVE) + call __x86.get_pc_thunk.bx + addl $_GLOBAL_OFFSET_TABLE_, %ebx +END_MACRO + +MACRO0(SETUP_GOT) + PUSH ebx + SETUP_GOT_NOSAVE +END_MACRO + +MACRO0(UNDO_SETUP_GOT) + POP ebx +END_MACRO + +#endif // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_ diff --git a/runtime/arch/x86_64/asm_support_x86_64.h b/runtime/arch/x86_64/asm_support_x86_64.h new file mode 100644 index 0000000000..d425ed8c81 --- /dev/null +++ b/runtime/arch/x86_64/asm_support_x86_64.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_ +#define ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_ + +#include "asm_support.h" + +// Offset of field Thread::self_ verified in InitCpu +#define THREAD_SELF_OFFSET 72 +// Offset of field Thread::card_table_ verified in InitCpu +#define THREAD_CARD_TABLE_OFFSET 8 +// Offset of field Thread::exception_ verified in InitCpu +#define THREAD_EXCEPTION_OFFSET 16 +// Offset of field Thread::thin_lock_thread_id_ verified in InitCpu +#define THREAD_ID_OFFSET 112 + +#endif // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_ diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc new file mode 100644 index 0000000000..4d1131c866 --- /dev/null +++ b/runtime/arch/x86_64/context_x86_64.cc @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 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 "context_x86_64.h" + +#include "mirror/art_method.h" +#include "mirror/object-inl.h" +#include "stack.h" + +namespace art { +namespace x86_64 { + +static const uintptr_t gZero = 0; + +void X86_64Context::Reset() { + for (int i = 0; i < kNumberOfCpuRegisters; i++) { + gprs_[i] = NULL; + } + gprs_[RSP] = &rsp_; + // Initialize registers with easy to spot debug values. + rsp_ = X86_64Context::kBadGprBase + RSP; + rip_ = X86_64Context::kBadGprBase + kNumberOfCpuRegisters; +} + +void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { + mirror::ArtMethod* method = fr.GetMethod(); + uint32_t core_spills = method->GetCoreSpillMask(); + size_t spill_count = __builtin_popcount(core_spills); + DCHECK_EQ(method->GetFpSpillMask(), 0u); + size_t frame_size = method->GetFrameSizeInBytes(); + if (spill_count > 0) { + // Lowest number spill is farthest away, walk registers and fill into context. + int j = 2; // Offset j to skip return address spill. + for (int i = 0; i < kNumberOfCpuRegisters; i++) { + if (((core_spills >> i) & 1) != 0) { + gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size); + j++; + } + } + } +} + +void X86_64Context::SmashCallerSaves() { + // This needs to be 0 because we want a null/zero return value. + gprs_[RAX] = const_cast<uintptr_t*>(&gZero); + gprs_[RDX] = const_cast<uintptr_t*>(&gZero); + gprs_[RCX] = nullptr; + gprs_[RBX] = nullptr; +} + +void X86_64Context::SetGPR(uint32_t reg, uintptr_t value) { + CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters)); + CHECK_NE(gprs_[reg], &gZero); + CHECK(gprs_[reg] != NULL); + *gprs_[reg] = value; +} + +void X86_64Context::DoLongJump() { + UNIMPLEMENTED(FATAL); +} + +} // namespace x86_64 +} // namespace art diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h new file mode 100644 index 0000000000..3e491650b8 --- /dev/null +++ b/runtime/arch/x86_64/context_x86_64.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_64_CONTEXT_X86_64_H_ +#define ART_RUNTIME_ARCH_X86_64_CONTEXT_X86_64_H_ + +#include "arch/context.h" +#include "base/logging.h" +#include "registers_x86_64.h" + +namespace art { +namespace x86_64 { + +class X86_64Context : public Context { + public: + X86_64Context() { + Reset(); + } + virtual ~X86_64Context() {} + + virtual void Reset(); + + virtual void FillCalleeSaves(const StackVisitor& fr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + virtual void SetSP(uintptr_t new_sp) { + SetGPR(RSP, new_sp); + } + + virtual void SetPC(uintptr_t new_pc) { + rip_ = new_pc; + } + + virtual uintptr_t GetGPR(uint32_t reg) { + const uint32_t kNumberOfCpuRegisters = 8; + DCHECK_LT(reg, kNumberOfCpuRegisters); + return *gprs_[reg]; + } + + virtual void SetGPR(uint32_t reg, uintptr_t value); + + virtual void SmashCallerSaves(); + virtual void DoLongJump(); + + private: + // Pointers to register locations, floating point registers are all caller save. Values are + // initialized to NULL or the special registers below. + uintptr_t* gprs_[kNumberOfCpuRegisters]; + // Hold values for rsp and rip if they are not located within a stack frame. RIP is somewhat + // special in that it cannot be encoded normally as a register operand to an instruction (except + // in 64bit addressing modes). + uintptr_t rsp_, rip_; +}; +} // namespace x86_64 +} // namespace art + +#endif // ART_RUNTIME_ARCH_X86_64_CONTEXT_X86_64_H_ diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc new file mode 100644 index 0000000000..589c7d9dc9 --- /dev/null +++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2012 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 "entrypoints/portable/portable_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "entrypoints/entrypoint_utils.h" + +namespace art { + +// Interpreter entrypoints. +extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); +extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + +// Portable entrypoints. +extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*); +extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*); + +// Cast entrypoints. +extern "C" uint32_t art_quick_is_assignable(const mirror::Class* klass, + const mirror::Class* ref_class); +extern "C" void art_quick_check_cast(void*, void*); + +// DexCache entrypoints. +extern "C" void* art_quick_initialize_static_storage(uint32_t, void*); +extern "C" void* art_quick_initialize_type(uint32_t, void*); +extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*); +extern "C" void* art_quick_resolve_string(void*, uint32_t); + +// Field entrypoints. +extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t); +extern "C" int art_quick_set32_static(uint32_t, int32_t); +extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t); +extern "C" int art_quick_set64_static(uint32_t, int64_t); +extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*); +extern "C" int art_quick_set_obj_static(uint32_t, void*); +extern "C" int32_t art_quick_get32_instance(uint32_t, void*); +extern "C" int32_t art_quick_get32_static(uint32_t); +extern "C" int64_t art_quick_get64_instance(uint32_t, void*); +extern "C" int64_t art_quick_get64_static(uint32_t); +extern "C" void* art_quick_get_obj_instance(uint32_t, void*); +extern "C" void* art_quick_get_obj_static(uint32_t); + +// Array entrypoints. +extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*); +extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*); +extern "C" void art_quick_aput_obj(void*, uint32_t, void*); +extern "C" void art_quick_handle_fill_data(void*, void*); + +// Lock entrypoints. +extern "C" void art_quick_lock_object(void*); +extern "C" void art_quick_unlock_object(void*); + +// Math entrypoints. +extern "C" double art_quick_fmod(double, double); +extern "C" float art_quick_fmodf(float, float); +extern "C" double art_quick_l2d(int64_t); +extern "C" float art_quick_l2f(int64_t); +extern "C" int64_t art_quick_d2l(double); +extern "C" int64_t art_quick_f2l(float); +extern "C" int32_t art_quick_idivmod(int32_t, int32_t); +extern "C" int64_t art_quick_ldiv(int64_t, int64_t); +extern "C" int64_t art_quick_lmod(int64_t, int64_t); +extern "C" int64_t art_quick_lmul(int64_t, int64_t); +extern "C" uint64_t art_quick_lshl(uint64_t, uint32_t); +extern "C" uint64_t art_quick_lshr(uint64_t, uint32_t); +extern "C" uint64_t art_quick_lushr(uint64_t, uint32_t); + +// Intrinsic entrypoints. +extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t); +extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); +extern "C" int32_t art_quick_string_compareto(void*, void*); +extern "C" void* art_quick_memcpy(void*, const void*, size_t); + +// Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); +extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); +extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); +extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); +extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); +extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); +extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); +extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*); + +// Thread entrypoints. +extern void CheckSuspendFromCode(Thread* thread); +extern "C" void art_quick_test_suspend(); + +// Throw entrypoints. +extern "C" void art_quick_deliver_exception(void*); +extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit); +extern "C" void art_quick_throw_div_zero(); +extern "C" void art_quick_throw_no_such_method(int32_t method_idx); +extern "C" void art_quick_throw_null_pointer_exception(); +extern "C" void art_quick_throw_stack_overflow(void*); + +extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints); + +void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, + PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) { + // Interpreter + ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; + ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; + + // JNI + jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; + + // Portable + ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline; + ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge; + + // Alloc + ResetQuickAllocEntryPoints(qpoints); + + // Cast + qpoints->pInstanceofNonTrivial = art_quick_is_assignable; + qpoints->pCheckCast = art_quick_check_cast; + + // DexCache + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; + qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; + qpoints->pInitializeType = art_quick_initialize_type; + qpoints->pResolveString = art_quick_resolve_string; + + // Field + qpoints->pSet32Instance = art_quick_set32_instance; + qpoints->pSet32Static = art_quick_set32_static; + qpoints->pSet64Instance = art_quick_set64_instance; + qpoints->pSet64Static = art_quick_set64_static; + qpoints->pSetObjInstance = art_quick_set_obj_instance; + qpoints->pSetObjStatic = art_quick_set_obj_static; + qpoints->pGet32Instance = art_quick_get32_instance; + qpoints->pGet64Instance = art_quick_get64_instance; + qpoints->pGetObjInstance = art_quick_get_obj_instance; + qpoints->pGet32Static = art_quick_get32_static; + qpoints->pGet64Static = art_quick_get64_static; + 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; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + + // Locks + qpoints->pLockObject = art_quick_lock_object; + qpoints->pUnlockObject = art_quick_unlock_object; + + // Math + // points->pCmpgDouble = NULL; // Not needed on x86. + // points->pCmpgFloat = NULL; // Not needed on x86. + // points->pCmplDouble = NULL; // Not needed on x86. + // points->pCmplFloat = NULL; // Not needed on x86. + qpoints->pFmod = art_quick_fmod; + // qpoints->pSqrt = NULL; // Not needed on x86. + qpoints->pL2d = art_quick_l2d; + qpoints->pFmodf = art_quick_fmodf; + qpoints->pL2f = art_quick_l2f; + // points->pD2iz = NULL; // Not needed on x86. + // points->pF2iz = NULL; // Not needed on x86. + qpoints->pIdivmod = art_quick_idivmod; + qpoints->pD2l = art_quick_d2l; + qpoints->pF2l = art_quick_f2l; + qpoints->pLdiv = art_quick_ldiv; + qpoints->pLmod = art_quick_lmod; + qpoints->pLmul = art_quick_lmul; + qpoints->pShlLong = art_quick_lshl; + qpoints->pShrLong = art_quick_lshr; + qpoints->pUshrLong = art_quick_lushr; + + // Intrinsics + qpoints->pIndexOf = art_quick_indexof; + qpoints->pMemcmp16 = art_quick_memcmp16; + qpoints->pStringCompareTo = art_quick_string_compareto; + qpoints->pMemcpy = art_quick_memcpy; + + // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; + qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; + qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; + qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; + qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; + qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; + qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; + qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; + + // Thread + qpoints->pCheckSuspend = CheckSuspendFromCode; + qpoints->pTestSuspend = art_quick_test_suspend; + + // Throws + qpoints->pDeliverException = art_quick_deliver_exception; + qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; + qpoints->pThrowDivZero = art_quick_throw_div_zero; + qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; + qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; + qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; +}; + +} // namespace art diff --git a/runtime/arch/x86_64/jni_entrypoints_x86_64.S b/runtime/arch/x86_64/jni_entrypoints_x86_64.S new file mode 100644 index 0000000000..35fcccb8cc --- /dev/null +++ b/runtime/arch/x86_64/jni_entrypoints_x86_64.S @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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 "asm_support_x86_64.S" + + /* + * Jni dlsym lookup stub. + */ +UNIMPLEMENTED art_jni_dlsym_lookup_stub diff --git a/runtime/arch/x86_64/portable_entrypoints_x86_64.S b/runtime/arch/x86_64/portable_entrypoints_x86_64.S new file mode 100644 index 0000000000..2e9d19a899 --- /dev/null +++ b/runtime/arch/x86_64/portable_entrypoints_x86_64.S @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 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 "asm_support_x86_64.S" + + /* + * Portable invocation stub. + */ +UNIMPLEMENTED art_portable_invoke_stub + +UNIMPLEMENTED art_portable_proxy_invoke_handler + +UNIMPLEMENTED art_portable_resolution_trampoline + +UNIMPLEMENTED art_portable_to_interpreter_bridge diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S new file mode 100644 index 0000000000..e01a31b6b4 --- /dev/null +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2012 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 "asm_support_x86_64.S" + +// For x86, the CFA is esp+4, the address above the pushed return address on the stack. + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kSaveAll) + */ +MACRO0(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME) + int3 + int3 +END_MACRO + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kRefsOnly) + */ +MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME) + int3 + int3 +END_MACRO + +MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME) + int3 + int3 +END_MACRO + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kRefsAndArgs) + */ +MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME) + int3 + int3 +END_MACRO + +MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME) + int3 +END_MACRO + + /* + * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending + * exception is Thread::Current()->exception_. + */ +MACRO0(DELIVER_PENDING_EXCEPTION) + int3 + int3 +END_MACRO + +MACRO2(NO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + + /* + * Called by managed code to create and deliver a NullPointerException. + */ +NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode + + /* + * Called by managed code to create and deliver an ArithmeticException. + */ +NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode + + /* + * Called by managed code to create and deliver a StackOverflowError. + */ +NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode + + /* + * Called by managed code, saves callee saves and then calls artThrowException + * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. + */ +ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode + + /* + * Called by managed code to create and deliver a NoSuchMethodError. + */ +ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode + + /* + * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds + * index, arg2 holds limit. + */ +TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode + + /* + * All generated callsites for interface invokes and invocation slow paths will load arguments + * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the + * stack and call the appropriate C helper. + * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1. + * + * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting + * of the target Method* in r0 and method->code_ in r1. + * + * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the + * thread and we branch to another stub to deliver it. + * + * On success this wrapper will restore arguments and *jump* to the target, leaving the lr + * pointing back to the original caller. + */ +MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline +INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck + +INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck +INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck +INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck +INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck + + /* + * Quick invocation stub. + */ +DEFINE_FUNCTION art_quick_invoke_stub + int3 + int3 +END_FUNCTION art_quick_invoke_stub + +MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO3(TWO_ARG_DOWNCALL, c_name, cxx_name, return_macro) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO3(THREE_ARG_DOWNCALL, c_name, cxx_name, return_macro) + DEFINE_FUNCTION VAR(c_name, 0) + int3 + int3 + END_FUNCTION VAR(c_name, 0) +END_MACRO + +MACRO0(RETURN_IF_RESULT_IS_NON_ZERO) + int3 + testl %eax, %eax // eax == 0 ? + jz 1f // if eax == 0 goto 1 + ret // return +1: // deliver exception on current thread + DELIVER_PENDING_EXCEPTION +END_MACRO + +MACRO0(RETURN_IF_EAX_ZERO) + int3 + testl %eax, %eax // eax == 0 ? + jnz 1f // if eax != 0 goto 1 + ret // return +1: // deliver exception on current thread + DELIVER_PENDING_EXCEPTION +END_MACRO + +MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION) + int3 + int3 + DELIVER_PENDING_EXCEPTION +END_MACRO + +// Generate the allocation entrypoints for each allocator. +// TODO: use arch/quick_alloc_entrypoints.S. Currently we don't as we need to use concatenation +// macros to work around differences between OS/X's as and binutils as (OS/X lacks named arguments +// to macros and the VAR macro won't concatenate arguments properly), this also breaks having +// 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) \ + THREE_ARG_DOWNCALL art_quick_alloc_array ## c_suffix, artAllocArrayFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(c_suffix, cxx_suffix) \ + THREE_ARG_DOWNCALL art_quick_alloc_array_resolved ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO +#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 +#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 +#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 + +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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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) + +TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO +TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO +TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO +TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO + +TWO_ARG_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO + +DEFINE_FUNCTION art_quick_lock_object + int3 + int3 +END_FUNCTION art_quick_lock_object + +DEFINE_FUNCTION art_quick_unlock_object + int3 + int3 +END_FUNCTION art_quick_unlock_object + +DEFINE_FUNCTION art_quick_is_assignable + int3 + int3 +END_FUNCTION art_quick_is_assignable + +DEFINE_FUNCTION art_quick_check_cast + int3 + int3 +END_FUNCTION art_quick_check_cast + + /* + * 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 + */ +UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check +UNIMPLEMENTED art_quick_aput_obj_with_bound_check +UNIMPLEMENTED art_quick_aput_obj +UNIMPLEMENTED art_quick_memcpy + +NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret + +UNIMPLEMENTED art_quick_fmod +UNIMPLEMENTED art_quick_fmodf +UNIMPLEMENTED art_quick_l2d +UNIMPLEMENTED art_quick_l2f +UNIMPLEMENTED art_quick_d2l +UNIMPLEMENTED art_quick_f2l +UNIMPLEMENTED art_quick_idivmod +UNIMPLEMENTED art_quick_ldiv +UNIMPLEMENTED art_quick_lmod +UNIMPLEMENTED art_quick_lmul +UNIMPLEMENTED art_quick_lshl +UNIMPLEMENTED art_quick_lshr +UNIMPLEMENTED art_quick_lushr +UNIMPLEMENTED art_quick_set32_instance +UNIMPLEMENTED art_quick_set64_instance +UNIMPLEMENTED art_quick_set_obj_instance +UNIMPLEMENTED art_quick_get32_instance +UNIMPLEMENTED art_quick_get64_instance +UNIMPLEMENTED art_quick_get_obj_instance +UNIMPLEMENTED art_quick_set32_static +UNIMPLEMENTED art_quick_set64_static +UNIMPLEMENTED art_quick_set_obj_static +UNIMPLEMENTED art_quick_get32_static +UNIMPLEMENTED art_quick_get64_static +UNIMPLEMENTED art_quick_get_obj_static +UNIMPLEMENTED art_quick_proxy_invoke_handler + + /* + * Called to resolve an imt conflict. + */ +UNIMPLEMENTED art_quick_imt_conflict_trampoline +UNIMPLEMENTED art_quick_resolution_trampoline +UNIMPLEMENTED art_quick_to_interpreter_bridge + + /* + * Routine that intercepts method calls and returns. + */ +UNIMPLEMENTED art_quick_instrumentation_entry +UNIMPLEMENTED art_quick_instrumentation_exit + + /* + * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization + * will long jump to the upcall with a special exception of -1. + */ +UNIMPLEMENTED art_quick_deoptimize + +UNIMPLEMENTED art_quick_indexof +UNIMPLEMENTED art_quick_string_compareto +UNIMPLEMENTED art_quick_memcmp16 diff --git a/runtime/arch/x86_64/registers_x86_64.cc b/runtime/arch/x86_64/registers_x86_64.cc new file mode 100644 index 0000000000..38f3494502 --- /dev/null +++ b/runtime/arch/x86_64/registers_x86_64.cc @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 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 "registers_x86_64.h" + +#include <ostream> + +namespace art { +namespace x86_64 { + +static const char* kRegisterNames[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs) { + if (rhs >= RAX && rhs <= R15) { + os << kRegisterNames[rhs]; + } else { + os << "Register[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +} // namespace x86_64 +} // namespace art diff --git a/runtime/arch/x86_64/registers_x86_64.h b/runtime/arch/x86_64/registers_x86_64.h new file mode 100644 index 0000000000..9808d910b9 --- /dev/null +++ b/runtime/arch/x86_64/registers_x86_64.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_64_REGISTERS_X86_64_H_ +#define ART_RUNTIME_ARCH_X86_64_REGISTERS_X86_64_H_ + +#include <iosfwd> + +#include "base/logging.h" +#include "base/macros.h" +#include "globals.h" + +namespace art { +namespace x86_64 { + +enum Register { + RAX = 0, + RCX = 1, + RDX = 2, + RBX = 3, + RSP = 4, + RBP = 5, + RSI = 6, + RDI = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + kNumberOfCpuRegisters = 16, + kNoRegister = -1 // Signals an illegal register. +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs); + +} // namespace x86_64 +} // namespace art + +#endif // ART_RUNTIME_ARCH_X86_64_REGISTERS_X86_64_H_ diff --git a/runtime/arch/x86_64/thread_x86_64.cc b/runtime/arch/x86_64/thread_x86_64.cc new file mode 100644 index 0000000000..9e45a72e4b --- /dev/null +++ b/runtime/arch/x86_64/thread_x86_64.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 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 "thread.h" + +#include "asm_support_x86_64.h" +#include "base/macros.h" +#include "thread-inl.h" +#include "thread_list.h" + +#include <asm/prctl.h> +#include <sys/prctl.h> +#include <sys/syscall.h> + +namespace art { + +static void arch_prctl(int code, void* val) { + syscall(__NR_arch_prctl, code, val); +} +void Thread::InitCpu() { + static Mutex modify_ldt_lock("modify_ldt lock"); + MutexLock mu(Thread::Current(), modify_ldt_lock); + arch_prctl(ARCH_SET_GS, this); + + // Allow easy indirection back to Thread*. + self_ = this; + + // Sanity check that reads from %gs point to this Thread*. + Thread* self_check; + CHECK_EQ(THREAD_SELF_OFFSET, OFFSETOF_MEMBER(Thread, self_)); + __asm__ __volatile__("movq %%gs:(%1), %0" + : "=r"(self_check) // output + : "r"(THREAD_SELF_OFFSET) // input + :); // clobber + CHECK_EQ(self_check, this); + + // Sanity check other offsets. + CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_)); + CHECK_EQ(THREAD_CARD_TABLE_OFFSET, OFFSETOF_MEMBER(Thread, card_table_)); + CHECK_EQ(THREAD_ID_OFFSET, OFFSETOF_MEMBER(Thread, thin_lock_thread_id_)); +} + +void Thread::CleanupCpu() { + // Sanity check that reads from %gs point to this Thread*. + Thread* self_check; + CHECK_EQ(THREAD_SELF_OFFSET, OFFSETOF_MEMBER(Thread, self_)); + __asm__ __volatile__("movq %%gs:(%1), %0" + : "=r"(self_check) // output + : "r"(THREAD_SELF_OFFSET) // input + :); // clobber + CHECK_EQ(self_check, this); + + // Do nothing. +} + +} // namespace art diff --git a/runtime/asm_support.h b/runtime/asm_support.h index 06c7b53a66..4c4209966d 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -40,6 +40,7 @@ // Offsets within java.lang.Method. #define METHOD_DEX_CACHE_METHODS_OFFSET 12 -#define METHOD_CODE_OFFSET 36 +#define METHOD_PORTABLE_CODE_OFFSET 40 +#define METHOD_QUICK_CODE_OFFSET 48 #endif // ART_RUNTIME_ASM_SUPPORT_H_ diff --git a/runtime/atomic.cc b/runtime/atomic.cc index bac0a992c4..63f2cf88bf 100644 --- a/runtime/atomic.cc +++ b/runtime/atomic.cc @@ -24,7 +24,7 @@ namespace art { std::vector<Mutex*>* QuasiAtomic::gSwapMutexes = nullptr; Mutex* QuasiAtomic::GetSwapMutex(const volatile int64_t* addr) { - return (*gSwapMutexes)[(reinterpret_cast<unsigned>(addr) >> 3U) % kSwapMutexCount]; + return (*gSwapMutexes)[(reinterpret_cast<uintptr_t>(addr) >> 3U) % kSwapMutexCount]; } void QuasiAtomic::Startup() { diff --git a/runtime/atomic.h b/runtime/atomic.h index b1e9870acf..2a47e46137 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -26,6 +26,69 @@ namespace art { class Mutex; +template<typename T> +class Atomic { + public: + Atomic<T>() : value_(0) { } + + explicit Atomic<T>(T value) : value_(value) { } + + Atomic<T>& operator=(T desired) { + Store(desired); + return *this; + } + + T Load() const { + return value_; + } + + operator T() const { + return Load(); + } + + T FetchAndAdd(const T value) { + return __sync_fetch_and_add(&value_, value); // Return old_value. + } + + T FetchAndSub(const T value) { + return __sync_fetch_and_sub(&value_, value); // Return old value. + } + + T operator++() { // Prefix operator. + return __sync_add_and_fetch(&value_, 1); // Return new value. + } + + T operator++(int) { // Postfix operator. + return __sync_fetch_and_add(&value_, 1); // Return old value. + } + + T operator--() { // Prefix operator. + return __sync_sub_and_fetch(&value_, 1); // Return new value. + } + + T operator--(int) { // Postfix operator. + return __sync_fetch_and_sub(&value_, 1); // Return old value. + } + + bool CompareAndSwap(T expected_value, T desired_value) { + return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); + } + + volatile T* Address() { + return &value_; + } + + private: + // Unsafe = operator for non atomic operations on the integer. + void Store(T desired) { + value_ = desired; + } + + volatile T value_; +}; + +typedef Atomic<int32_t> AtomicInteger; + // NOTE: Two "quasiatomic" operations on the exact same memory address // are guaranteed to operate atomically with respect to each other, // but no guarantees are made about quasiatomic operations mixed with @@ -80,7 +143,7 @@ class QuasiAtomic { static void MembarLoadStore() { #if defined(__arm__) __asm__ __volatile__("dmb ish" : : : "memory"); - #elif defined(__i386__) + #elif defined(__i386__) || defined(__x86_64__) __asm__ __volatile__("" : : : "memory"); #elif defined(__mips__) __asm__ __volatile__("sync" : : : "memory"); @@ -92,7 +155,7 @@ class QuasiAtomic { static void MembarLoadLoad() { #if defined(__arm__) __asm__ __volatile__("dmb ish" : : : "memory"); - #elif defined(__i386__) + #elif defined(__i386__) || defined(__x86_64__) __asm__ __volatile__("" : : : "memory"); #elif defined(__mips__) __asm__ __volatile__("sync" : : : "memory"); @@ -104,7 +167,7 @@ class QuasiAtomic { static void MembarStoreStore() { #if defined(__arm__) __asm__ __volatile__("dmb ishst" : : : "memory"); - #elif defined(__i386__) + #elif defined(__i386__) || defined(__x86_64__) __asm__ __volatile__("" : : : "memory"); #elif defined(__mips__) __asm__ __volatile__("sync" : : : "memory"); @@ -116,7 +179,7 @@ class QuasiAtomic { static void MembarStoreLoad() { #if defined(__arm__) __asm__ __volatile__("dmb ish" : : : "memory"); - #elif defined(__i386__) + #elif defined(__i386__) || defined(__x86_64__) __asm__ __volatile__("mfence" : : : "memory"); #elif defined(__mips__) __asm__ __volatile__("sync" : : : "memory"); diff --git a/runtime/atomic_integer.h b/runtime/atomic_integer.h deleted file mode 100644 index 651ca4a6e9..0000000000 --- a/runtime/atomic_integer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -#ifndef ART_RUNTIME_ATOMIC_INTEGER_H_ -#define ART_RUNTIME_ATOMIC_INTEGER_H_ - -#include <stdint.h> - -namespace art { - -class AtomicInteger { - public: - AtomicInteger() : value_(0) { } - - explicit AtomicInteger(int32_t value) : value_(value) { } - - AtomicInteger& operator=(int32_t desired) { - Store(desired); - return *this; - } - - int32_t Load() const { - return value_; - } - - operator int32_t() const { - return Load(); - } - - int32_t FetchAndAdd(const int32_t value) { - return __sync_fetch_and_add(&value_, value); // Return old_value. - } - - int32_t FetchAndSub(const int32_t value) { - return __sync_fetch_and_sub(&value_, value); // Return old value. - } - - int32_t operator++() { // Prefix operator. - return __sync_add_and_fetch(&value_, 1); // Return new value. - } - - int32_t operator++(int32_t) { // Postfix operator. - return __sync_fetch_and_add(&value_, 1); // Return old value. - } - - int32_t operator--() { // Prefix operator. - return __sync_sub_and_fetch(&value_, 1); // Return new value. - } - - int32_t operator--(int32_t) { // Postfix operator. - return __sync_fetch_and_sub(&value_, 1); // Return old value. - } - - bool CompareAndSwap(int32_t expected_value, int32_t desired_value) { - return __sync_bool_compare_and_swap(&value_, expected_value, desired_value); - } - - volatile int32_t* Address() { - return &value_; - } - - private: - // Unsafe = operator for non atomic operations on the integer. - void Store(int32_t desired) { - value_ = desired; - } - - volatile int32_t value_; -}; - -} // namespace art - -#endif // ART_RUNTIME_ATOMIC_INTEGER_H_ diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index 91fc143dbe..69951c5800 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -18,7 +18,7 @@ #include <string> -#include "atomic_integer.h" +#include "atomic.h" #include "common_test.h" #include "mirror/object_array-inl.h" #include "thread_pool.h" diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc index d99d059e0f..3fc9b8604b 100644 --- a/runtime/base/bit_vector_test.cc +++ b/runtime/base/bit_vector_test.cc @@ -25,7 +25,7 @@ TEST(BitVector, Test) { BitVector bv(kBits, false, Allocator::GetMallocAllocator()); EXPECT_EQ(1U, bv.GetStorageSize()); - EXPECT_EQ(kWordSize, bv.GetSizeOf()); + EXPECT_EQ(sizeof(uint32_t), bv.GetSizeOf()); EXPECT_FALSE(bv.IsExpandable()); EXPECT_EQ(0U, bv.NumSetBits()); @@ -70,7 +70,7 @@ TEST(BitVector, NoopAllocator) { BitVector bv(0U, false, Allocator::GetNoopAllocator(), kWords, bits); EXPECT_EQ(kWords, bv.GetStorageSize()); - EXPECT_EQ(kWords * kWordSize, bv.GetSizeOf()); + EXPECT_EQ(kWords * sizeof(uint32_t), bv.GetSizeOf()); EXPECT_EQ(bits, bv.GetRawStorage()); EXPECT_EQ(0U, bv.NumSetBits()); diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 05e3a8327e..ff72d16908 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -47,7 +47,7 @@ static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, co struct AllMutexData { // A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait). - AtomicInteger all_mutexes_guard; + Atomic<const BaseMutex*> all_mutexes_guard; // All created mutexes guarded by all_mutexes_guard_. std::set<BaseMutex*>* all_mutexes; AllMutexData() : all_mutexes(NULL) {} @@ -57,12 +57,12 @@ static struct AllMutexData gAllMutexData[kAllMutexDataSize]; class ScopedAllMutexesLock { public: explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) { - while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(0, reinterpret_cast<int32_t>(mutex))) { + while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(0, mutex)) { NanoSleep(100); } } ~ScopedAllMutexesLock() { - while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(reinterpret_cast<int32_t>(mutex_), 0)) { + while (!gAllMutexData->all_mutexes_guard.CompareAndSwap(mutex_, 0)) { NanoSleep(100); } } diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 1c1dcaf43f..63ed6cbe2f 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -23,7 +23,7 @@ #include <iosfwd> #include <string> -#include "atomic_integer.h" +#include "atomic.h" #include "base/logging.h" #include "base/macros.h" #include "globals.h" diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index f48c76db23..87d1c0655d 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -102,11 +102,11 @@ bool FdFile::IsOpened() const { return fd_ >= 0; } -bool FdFile::ReadFully(void* buffer, int64_t byte_count) { +bool FdFile::ReadFully(void* buffer, size_t byte_count) { char* ptr = static_cast<char*>(buffer); while (byte_count > 0) { - int bytes_read = TEMP_FAILURE_RETRY(read(fd_, ptr, byte_count)); - if (bytes_read <= 0) { + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd_, ptr, byte_count)); + if (bytes_read == -1) { return false; } byte_count -= bytes_read; // Reduce the number of remaining bytes. @@ -115,15 +115,15 @@ bool FdFile::ReadFully(void* buffer, int64_t byte_count) { return true; } -bool FdFile::WriteFully(const void* buffer, int64_t byte_count) { +bool FdFile::WriteFully(const void* buffer, size_t byte_count) { const char* ptr = static_cast<const char*>(buffer); while (byte_count > 0) { - int bytes_read = TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); - if (bytes_read < 0) { + ssize_t bytes_written = TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); + if (bytes_written == -1) { return false; } - byte_count -= bytes_read; // Reduce the number of remaining bytes. - ptr += bytes_read; // Move the buffer forward. + byte_count -= bytes_written; // Reduce the number of remaining bytes. + ptr += bytes_written; // Move the buffer forward. } return true; } diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h index 19e3511eb4..01f4ca2819 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/runtime/base/unix_file/fd_file.h @@ -61,8 +61,8 @@ class FdFile : public RandomAccessFile { return file_path_; } void DisableAutoClose(); - bool ReadFully(void* buffer, int64_t byte_count); - bool WriteFully(const void* buffer, int64_t byte_count); + bool ReadFully(void* buffer, size_t byte_count); + bool WriteFully(const void* buffer, size_t byte_count); private: int fd_; diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc index b63fdd3bef..bc23a745c9 100644 --- a/runtime/base/unix_file/mapped_file.cc +++ b/runtime/base/unix_file/mapped_file.cc @@ -101,7 +101,8 @@ int64_t MappedFile::Read(char* buf, int64_t byte_count, int64_t offset) const { errno = EINVAL; return -errno; } - int64_t read_size = std::max(0LL, std::min(byte_count, file_size_ - offset)); + int64_t read_size = std::max(static_cast<int64_t>(0), + std::min(byte_count, file_size_ - offset)); if (read_size > 0) { memcpy(buf, data() + offset, read_size); } @@ -136,7 +137,8 @@ int64_t MappedFile::Write(const char* buf, int64_t byte_count, int64_t offset) { errno = EINVAL; return -errno; } - int64_t write_size = std::max(0LL, std::min(byte_count, file_size_ - offset)); + int64_t write_size = std::max(static_cast<int64_t>(0), + std::min(byte_count, file_size_ - offset)); if (write_size > 0) { memcpy(data() + offset, buf, write_size); } diff --git a/runtime/base/unix_file/mapped_file_test.cc b/runtime/base/unix_file/mapped_file_test.cc index 3dda02f59f..49750f446d 100644 --- a/runtime/base/unix_file/mapped_file_test.cc +++ b/runtime/base/unix_file/mapped_file_test.cc @@ -65,7 +65,7 @@ TEST_F(MappedFileTest, OpenClose) { ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); EXPECT_GE(file.Fd(), 0); EXPECT_TRUE(file.IsOpened()); - EXPECT_EQ(kContent.size(), file.size()); + EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size())); EXPECT_EQ(0, file.Close()); EXPECT_EQ(-1, file.Fd()); EXPECT_FALSE(file.IsOpened()); @@ -86,7 +86,7 @@ TEST_F(MappedFileTest, CanUseAfterMapReadOnly) { EXPECT_FALSE(file.IsMapped()); EXPECT_TRUE(file.MapReadOnly()); EXPECT_TRUE(file.IsMapped()); - EXPECT_EQ(kContent.size(), file.size()); + EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size())); ASSERT_TRUE(file.data()); EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size())); EXPECT_EQ(0, file.Flush()); @@ -113,7 +113,7 @@ TEST_F(MappedFileTest, CanWriteNewData) { ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode)); EXPECT_TRUE(file.MapReadWrite(kContent.size())); EXPECT_TRUE(file.IsMapped()); - EXPECT_EQ(kContent.size(), file.size()); + EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size())); ASSERT_TRUE(file.data()); memcpy(file.data(), kContent.c_str(), kContent.size()); EXPECT_EQ(0, file.Close()); @@ -200,15 +200,16 @@ TEST_F(MappedFileTest, WriteMappedReadWrite) { // A zero-length write is a no-op. EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0)); // But the file size is as given when mapped. - EXPECT_EQ(kContent.size(), file.GetLength()); + EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.GetLength())); // Data written past the end are discarded. EXPECT_EQ(kContent.size() - 1, - file.Write(kContent.c_str(), kContent.size(), 1)); + static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 1))); EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1)); // Data can be overwritten. - EXPECT_EQ(kContent.size(), file.Write(kContent.c_str(), kContent.size(), 0)); + EXPECT_EQ(kContent.size(), + static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 0))); EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size())); } diff --git a/runtime/base/unix_file/null_file_test.cc b/runtime/base/unix_file/null_file_test.cc index 0f20acd825..410fdfc28e 100644 --- a/runtime/base/unix_file/null_file_test.cc +++ b/runtime/base/unix_file/null_file_test.cc @@ -48,7 +48,7 @@ TEST_F(NullFileTest, GetLength) { NullFile f; // The length is always 0. ASSERT_EQ(0, f.GetLength()); - ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 0)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 0))); ASSERT_EQ(0, f.GetLength()); } @@ -58,8 +58,8 @@ TEST_F(NullFileTest, Write) { // You can't write at a negative offset... ASSERT_EQ(-EINVAL, f.Write(content.data(), content.size(), -128)); // But you can write anywhere else... - ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 0)); - ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 128)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 0))); + ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 128))); // ...though the file will remain empty. ASSERT_EQ(0, f.GetLength()); } diff --git a/runtime/base/unix_file/random_access_file_test.h b/runtime/base/unix_file/random_access_file_test.h index 9d8550d6f6..31527888c7 100644 --- a/runtime/base/unix_file/random_access_file_test.h +++ b/runtime/base/unix_file/random_access_file_test.h @@ -71,7 +71,7 @@ class RandomAccessFileTest : public testing::Test { ASSERT_EQ(0, file->Read(buf, 123, 0)); const std::string content("hello"); - ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Write(content.data(), content.size(), 0))); TestReadContent(content, file.get()); } @@ -83,21 +83,21 @@ class RandomAccessFileTest : public testing::Test { ASSERT_EQ(-EINVAL, file->Read(buf.get(), 0, -123)); // Reading too much gets us just what's in the file. - ASSERT_EQ(content.size(), file->Read(buf.get(), buf_size, 0)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Read(buf.get(), buf_size, 0))); ASSERT_EQ(std::string(buf.get(), content.size()), content); // We only get as much as we ask for. const size_t short_request = 2; ASSERT_LT(short_request, content.size()); - ASSERT_EQ(short_request, file->Read(buf.get(), short_request, 0)); + ASSERT_EQ(short_request, static_cast<uint64_t>(file->Read(buf.get(), short_request, 0))); ASSERT_EQ(std::string(buf.get(), short_request), content.substr(0, short_request)); // We don't have to start at the beginning. const int non_zero_offset = 2; ASSERT_GT(non_zero_offset, 0); - ASSERT_EQ(short_request, - file->Read(buf.get(), short_request, non_zero_offset)); + ASSERT_EQ(short_request, static_cast<uint64_t>(file->Read(buf.get(), short_request, + non_zero_offset))); ASSERT_EQ(std::string(buf.get(), short_request), content.substr(non_zero_offset, short_request)); @@ -109,8 +109,8 @@ class RandomAccessFileTest : public testing::Test { void TestSetLength() { const std::string content("hello"); UniquePtr<RandomAccessFile> file(MakeTestFile()); - ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); - ASSERT_EQ(content.size(), file->GetLength()); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Write(content.data(), content.size(), 0))); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->GetLength())); // Can't give a file a negative length. ASSERT_EQ(-EINVAL, file->SetLength(-123)); @@ -143,20 +143,20 @@ class RandomAccessFileTest : public testing::Test { ASSERT_EQ(0, file->GetLength()); // We can write data. - ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); - ASSERT_EQ(content.size(), file->GetLength()); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Write(content.data(), content.size(), 0))); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->GetLength())); std::string new_content; ASSERT_TRUE(ReadString(file.get(), &new_content)); ASSERT_EQ(new_content, content); // We can read it back. char buf[256]; - ASSERT_EQ(content.size(), file->Read(buf, sizeof(buf), 0)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Read(buf, sizeof(buf), 0))); ASSERT_EQ(std::string(buf, content.size()), content); // We can append data past the end. - ASSERT_EQ(content.size(), - file->Write(content.data(), content.size(), file->GetLength() + 1)); + ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Write(content.data(), content.size(), + file->GetLength() + 1))); int64_t new_length = 2*content.size() + 1; ASSERT_EQ(file->GetLength(), new_length); ASSERT_TRUE(ReadString(file.get(), &new_content)); diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index 1b79ee0c81..960c26dfde 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -40,23 +40,23 @@ namespace art { static void JniAbort(const char* jni_function_name, const char* msg) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); - mirror::ArtMethod* current_method = self->GetCurrentMethod(NULL); + mirror::ArtMethod* current_method = self->GetCurrentMethod(nullptr); std::ostringstream os; os << "JNI DETECTED ERROR IN APPLICATION: " << msg; - if (jni_function_name != NULL) { + if (jni_function_name != nullptr) { os << "\n in call to " << jni_function_name; } // TODO: is this useful given that we're about to dump the calling thread's stack? - if (current_method != NULL) { + if (current_method != nullptr) { os << "\n from " << PrettyMethod(current_method); } os << "\n"; self->Dump(os); JavaVMExt* vm = Runtime::Current()->GetJavaVM(); - if (vm->check_jni_abort_hook != NULL) { + if (vm->check_jni_abort_hook != nullptr) { vm->check_jni_abort_hook(vm->check_jni_abort_hook_data, os.str()); } else { // Ensure that we get a native stack trace for this thread. @@ -118,10 +118,10 @@ static const char* gBuiltInPrefixes[] = { "Ljavax/", "Llibcore/", "Lorg/apache/harmony/", - NULL + nullptr }; -static bool ShouldTrace(JavaVMExt* vm, const mirror::ArtMethod* method) +static bool ShouldTrace(JavaVMExt* vm, mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages // when a native method that matches the -Xjnitrace argument calls a JNI function @@ -135,7 +135,7 @@ static bool ShouldTrace(JavaVMExt* vm, const mirror::ArtMethod* method) if (VLOG_IS_ON(third_party_jni)) { // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look // like part of Android. - for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) { + for (size_t i = 0; gBuiltInPrefixes[i] != nullptr; ++i) { if (StartsWith(class_name, gBuiltInPrefixes[i])) { return false; } @@ -192,15 +192,16 @@ class ScopedCheck { * * Works for both static and instance fields. */ - void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) + void CheckFieldType(jvalue value, jfieldID fid, char prim, bool isStatic) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* f = CheckFieldID(fid); - if (f == NULL) { + if (f == nullptr) { return; } mirror::Class* field_type = FieldHelper(f).GetType(); if (!field_type->IsPrimitive()) { - if (java_object != NULL) { + jobject java_object = value.l; + if (java_object != nullptr) { mirror::Object* obj = soa_.Decode<mirror::Object*>(java_object); // If java_object is a weak global ref whose referent has been cleared, // obj will be NULL. Otherwise, obj should always be non-NULL @@ -242,7 +243,7 @@ class ScopedCheck { void CheckInstanceFieldID(jobject java_object, jfieldID fid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::Object* o = soa_.Decode<mirror::Object*>(java_object); - if (o == NULL || !Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) { + if (o == nullptr || !Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) { Runtime::Current()->GetHeap()->DumpSpaces(); JniAbortF(function_name_, "field operation on invalid %s: %p", ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(), java_object); @@ -250,12 +251,12 @@ class ScopedCheck { } mirror::ArtField* f = CheckFieldID(fid); - if (f == NULL) { + if (f == nullptr) { return; } mirror::Class* c = o->GetClass(); FieldHelper fh(f); - if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) { + if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == nullptr) { JniAbortF(function_name_, "jfieldID %s not valid for an object of class %s", PrettyField(f).c_str(), PrettyTypeOf(o).c_str()); } @@ -265,7 +266,7 @@ class ScopedCheck { * Verify that the pointer value is non-NULL. */ void CheckNonNull(const void* ptr) { - if (ptr == NULL) { + if (ptr == nullptr) { JniAbortF(function_name_, "non-nullable argument was NULL"); } } @@ -277,7 +278,7 @@ class ScopedCheck { void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* m = CheckMethodID(mid); - if (m == NULL) { + if (m == nullptr) { return; } if (*expectedType != MethodHelper(m).GetShorty()[0]) { @@ -303,8 +304,8 @@ class ScopedCheck { void CheckStaticFieldID(jclass java_class, jfieldID fid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::Class* c = soa_.Decode<mirror::Class*>(java_class); - const mirror::ArtField* f = CheckFieldID(fid); - if (f == NULL) { + mirror::ArtField* f = CheckFieldID(fid); + if (f == nullptr) { return; } if (f->GetDeclaringClass() != c) { @@ -324,8 +325,8 @@ class ScopedCheck { */ void CheckStaticMethod(jclass java_class, jmethodID mid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const mirror::ArtMethod* m = CheckMethodID(mid); - if (m == NULL) { + mirror::ArtMethod* m = CheckMethodID(mid); + if (m == nullptr) { return; } mirror::Class* c = soa_.Decode<mirror::Class*>(java_class); @@ -344,8 +345,8 @@ class ScopedCheck { */ void CheckVirtualMethod(jobject java_object, jmethodID mid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const mirror::ArtMethod* m = CheckMethodID(mid); - if (m == NULL) { + mirror::ArtMethod* m = CheckMethodID(mid); + if (m == nullptr) { return; } mirror::Object* o = soa_.Decode<mirror::Object*>(java_object); @@ -394,17 +395,18 @@ class ScopedCheck { void Check(bool entry, const char* fmt0, ...) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { va_list ap; - const mirror::ArtMethod* traceMethod = NULL; + mirror::ArtMethod* traceMethod = nullptr; if (has_method_ && (!soa_.Vm()->trace.empty() || VLOG_IS_ON(third_party_jni))) { // We need to guard some of the invocation interface's calls: a bad caller might // use DetachCurrentThread or GetEnv on a thread that's not yet attached. Thread* self = Thread::Current(); - if ((flags_ & kFlag_Invocation) == 0 || self != NULL) { - traceMethod = self->GetCurrentMethod(NULL); + if ((flags_ & kFlag_Invocation) == 0 || self != nullptr) { + traceMethod = self->GetCurrentMethod(nullptr); } } - if (((flags_ & kFlag_ForceTrace) != 0) || (traceMethod != NULL && ShouldTrace(soa_.Vm(), traceMethod))) { + if (((flags_ & kFlag_ForceTrace) != 0) || + (traceMethod != nullptr && ShouldTrace(soa_.Vm(), traceMethod))) { va_start(ap, fmt0); std::string msg; for (const char* fmt = fmt0; *fmt;) { @@ -428,7 +430,7 @@ class ScopedCheck { } else if (ch == 'I' || ch == 'S') { // jint, jshort StringAppendF(&msg, "%d", va_arg(ap, int)); } else if (ch == 'J') { // jlong - StringAppendF(&msg, "%lld", va_arg(ap, jlong)); + StringAppendF(&msg, "%" PRId64, va_arg(ap, jlong)); } else if (ch == 'Z') { // jboolean StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false"); } else if (ch == 'V') { // void @@ -442,7 +444,7 @@ class ScopedCheck { } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring // For logging purposes, these are identical. jobject o = va_arg(ap, jobject); - if (o == NULL) { + if (o == nullptr) { msg += "NULL"; } else { StringAppendF(&msg, "%p", o); @@ -453,7 +455,7 @@ class ScopedCheck { } else if (ch == 'c') { // jclass jclass jc = va_arg(ap, jclass); mirror::Class* c = reinterpret_cast<mirror::Class*>(Thread::Current()->DecodeJObject(jc)); - if (c == NULL) { + if (c == nullptr) { msg += "NULL"; } else if (c == kInvalidIndirectRefObject || !Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) { @@ -488,7 +490,7 @@ class ScopedCheck { } } else if (ch == 'p') { // void* ("pointer") void* p = va_arg(ap, void*); - if (p == NULL) { + if (p == nullptr) { msg += "NULL"; } else { StringAppendF(&msg, "(void*) %p", p); @@ -506,7 +508,7 @@ class ScopedCheck { } } else if (ch == 'u') { // const char* (Modified UTF-8) const char* utf = va_arg(ap, const char*); - if (utf == NULL) { + if (utf == nullptr) { msg += "NULL"; } else { StringAppendF(&msg, "\"%s\"", utf); @@ -563,7 +565,7 @@ class ScopedCheck { } } else if (ch == 'z') { CheckLengthPositive(va_arg(ap, jsize)); - } else if (strchr("BCISZbfmpEv", ch) != NULL) { + } else if (strchr("BCISZbfmpEv", ch) != nullptr) { va_arg(ap, uint32_t); // Skip this argument. } else if (ch == 'D' || ch == 'F') { va_arg(ap, double); // Skip this argument. @@ -595,7 +597,7 @@ class ScopedCheck { */ bool CheckInstance(InstanceKind kind, jobject java_object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* what = NULL; + const char* what = nullptr; switch (kind) { case kClass: what = "jclass"; @@ -616,7 +618,7 @@ class ScopedCheck { LOG(FATAL) << "Unknown kind " << static_cast<int>(kind); } - if (java_object == NULL) { + if (java_object == nullptr) { JniAbortF(function_name_, "%s received null %s", function_name_, what); return false; } @@ -670,7 +672,7 @@ class ScopedCheck { * Since we're dealing with objects, switch to "running" mode. */ void CheckArray(jarray java_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (java_array == NULL) { + if (java_array == nullptr) { JniAbortF(function_name_, "jarray was NULL"); return; } @@ -692,29 +694,29 @@ class ScopedCheck { } mirror::ArtField* CheckFieldID(jfieldID fid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (fid == NULL) { + if (fid == nullptr) { JniAbortF(function_name_, "jfieldID was NULL"); - return NULL; + return nullptr; } mirror::ArtField* f = soa_.DecodeField(fid); if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(f) || !f->IsArtField()) { Runtime::Current()->GetHeap()->DumpSpaces(); JniAbortF(function_name_, "invalid jfieldID: %p", fid); - return NULL; + return nullptr; } return f; } mirror::ArtMethod* CheckMethodID(jmethodID mid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (mid == NULL) { + if (mid == nullptr) { JniAbortF(function_name_, "jmethodID was NULL"); - return NULL; + return nullptr; } mirror::ArtMethod* m = soa_.DecodeMethod(mid); if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(m) || !m->IsArtMethod()) { Runtime::Current()->GetHeap()->DumpSpaces(); JniAbortF(function_name_, "invalid jmethodID: %p", mid); - return NULL; + return nullptr; } return m; } @@ -727,7 +729,7 @@ class ScopedCheck { */ void CheckObject(jobject java_object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (java_object == NULL) { + if (java_object == nullptr) { return; } @@ -752,7 +754,7 @@ class ScopedCheck { void CheckThread(int flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Thread* self = Thread::Current(); - if (self == NULL) { + if (self == nullptr) { JniAbortF(function_name_, "a thread (tid %d) is making JNI calls without being attached", GetTid()); return; } @@ -813,7 +815,7 @@ class ScopedCheck { // Verifies that "bytes" points to valid Modified UTF-8 data. void CheckUtfString(const char* bytes, bool nullable) { - if (bytes == NULL) { + if (bytes == nullptr) { if (!nullable) { JniAbortF(function_name_, "non-nullable const char* was NULL"); return; @@ -821,9 +823,9 @@ class ScopedCheck { return; } - const char* errorKind = NULL; + const char* errorKind = nullptr; uint8_t utf8 = CheckUtfBytes(bytes, &errorKind); - if (errorKind != NULL) { + if (errorKind != nullptr) { JniAbortF(function_name_, "input is not valid Modified UTF-8: illegal %s byte %#x\n" " string: '%s'", errorKind, utf8, bytes); @@ -998,7 +1000,7 @@ struct GuardedCopy { const uint16_t* pat = reinterpret_cast<const uint16_t*>(fullBuf); for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) { if (pat[i] != kGuardPattern) { - JniAbortF(functionName, "guard pattern(1) disturbed at %p +%d", fullBuf, i*2); + JniAbortF(functionName, "guard pattern(1) disturbed at %p +%zd", fullBuf, i*2); } } @@ -1018,7 +1020,7 @@ struct GuardedCopy { pat = reinterpret_cast<const uint16_t*>(fullBuf + offset); for (size_t i = 0; i < kGuardLen / 4; i++) { if (pat[i] != kGuardPattern) { - JniAbortF(functionName, "guard pattern(2) disturbed at %p +%d", fullBuf, offset + i*2); + JniAbortF(functionName, "guard pattern(2) disturbed at %p +%zd", fullBuf, offset + i*2); } } @@ -1037,7 +1039,7 @@ struct GuardedCopy { private: static uint8_t* DebugAlloc(size_t len) { - void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + void* result = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (result == MAP_FAILED) { PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed"; } @@ -1081,8 +1083,8 @@ static void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* mirror::Array* a = soa.Decode<mirror::Array*>(java_array); size_t component_size = a->GetClass()->GetComponentSize(); size_t byte_count = a->GetLength() * component_size; - void* result = GuardedCopy::Create(a->GetRawData(component_size), byte_count, true); - if (isCopy != NULL) { + void* result = GuardedCopy::Create(a->GetRawData(component_size, 0), byte_count, true); + if (isCopy != nullptr) { *isCopy = JNI_TRUE; } return result; @@ -1100,7 +1102,7 @@ static void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, if (mode != JNI_ABORT) { size_t len = GuardedCopy::FromData(dataBuf)->original_length; - memcpy(a->GetRawData(a->GetClass()->GetComponentSize()), dataBuf, len); + memcpy(a->GetRawData(a->GetClass()->GetComponentSize(), 0), dataBuf, len); } if (mode != JNI_COMMIT) { GuardedCopy::Destroy(dataBuf); @@ -1223,7 +1225,7 @@ class CheckJNI { static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) { CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef); - if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) { + if (globalRef != nullptr && GetIndirectRefKind(globalRef) != kGlobal) { JniAbortF(__FUNCTION__, "DeleteGlobalRef on %s: %p", ToStr<IndirectRefKind>(GetIndirectRefKind(globalRef)).c_str(), globalRef); } else { @@ -1234,7 +1236,7 @@ class CheckJNI { static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) { CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef); - if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) { + if (weakGlobalRef != nullptr && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) { JniAbortF(__FUNCTION__, "DeleteWeakGlobalRef on %s: %p", ToStr<IndirectRefKind>(GetIndirectRefKind(weakGlobalRef)).c_str(), weakGlobalRef); } else { @@ -1245,7 +1247,7 @@ class CheckJNI { static void DeleteLocalRef(JNIEnv* env, jobject localRef) { CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef); - if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) { + if (localRef != nullptr && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) { JniAbortF(__FUNCTION__, "DeleteLocalRef on %s: %p", ToStr<IndirectRefKind>(GetIndirectRefKind(localRef)).c_str(), localRef); } else { @@ -1318,7 +1320,7 @@ class CheckJNI { return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, c, name, sig)); } -#define FIELD_ACCESSORS(_ctype, _jname, _type) \ +#define FIELD_ACCESSORS(_ctype, _jname, _jvalue_type, _type) \ static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass c, jfieldID fid) { \ CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, c, fid); \ sc.CheckStaticFieldID(c, fid); \ @@ -1333,7 +1335,9 @@ class CheckJNI { CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, c, fid, value); \ sc.CheckStaticFieldID(c, fid); \ /* "value" arg only used when type == ref */ \ - sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \ + jvalue java_type_value; \ + java_type_value._jvalue_type = value; \ + sc.CheckFieldType(java_type_value, fid, _type[0], true); \ baseEnv(env)->SetStatic##_jname##Field(env, c, fid, value); \ CHECK_JNI_EXIT_VOID(); \ } \ @@ -1341,20 +1345,22 @@ class CheckJNI { CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \ sc.CheckInstanceFieldID(obj, fid); \ /* "value" arg only used when type == ref */ \ - sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \ + jvalue java_type_value; \ + java_type_value._jvalue_type = value; \ + sc.CheckFieldType(java_type_value, fid, _type[0], false); \ baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \ CHECK_JNI_EXIT_VOID(); \ } -FIELD_ACCESSORS(jobject, Object, "L"); -FIELD_ACCESSORS(jboolean, Boolean, "Z"); -FIELD_ACCESSORS(jbyte, Byte, "B"); -FIELD_ACCESSORS(jchar, Char, "C"); -FIELD_ACCESSORS(jshort, Short, "S"); -FIELD_ACCESSORS(jint, Int, "I"); -FIELD_ACCESSORS(jlong, Long, "J"); -FIELD_ACCESSORS(jfloat, Float, "F"); -FIELD_ACCESSORS(jdouble, Double, "D"); +FIELD_ACCESSORS(jobject, Object, l, "L"); +FIELD_ACCESSORS(jboolean, Boolean, z, "Z"); +FIELD_ACCESSORS(jbyte, Byte, b, "B"); +FIELD_ACCESSORS(jchar, Char, c, "C"); +FIELD_ACCESSORS(jshort, Short, s, "S"); +FIELD_ACCESSORS(jint, Int, i, "I"); +FIELD_ACCESSORS(jlong, Long, j, "J"); +FIELD_ACCESSORS(jfloat, Float, f, "F"); +FIELD_ACCESSORS(jdouble, Double, d, "D"); #define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \ /* Virtual... */ \ @@ -1484,11 +1490,11 @@ CALL(void, Void, , , VOID_RETURN, "V"); static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) { CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy); const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy); - if (sc.ForceCopy() && result != NULL) { + if (sc.ForceCopy() && result != nullptr) { mirror::String* s = sc.soa().Decode<mirror::String*>(java_string); int byteCount = s->GetLength() * 2; result = (const jchar*) GuardedCopy::Create(result, byteCount, false); - if (isCopy != NULL) { + if (isCopy != nullptr) { *isCopy = JNI_TRUE; } } @@ -1519,9 +1525,9 @@ CALL(void, Void, , , VOID_RETURN, "V"); static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) { CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy); - if (sc.ForceCopy() && result != NULL) { + if (sc.ForceCopy() && result != nullptr) { result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false); - if (isCopy != NULL) { + if (isCopy != nullptr) { *isCopy = JNI_TRUE; } } @@ -1578,7 +1584,7 @@ struct ForceCopyGetChecker { ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) { force_copy = sc.ForceCopy(); no_copy = 0; - if (force_copy && isCopy != NULL) { + if (force_copy && isCopy != nullptr) { // Capture this before the base call tramples on it. no_copy = *reinterpret_cast<uint32_t*>(isCopy); } @@ -1586,7 +1592,7 @@ struct ForceCopyGetChecker { template<typename ResultT> ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) { - if (force_copy && result != NULL) { + if (force_copy && result != nullptr) { result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy)); } return result; @@ -1690,7 +1696,7 @@ PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) { CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy); void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy); - if (sc.ForceCopy() && result != NULL) { + if (sc.ForceCopy() && result != nullptr) { result = CreateGuardedPACopy(env, array, isCopy); } return CHECK_JNI_EXIT("p", result); @@ -1709,11 +1715,11 @@ PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) { CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy); const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy); - if (sc.ForceCopy() && result != NULL) { + if (sc.ForceCopy() && result != nullptr) { mirror::String* s = sc.soa().Decode<mirror::String*>(java_string); int byteCount = s->GetLength() * 2; result = (const jchar*) GuardedCopy::Create(result, byteCount, false); - if (isCopy != NULL) { + if (isCopy != nullptr) { *isCopy = JNI_TRUE; } } @@ -1751,11 +1757,11 @@ PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity); - if (address == NULL) { + if (address == nullptr) { JniAbortF(__FUNCTION__, "non-nullable address is NULL"); } if (capacity < 0) { - JniAbortF(__FUNCTION__, "capacity must be non-negative: %lld", capacity); + JniAbortF(__FUNCTION__, "capacity must be non-negative: %" PRId64, capacity); } return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity)); } @@ -1779,10 +1785,10 @@ PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); }; const JNINativeInterface gCheckNativeInterface = { - NULL, // reserved0. - NULL, // reserved1. - NULL, // reserved2. - NULL, // reserved3. + nullptr, // reserved0. + nullptr, // reserved1. + nullptr, // reserved2. + nullptr, // reserved3. CheckJNI::GetVersion, CheckJNI::DefineClass, CheckJNI::FindClass, @@ -2057,9 +2063,9 @@ class CheckJII { }; const JNIInvokeInterface gCheckInvokeInterface = { - NULL, // reserved0 - NULL, // reserved1 - NULL, // reserved2 + nullptr, // reserved0 + nullptr, // reserved1 + nullptr, // reserved2 CheckJII::DestroyJavaVM, CheckJII::AttachCurrentThread, CheckJII::DetachCurrentThread, diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 0436435e65..66c24b51d2 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -28,7 +28,7 @@ namespace art { inline mirror::String* ClassLinker::ResolveString(uint32_t string_idx, - const mirror::ArtMethod* referrer) { + mirror::ArtMethod* referrer) { mirror::String* resolved_string = referrer->GetDexCacheStrings()->Get(string_idx); if (UNLIKELY(resolved_string == NULL)) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); @@ -40,7 +40,7 @@ inline mirror::String* ClassLinker::ResolveString(uint32_t string_idx, } inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, - const mirror::ArtMethod* referrer) { + mirror::ArtMethod* referrer) { mirror::Class* resolved_type = referrer->GetDexCacheResolvedTypes()->Get(type_idx); if (UNLIKELY(resolved_type == NULL)) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); @@ -53,7 +53,7 @@ inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, return resolved_type; } -inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, const mirror::ArtField* referrer) { +inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, mirror::ArtField* referrer) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache(); mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx); @@ -68,7 +68,7 @@ inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, const mirror:: } inline mirror::ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, InvokeType type) { mirror::ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethods()->Get(method_idx); @@ -84,7 +84,7 @@ inline mirror::ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, } inline mirror::ArtField* ClassLinker::ResolveField(uint32_t field_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, bool is_static) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); mirror::ArtField* resolved_field = diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f1f5905579..978c99bf1a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -712,11 +712,11 @@ const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location, return nullptr; } - uint32_t expected_image_oat_offset = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin()); + uintptr_t expected_image_oat_offset = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()); uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(); if (expected_image_oat_offset != actual_image_oat_offset) { - *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %ud, " - "found %ud", oat_location, expected_image_oat_offset, + *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %" + PRIuPTR ", found %ud", oat_location, expected_image_oat_offset, actual_image_oat_offset); return nullptr; } @@ -858,7 +858,7 @@ bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, Runtime* runtime = Runtime::Current(); const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader(); uint32_t image_oat_checksum = image_header.GetOatChecksum(); - uint32_t image_oat_data_begin = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin()); + uintptr_t image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()); bool image_check = ((oat_file->GetOatHeader().GetImageFileLocationOatChecksum() == image_oat_checksum) && (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() == image_oat_data_begin)); @@ -885,7 +885,7 @@ bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, ScopedObjectAccess soa(Thread::Current()); mirror::String* oat_location = image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString(); std::string image_file(oat_location->ToModifiedUtf8()); - *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d) with '%s' (0x%x, %d)", + *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d) with '%s' (0x%x, %" PRIdPTR ")", oat_file->GetLocation().c_str(), oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), @@ -1023,7 +1023,8 @@ static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg) if (!method->IsNative()) { method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); if (method != Runtime::Current()->GetResolutionMethod()) { - method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge()); + method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); + method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge()); } } } @@ -1572,7 +1573,7 @@ static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16 return 0; } -const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::ArtMethod* method) { +const OatFile::OatMethod ClassLinker::GetOatMethodFor(mirror::ArtMethod* method) { // Although we overwrite the trampoline of non-static methods, we may get here via the resolution // method for direct methods (or virtual methods made direct). mirror::Class* declaring_class = method->GetDeclaringClass(); @@ -1608,35 +1609,68 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::ArtMethod* m } // Special case to get oat code without overwriting a trampoline. -const void* ClassLinker::GetOatCodeFor(const mirror::ArtMethod* method) { +const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) { CHECK(!method->IsAbstract()) << PrettyMethod(method); if (method->IsProxyMethod()) { -#if !defined(ART_USE_PORTABLE_COMPILER) - return reinterpret_cast<void*>(art_quick_proxy_invoke_handler); -#else - return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); -#endif + return GetQuickProxyInvokeHandler(); + } + const void* result = GetOatMethodFor(method).GetQuickCode(); + if (result == nullptr) { + if (method->IsPortableCompiled()) { + // No code? Do we expect portable code? + result = GetQuickToPortableBridge(); + } else { + // No code? You must mean to go into the interpreter. + result = GetQuickToInterpreterBridge(); + } } - const void* result = GetOatMethodFor(method).GetCode(); - if (result == NULL) { - // No code? You must mean to go into the interpreter. - result = GetCompiledCodeToInterpreterBridge(); + return result; +} + +const void* ClassLinker::GetPortableOatCodeFor(mirror::ArtMethod* method, + bool* have_portable_code) { + CHECK(!method->IsAbstract()) << PrettyMethod(method); + *have_portable_code = false; + if (method->IsProxyMethod()) { + return GetPortableProxyInvokeHandler(); + } + const void* result = GetOatMethodFor(method).GetPortableCode(); + if (result == nullptr) { + if (GetOatMethodFor(method).GetQuickCode() == nullptr) { + // No code? You must mean to go into the interpreter. + result = GetPortableToInterpreterBridge(); + } else { + // No code? But there's quick code, so use a bridge. + result = GetPortableToQuickBridge(); + } + } else { + *have_portable_code = true; } return result; } -const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, - uint32_t method_idx) { +const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, class_def_idx)); CHECK(oat_class.get() != nullptr); uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); - return oat_class->GetOatMethod(oat_method_idx).GetCode(); + return oat_class->GetOatMethod(oat_method_idx).GetQuickCode(); +} + +const void* ClassLinker::GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, class_def_idx)); + CHECK(oat_class.get() != nullptr); + uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); + return oat_class->GetOatMethod(oat_method_idx).GetPortableCode(); } // Returns true if the method must run with interpreter, false otherwise. -static bool NeedsInterpreter(const mirror::ArtMethod* method, const void* code) { - if (code == NULL) { +static bool NeedsInterpreter(mirror::ArtMethod* method, const void* quick_code, + const void* portable_code) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if ((quick_code == nullptr) && (portable_code == nullptr)) { // No code: need interpreter. + DCHECK(!method->IsNative()); return true; } #ifdef ART_SEA_IR_MODE @@ -1684,13 +1718,26 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // Only update static methods. continue; } - const void* code = oat_class->GetOatMethod(method_index).GetCode(); - const bool enter_interpreter = NeedsInterpreter(method, code); + const void* portable_code = oat_class->GetOatMethod(method_index).GetPortableCode(); + const void* quick_code = oat_class->GetOatMethod(method_index).GetQuickCode(); + const bool enter_interpreter = NeedsInterpreter(method, quick_code, portable_code); + bool have_portable_code = false; if (enter_interpreter) { // Use interpreter entry point. - code = GetCompiledCodeToInterpreterBridge(); + portable_code = GetPortableToInterpreterBridge(); + quick_code = GetQuickToInterpreterBridge(); + } else { + if (portable_code == nullptr) { + portable_code = GetPortableToQuickBridge(); + } else { + have_portable_code = true; + } + if (quick_code == nullptr) { + quick_code = GetQuickToPortableBridge(); + } } - runtime->GetInstrumentation()->UpdateMethodsCode(method, code); + runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code, portable_code, + have_portable_code); } // Ignore virtual methods on the iterator. } @@ -1699,7 +1746,8 @@ static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::Oa uint32_t method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Method shouldn't have already been linked. - DCHECK(method->GetEntryPointFromCompiledCode() == NULL); + DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr); + DCHECK(method->GetEntryPointFromPortableCompiledCode() == nullptr); // Every kind of method should at least get an invoke stub from the oat_method. // non-abstract methods also get their code pointers. const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index); @@ -1707,7 +1755,9 @@ static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::Oa // Install entry point from interpreter. Runtime* runtime = Runtime::Current(); - bool enter_interpreter = NeedsInterpreter(method.get(), method->GetEntryPointFromCompiledCode()); + bool enter_interpreter = NeedsInterpreter(method.get(), + method->GetEntryPointFromQuickCompiledCode(), + method->GetEntryPointFromPortableCompiledCode()); if (enter_interpreter) { method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); } else { @@ -1715,18 +1765,29 @@ static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::Oa } if (method->IsAbstract()) { - method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge()); + method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); + method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge()); return; } + bool have_portable_code = false; if (method->IsStatic() && !method->IsConstructor()) { // For static methods excluding the class initializer, install the trampoline. // It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines // after initializing class (see ClassLinker::InitializeClass method). - method->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker())); + method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline(runtime->GetClassLinker())); + method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline(runtime->GetClassLinker())); } else if (enter_interpreter) { // Set entry point from compiled code if there's no code or in interpreter only mode. - method->SetEntryPointFromCompiledCode(GetCompiledCodeToInterpreterBridge()); + method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); + method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge()); + } else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) { + DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr); + have_portable_code = true; + method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge()); + } else { + DCHECK(method->GetEntryPointFromQuickCompiledCode() != nullptr); + method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge()); } if (method->IsNative()) { @@ -1736,7 +1797,9 @@ static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::Oa // Allow instrumentation its chance to hijack code. runtime->GetInstrumentation()->UpdateMethodsCode(method.get(), - method->GetEntryPointFromCompiledCode()); + method->GetEntryPointFromQuickCompiledCode(), + method->GetEntryPointFromPortableCompiledCode(), + have_portable_code); } void ClassLinker::LoadClass(const DexFile& dex_file, @@ -2803,15 +2866,15 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring na return klass.get(); } -std::string ClassLinker::GetDescriptorForProxy(const mirror::Class* proxy_class) { +std::string ClassLinker::GetDescriptorForProxy(mirror::Class* proxy_class) { DCHECK(proxy_class->IsProxyClass()); mirror::String* name = proxy_class->GetName(); DCHECK(name != NULL); return DotToDescriptor(name->ToModifiedUtf8().c_str()); } -mirror::ArtMethod* ClassLinker::FindMethodForProxy(const mirror::Class* proxy_class, - const mirror::ArtMethod* proxy_method) { +mirror::ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, + mirror::ArtMethod* proxy_method) { DCHECK(proxy_class->IsProxyClass()); DCHECK(proxy_method->IsProxyMethod()); // Locate the dex cache of the original interface/Object @@ -2892,7 +2955,8 @@ mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask()); method->SetFpSpillMask(refs_and_args->GetFpSpillMask()); method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes()); - method->SetEntryPointFromCompiledCode(GetProxyInvokeHandler()); + method->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler()); + method->SetEntryPointFromPortableCompiledCode(GetPortableProxyInvokeHandler()); method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); return method; @@ -3175,7 +3239,7 @@ bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& kl klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) { SirtRef<mirror::Class> super(self, klass->GetSuperClass()); for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) { - const mirror::ArtMethod* method = klass->GetVTable()->Get(i); + mirror::ArtMethod* method = klass->GetVTable()->Get(i); if (method != super->GetVTable()->Get(i) && !IsSameMethodSignatureInDifferentClassContexts(method, super.get(), klass.get())) { ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s", @@ -3189,7 +3253,7 @@ bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& kl SirtRef<mirror::Class> interface(self, klass->GetIfTable()->GetInterface(i)); if (klass->GetClassLoader() != interface->GetClassLoader()) { for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) { - const mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j); + mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j); if (!IsSameMethodSignatureInDifferentClassContexts(method, interface.get(), method->GetDeclaringClass())) { ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s", @@ -3206,9 +3270,9 @@ bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& kl // Returns true if classes referenced by the signature of the method are the // same classes in klass1 as they are in klass2. -bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::ArtMethod* method, - const mirror::Class* klass1, - const mirror::Class* klass2) { +bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(mirror::ArtMethod* method, + mirror::Class* klass1, + mirror::Class* klass2) { if (klass1 == klass2) { return true; } @@ -3790,23 +3854,24 @@ struct LinkFieldsComparator { explicit LinkFieldsComparator() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { } // No thread safety analysis as will be called from STL. Checked lock held in constructor. - bool operator()(const mirror::ArtField* field1, const mirror::ArtField* field2) + bool operator()(mirror::ArtField* field1, mirror::ArtField* field2) NO_THREAD_SAFETY_ANALYSIS { // First come reference fields, then 64-bit, and finally 32-bit FieldHelper fh1(field1); Primitive::Type type1 = fh1.GetTypeAsPrimitiveType(); FieldHelper fh2(field2); Primitive::Type type2 = fh2.GetTypeAsPrimitiveType(); - bool isPrimitive1 = type1 != Primitive::kPrimNot; - bool isPrimitive2 = type2 != Primitive::kPrimNot; - bool is64bit1 = isPrimitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble); - bool is64bit2 = isPrimitive2 && (type2 == Primitive::kPrimLong || type2 == Primitive::kPrimDouble); - int order1 = (!isPrimitive1 ? 0 : (is64bit1 ? 1 : 2)); - int order2 = (!isPrimitive2 ? 0 : (is64bit2 ? 1 : 2)); - if (order1 != order2) { - return order1 < order2; + if (type1 != type2) { + bool is_primitive1 = type1 != Primitive::kPrimNot; + bool is_primitive2 = type2 != Primitive::kPrimNot; + bool is64bit1 = is_primitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble); + bool is64bit2 = is_primitive2 && (type2 == Primitive::kPrimLong || type2 == Primitive::kPrimDouble); + int order1 = !is_primitive1 ? 0 : (is64bit1 ? 1 : 2); + int order2 = !is_primitive2 ? 0 : (is64bit2 ? 1 : 2); + if (order1 != order2) { + return order1 < order2; + } } - // same basic group? then sort by string. const char* name1 = fh1.GetName(); const char* name2 = fh2.GetName(); @@ -3996,14 +4061,14 @@ void ClassLinker::CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bo size_t num_reference_fields = is_static ? klass->NumReferenceStaticFieldsDuringLinking() : klass->NumReferenceInstanceFieldsDuringLinking(); - const mirror::ObjectArray<mirror::ArtField>* fields = + mirror::ObjectArray<mirror::ArtField>* fields = is_static ? klass->GetSFields() : klass->GetIFields(); // All of the fields that contain object references are guaranteed // to be at the beginning of the fields list. for (size_t i = 0; i < num_reference_fields; ++i) { // Note that byte_offset is the offset from the beginning of // object, not the offset into instance data - const mirror::ArtField* field = fields->Get(i); + mirror::ArtField* field = fields->Get(i); MemberOffset byte_offset = field->GetOffsetDuringLinking(); CHECK_EQ(byte_offset.Uint32Value() & (CLASS_OFFSET_ALIGNMENT - 1), 0U); if (CLASS_CAN_ENCODE_OFFSET(byte_offset.Uint32Value())) { @@ -4038,7 +4103,7 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t str } mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, - const mirror::Class* referrer) { + mirror::Class* referrer) { Thread* self = Thread::Current(); SirtRef<mirror::DexCache> dex_cache(self, referrer->GetDexCache()); SirtRef<mirror::ClassLoader> class_loader(self, referrer->GetClassLoader()); @@ -4081,7 +4146,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, const SirtRef<mirror::DexCache>& dex_cache, const SirtRef<mirror::ClassLoader>& class_loader, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, InvokeType type) { DCHECK(dex_cache.get() != NULL); // Check for hit in the dex cache. diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 8722de3134..7e31356ea3 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -121,7 +121,7 @@ class ClassLinker { // Resolve a String with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the // target DexCache and ClassLoader to use for resolution. - mirror::String* ResolveString(uint32_t string_idx, const mirror::ArtMethod* referrer) + mirror::String* ResolveString(uint32_t string_idx, mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a String with the given index from the DexFile, storing the @@ -133,17 +133,16 @@ class ClassLinker { // Resolve a Type with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identity the // target DexCache and ClassLoader to use for resolution. - mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, - const mirror::Class* referrer) + mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, mirror::Class* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a Type with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the // target DexCache and ClassLoader to use for resolution. - mirror::Class* ResolveType(uint16_t type_idx, const mirror::ArtMethod* referrer) + mirror::Class* ResolveType(uint16_t type_idx, mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::Class* ResolveType(uint16_t type_idx, const mirror::ArtField* referrer) + mirror::Class* ResolveType(uint16_t type_idx, mirror::ArtField* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a type with the given ID from the DexFile, storing the @@ -164,15 +163,15 @@ class ClassLinker { uint32_t method_idx, const SirtRef<mirror::DexCache>& dex_cache, const SirtRef<mirror::ClassLoader>& class_loader, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::ArtMethod* ResolveMethod(uint32_t method_idx, const mirror::ArtMethod* referrer, + mirror::ArtMethod* ResolveMethod(uint32_t method_idx, mirror::ArtMethod* referrer, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::ArtField* ResolveField(uint32_t field_idx, const mirror::ArtMethod* referrer, + mirror::ArtField* ResolveField(uint32_t field_idx, mirror::ArtMethod* referrer, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -319,19 +318,23 @@ class ClassLinker { mirror::Class* CreateProxyClass(ScopedObjectAccess& soa, jstring name, jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - std::string GetDescriptorForProxy(const mirror::Class* proxy_class) + std::string GetDescriptorForProxy(mirror::Class* proxy_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::ArtMethod* FindMethodForProxy(const mirror::Class* proxy_class, - const mirror::ArtMethod* proxy_method) + mirror::ArtMethod* FindMethodForProxy(mirror::Class* proxy_class, + mirror::ArtMethod* proxy_method) LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the oat code for a method when its class isn't yet initialized - const void* GetOatCodeFor(const mirror::ArtMethod* method) + const void* GetQuickOatCodeFor(mirror::ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const void* GetPortableOatCodeFor(mirror::ArtMethod* method, bool* have_portable_code) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the oat code for a method from a method index. - const void* GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) + const void* GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const void* GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. @@ -368,7 +371,7 @@ class ClassLinker { mirror::ArtMethod* AllocArtMethod(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: - const OatFile::OatMethod GetOatMethodFor(const mirror::ArtMethod* method) + const OatFile::OatMethod GetOatMethodFor(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); OatFile& GetImageOatFile(gc::space::ImageSpace* space) @@ -451,9 +454,9 @@ class ClassLinker { SirtRef<mirror::ClassLoader>& class_loader2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsSameMethodSignatureInDifferentClassContexts(const mirror::ArtMethod* method, - const mirror::Class* klass1, - const mirror::Class* klass2) + bool IsSameMethodSignatureInDifferentClassContexts(mirror::ArtMethod* method, + mirror::Class* klass1, + mirror::Class* klass2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool LinkClass(Thread* self, const SirtRef<mirror::Class>& klass, diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 1744050a00..fb979c201d 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -55,7 +55,7 @@ class ClassLinkerTest : public CommonTest { AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(descriptor.c_str())); } - void AssertPrimitiveClass(const std::string& descriptor, const mirror::Class* primitive) + void AssertPrimitiveClass(const std::string& descriptor, mirror::Class* primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ClassHelper primitive_ch(primitive); ASSERT_TRUE(primitive != NULL); @@ -212,7 +212,7 @@ class ClassLinkerTest : public CommonTest { } } EXPECT_EQ(klass->IsInterface(), klass->GetVTable() == NULL); - const mirror::IfTable* iftable = klass->GetIfTable(); + mirror::IfTable* iftable = klass->GetIfTable(); for (int i = 0; i < klass->GetIfTableCount(); i++) { mirror::Class* interface = iftable->GetInterface(i); ASSERT_TRUE(interface != NULL); @@ -469,20 +469,23 @@ struct ArtMethodOffsets : public CheckOffsets<mirror::ArtMethod> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_), "dexCacheResolvedTypes")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_strings_), "dexCacheStrings")); + // alphabetical 64-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_interpreter_), "entryPointFromInterpreter")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_jni_), "entryPointFromJni")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_portable_compiled_code_), "entryPointFromPortableCompiledCode")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_quick_compiled_code_), "entryPointFromQuickCompiledCode")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, gc_map_), "gcMap")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_mapping_table_), "quickMappingTable")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_vmap_table_), "quickVmapTable")); + // alphabetical 32-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_), "accessFlags")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, code_item_offset_), "codeItemOffset")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, core_spill_mask_), "coreSpillMask")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_compiled_code_), "entryPointFromCompiledCode")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_interpreter_), "entryPointFromInterpreter")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, fp_spill_mask_), "fpSpillMask")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, frame_size_in_bytes_), "frameSizeInBytes")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, gc_map_), "gcMap")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, mapping_table_), "mappingTable")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_dex_index_), "methodDexIndex")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, native_method_), "nativeMethod")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, vmap_table_), "vmapTable")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_core_spill_mask_), "quickCoreSpillMask")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_fp_spill_mask_), "quickFpSpillMask")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_frame_size_in_bytes_), "quickFrameSizeInBytes")); }; }; @@ -762,10 +765,10 @@ TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) { mirror::Class* array_class = class_linker_->FindSystemClass("[Ljava/lang/String;"); mirror::ObjectArray<mirror::String>* array = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), array_class, 0); - uint32_t array_offset = reinterpret_cast<uint32_t>(array); - uint32_t data_offset = - array_offset + mirror::ObjectArray<mirror::String>::DataOffset(sizeof(mirror::String*)).Uint32Value(); - if (sizeof(mirror::String*) == sizeof(int32_t)) { + uintptr_t data_offset = + reinterpret_cast<uintptr_t>(array->GetRawData(sizeof(mirror::HeapReference<mirror::String>), + 0)); + if (sizeof(mirror::HeapReference<mirror::String>) == sizeof(int32_t)) { EXPECT_TRUE(IsAligned<4>(data_offset)); // Check 4 byte alignment. } else { EXPECT_TRUE(IsAligned<8>(data_offset)); // Check 8 byte alignment. diff --git a/runtime/common_test.h b/runtime/common_test.h index fce3f3f7c2..ddaf52a04b 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -48,6 +48,7 @@ #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" #include "thread.h" +#include "utils.h" #include "UniquePtr.h" #include "verifier/method_verifier.h" #include "verifier/method_verifier-inl.h" @@ -262,11 +263,6 @@ static InstructionSetFeatures ParseFeatureList(std::string str) { class CommonTest : public testing::Test { public: - static void MakeExecutable(const mirror::ByteArray* code_array) { - CHECK(code_array != NULL); - MakeExecutable(code_array->GetData(), code_array->GetLength()); - } - static void MakeExecutable(const std::vector<uint8_t>& code) { CHECK_NE(code.size(), 0U); MakeExecutable(&code[0], code.size()); @@ -280,31 +276,39 @@ class CommonTest : public testing::Test { const uint8_t* mapping_table, const uint8_t* vmap_table, const uint8_t* gc_map) { - return OatFile::OatMethod(NULL, - reinterpret_cast<uint32_t>(code), - frame_size_in_bytes, - core_spill_mask, - fp_spill_mask, - reinterpret_cast<uint32_t>(mapping_table), - reinterpret_cast<uint32_t>(vmap_table), - reinterpret_cast<uint32_t>(gc_map)); + const byte* base = nullptr; // Base of data in oat file, ie 0. + uint32_t code_offset = PointerToLowMemUInt32(code); + uint32_t mapping_table_offset = PointerToLowMemUInt32(mapping_table); + uint32_t vmap_table_offset = PointerToLowMemUInt32(vmap_table); + uint32_t gc_map_offset = PointerToLowMemUInt32(gc_map); + return OatFile::OatMethod(base, + code_offset, + frame_size_in_bytes, + core_spill_mask, + fp_spill_mask, + mapping_table_offset, + vmap_table_offset, + gc_map_offset); } void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(method != NULL); + CHECK(method != nullptr); - const CompiledMethod* compiled_method = NULL; + const CompiledMethod* compiled_method = nullptr; if (!method->IsAbstract()) { - const mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); + mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); const DexFile& dex_file = *dex_cache->GetDexFile(); compiled_method = compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method->GetDexMethodIndex())); } - if (compiled_method != NULL) { - const std::vector<uint8_t>& code = compiled_method->GetCode(); - MakeExecutable(code); - const void* method_code = CompiledMethod::CodePointer(&code[0], + if (compiled_method != nullptr) { + const std::vector<uint8_t>* code = compiled_method->GetQuickCode(); + if (code == nullptr) { + code = compiled_method->GetPortableCode(); + } + MakeExecutable(*code); + const void* method_code = CompiledMethod::CodePointer(&(*code)[0], compiled_method->GetInstructionSet()); LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code; OatFile::OatMethod oat_method = CreateOatMethod(method_code, @@ -317,9 +321,9 @@ class CommonTest : public testing::Test { oat_method.LinkMethod(method); method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); } else { - const void* method_code; // No code? You must mean to go into the interpreter. - method_code = GetCompiledCodeToInterpreterBridge(); + const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge() + : GetQuickToInterpreterBridge(); OatFile::OatMethod oat_method = CreateOatMethod(method_code, kStackAlignment, 0, @@ -330,6 +334,14 @@ class CommonTest : public testing::Test { oat_method.LinkMethod(method); method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); } + // Create bridges to transition between different kinds of compiled bridge. + if (method->GetEntryPointFromPortableCompiledCode() == nullptr) { + method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge()); + } else { + CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr); + method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge()); + method->SetIsPortableCompiled(); + } } static void MakeExecutable(const void* code_start, size_t code_length) { @@ -415,11 +427,7 @@ class CommonTest : public testing::Test { std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); // TODO: make selectable -#if defined(ART_USE_PORTABLE_COMPILER) - CompilerBackend compiler_backend = kPortable; -#else - CompilerBackend compiler_backend = kQuick; -#endif + CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick; verification_results_.reset(new VerificationResults); method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr); @@ -460,6 +468,8 @@ class CommonTest : public testing::Test { instruction_set = kMips; #elif defined(__i386__) instruction_set = kX86; +#elif defined(__x86_64__) + instruction_set = kX86_64; #endif for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { @@ -640,7 +650,9 @@ class CommonTest : public testing::Test { image_reservation_.reset(MemMap::MapAnonymous("image reservation", reinterpret_cast<byte*>(ART_BASE_ADDRESS), (size_t)100 * 1024 * 1024, // 100MB - PROT_NONE, &error_msg)); + PROT_NONE, + false /* no need for 4gb flag with fixed mmap*/, + &error_msg)); CHECK(image_reservation_.get() != nullptr) << error_msg; } @@ -733,11 +745,12 @@ class CheckJniAbortCatcher { // MCLinker link LLVM ELF output because we no longer just have code // blobs in memory. We'll need to dlopen to load and relocate // temporary output to resurrect these tests. -#if defined(ART_USE_PORTABLE_COMPILER) -#define TEST_DISABLED_FOR_PORTABLE() printf("WARNING: TEST DISABLED FOR PORTABLE\n"); return -#else -#define TEST_DISABLED_FOR_PORTABLE() -#endif +#define TEST_DISABLED_FOR_PORTABLE() \ + if (kUsePortableCompiler) { \ + printf("WARNING: TEST DISABLED FOR PORTABLE\n"); \ + return; \ + } + } // namespace art namespace std { diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index dd832df373..24d16c4c97 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -33,7 +33,7 @@ namespace art { -static void AddReferrerLocation(std::ostream& os, const mirror::Class* referrer) +static void AddReferrerLocation(std::ostream& os, mirror::Class* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (referrer != NULL) { ClassHelper kh(referrer); @@ -46,7 +46,7 @@ static void AddReferrerLocation(std::ostream& os, const mirror::Class* referrer) } static void ThrowException(const ThrowLocation* throw_location, const char* exception_descriptor, - const mirror::Class* referrer, const char* fmt, va_list* args = NULL) + mirror::Class* referrer, const char* fmt, va_list* args = NULL) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::ostringstream msg; if (args != NULL) { @@ -68,7 +68,7 @@ static void ThrowException(const ThrowLocation* throw_location, const char* exce // AbstractMethodError -void ThrowAbstractMethodError(const mirror::ArtMethod* method) { +void ThrowAbstractMethodError(mirror::ArtMethod* method) { ThrowException(NULL, "Ljava/lang/AbstractMethodError;", NULL, StringPrintf("abstract method \"%s\"", PrettyMethod(method).c_str()).c_str()); @@ -89,8 +89,7 @@ void ThrowArrayIndexOutOfBoundsException(int index, int length) { // ArrayStoreException -void ThrowArrayStoreException(const mirror::Class* element_class, - const mirror::Class* array_class) { +void ThrowArrayStoreException(mirror::Class* element_class, mirror::Class* array_class) { ThrowException(NULL, "Ljava/lang/ArrayStoreException;", NULL, StringPrintf("%s cannot be stored in an array of type %s", PrettyDescriptor(element_class).c_str(), @@ -99,7 +98,7 @@ void ThrowArrayStoreException(const mirror::Class* element_class, // ClassCastException -void ThrowClassCastException(const mirror::Class* dest_type, const mirror::Class* src_type) { +void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type) { ThrowException(NULL, "Ljava/lang/ClassCastException;", NULL, StringPrintf("%s cannot be cast to %s", PrettyDescriptor(src_type).c_str(), @@ -120,7 +119,7 @@ void ThrowClassCircularityError(mirror::Class* c) { // ClassFormatError -void ThrowClassFormatError(const mirror::Class* referrer, const char* fmt, ...) { +void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) { va_list args; va_start(args, fmt); ThrowException(NULL, "Ljava/lang/ClassFormatError;", referrer, fmt, &args); @@ -136,7 +135,7 @@ void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* access } void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, - const mirror::ArtMethod* called, + mirror::ArtMethod* called, InvokeType type) { std::ostringstream msg; msg << "Illegal class access ('" << PrettyDescriptor(referrer) << "' attempting to access '" @@ -159,7 +158,7 @@ void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::ArtField* acc ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str()); } -void ThrowIllegalAccessErrorFinalField(const mirror::ArtMethod* referrer, +void ThrowIllegalAccessErrorFinalField(mirror::ArtMethod* referrer, mirror::ArtField* accessed) { std::ostringstream msg; msg << "Final field '" << PrettyField(accessed, false) << "' cannot be written to by method '" @@ -187,7 +186,7 @@ void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const ch void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type, mirror::ArtMethod* method, - const mirror::ArtMethod* referrer) { + mirror::ArtMethod* referrer) { std::ostringstream msg; msg << "The method '" << PrettyMethod(method) << "' was expected to be of type " << expected_type << " but instead was found to be of type " << found_type; @@ -196,9 +195,9 @@ void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType foun msg.str().c_str()); } -void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::ArtMethod* interface_method, +void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(mirror::ArtMethod* interface_method, mirror::Object* this_object, - const mirror::ArtMethod* referrer) { + mirror::ArtMethod* referrer) { // Referrer is calling interface_method on this_object, however, the interface_method isn't // implemented by this_object. CHECK(this_object != NULL); @@ -212,8 +211,8 @@ void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::Ar msg.str().c_str()); } -void ThrowIncompatibleClassChangeErrorField(const mirror::ArtField* resolved_field, bool is_static, - const mirror::ArtMethod* referrer) { +void ThrowIncompatibleClassChangeErrorField(mirror::ArtField* resolved_field, bool is_static, + mirror::ArtMethod* referrer) { std::ostringstream msg; msg << "Expected '" << PrettyField(resolved_field) << "' to be a " << (is_static ? "static" : "instance") << " field" << " rather than a " @@ -222,7 +221,7 @@ void ThrowIncompatibleClassChangeErrorField(const mirror::ArtField* resolved_fie msg.str().c_str()); } -void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char* fmt, ...) { +void ThrowIncompatibleClassChangeError(mirror::Class* referrer, const char* fmt, ...) { va_list args; va_start(args, fmt); ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;", referrer, fmt, &args); @@ -240,7 +239,7 @@ void ThrowIOException(const char* fmt, ...) { // LinkageError -void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) { +void ThrowLinkageError(mirror::Class* referrer, const char* fmt, ...) { va_list args; va_start(args, fmt); ThrowException(NULL, "Ljava/lang/LinkageError;", referrer, fmt, &args); @@ -486,7 +485,7 @@ void ThrowRuntimeException(const char* fmt, ...) { // VerifyError -void ThrowVerifyError(const mirror::Class* referrer, const char* fmt, ...) { +void ThrowVerifyError(mirror::Class* referrer, const char* fmt, ...) { va_list args; va_start(args, fmt); ThrowException(NULL, "Ljava/lang/VerifyError;", referrer, fmt, &args); diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 7f13891400..792cdefce2 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -33,7 +33,7 @@ class ThrowLocation; // AbstractMethodError -void ThrowAbstractMethodError(const mirror::ArtMethod* method) +void ThrowAbstractMethodError(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ArithmeticException @@ -47,8 +47,7 @@ void ThrowArrayIndexOutOfBoundsException(int index, int length) // ArrayStoreException -void ThrowArrayStoreException(const mirror::Class* element_class, - const mirror::Class* array_class) +void ThrowArrayStoreException(mirror::Class* element_class, mirror::Class* array_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; // ClassCircularityError @@ -58,7 +57,7 @@ void ThrowClassCircularityError(mirror::Class* c) // ClassCastException -void ThrowClassCastException(const mirror::Class* dest_type, const mirror::Class* src_type) +void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowClassCastException(const ThrowLocation* throw_location, const char* msg) @@ -66,7 +65,7 @@ void ThrowClassCastException(const ThrowLocation* throw_location, const char* ms // ClassFormatError -void ThrowClassFormatError(const mirror::Class* referrer, const char* fmt, ...) +void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; @@ -76,7 +75,7 @@ void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* access SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, - const mirror::ArtMethod* called, + mirror::ArtMethod* called, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; @@ -86,8 +85,7 @@ void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, mirror::ArtMethod* a void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::ArtField* accessed) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; -void ThrowIllegalAccessErrorFinalField(const mirror::ArtMethod* referrer, - mirror::ArtField* accessed) +void ThrowIllegalAccessErrorFinalField(mirror::ArtMethod* referrer, mirror::ArtField* accessed) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) @@ -102,20 +100,19 @@ void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const ch // IncompatibleClassChangeError void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type, - mirror::ArtMethod* method, - const mirror::ArtMethod* referrer) + mirror::ArtMethod* method, mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; -void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::ArtMethod* interface_method, +void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(mirror::ArtMethod* interface_method, mirror::Object* this_object, - const mirror::ArtMethod* referrer) + mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; -void ThrowIncompatibleClassChangeErrorField(const mirror::ArtField* resolved_field, bool is_static, - const mirror::ArtMethod* referrer) +void ThrowIncompatibleClassChangeErrorField(mirror::ArtField* resolved_field, bool is_static, + mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; -void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char* fmt, ...) +void ThrowIncompatibleClassChangeError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; @@ -126,7 +123,7 @@ void ThrowIOException(const char* fmt, ...) __attribute__((__format__(__printf__ // LinkageError -void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) +void ThrowLinkageError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; @@ -185,7 +182,7 @@ void ThrowRuntimeException(const char* fmt, ...) // VerifyError -void ThrowVerifyError(const mirror::Class* referrer, const char* fmt, ...) +void ThrowVerifyError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 21419973e0..9cc7cb476f 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -101,7 +101,7 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList virtual ~DebugInstrumentationListener() {} virtual void MethodEntered(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (method->IsNative()) { // TODO: post location events is a suspension point and native method entry stubs aren't. @@ -111,7 +111,7 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList } virtual void MethodExited(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (method->IsNative()) { @@ -122,7 +122,7 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList } virtual void MethodUnwind(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // We're not recorded to listen to this kind of event, so complain. LOG(ERROR) << "Unexpected method unwind event in debugger " << PrettyMethod(method) @@ -130,7 +130,7 @@ class DebugInstrumentationListener : public instrumentation::InstrumentationList } virtual void DexPcMoved(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t new_dex_pc) + mirror::ArtMethod* method, uint32_t new_dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Dbg::UpdateDebugger(thread, this_object, method, new_dex_pc); } @@ -303,7 +303,7 @@ static JDWP::JdwpTag TagFromClass(mirror::Class* c) * * Null objects are tagged JT_OBJECT. */ -static JDWP::JdwpTag TagFromObject(const mirror::Object* o) +static JDWP::JdwpTag TagFromObject(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (o == NULL) ? JDWP::JT_OBJECT : TagFromClass(o->GetClass()); } @@ -1054,16 +1054,16 @@ JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count, size_t width = GetTagWidth(tag); uint8_t* dst = expandBufAddSpace(pReply, count * width); if (width == 8) { - const uint64_t* src8 = reinterpret_cast<uint64_t*>(a->GetRawData(sizeof(uint64_t))); + const uint64_t* src8 = reinterpret_cast<uint64_t*>(a->GetRawData(sizeof(uint64_t), 0)); for (int i = 0; i < count; ++i) JDWP::Write8BE(&dst, src8[offset + i]); } else if (width == 4) { - const uint32_t* src4 = reinterpret_cast<uint32_t*>(a->GetRawData(sizeof(uint32_t))); + const uint32_t* src4 = reinterpret_cast<uint32_t*>(a->GetRawData(sizeof(uint32_t), 0)); for (int i = 0; i < count; ++i) JDWP::Write4BE(&dst, src4[offset + i]); } else if (width == 2) { - const uint16_t* src2 = reinterpret_cast<uint16_t*>(a->GetRawData(sizeof(uint16_t))); + const uint16_t* src2 = reinterpret_cast<uint16_t*>(a->GetRawData(sizeof(uint16_t), 0)); for (int i = 0; i < count; ++i) JDWP::Write2BE(&dst, src2[offset + i]); } else { - const uint8_t* src = reinterpret_cast<uint8_t*>(a->GetRawData(sizeof(uint8_t))); + const uint8_t* src = reinterpret_cast<uint8_t*>(a->GetRawData(sizeof(uint8_t), 0)); memcpy(dst, &src[offset * width], count * width); } } else { @@ -1079,10 +1079,13 @@ JDWP::JdwpError Dbg::OutputArray(JDWP::ObjectId array_id, int offset, int count, return JDWP::ERR_NONE; } -template <typename T> void CopyArrayData(mirror::Array* a, JDWP::Request& src, int offset, int count) { +template <typename T> +static void CopyArrayData(mirror::Array* a, JDWP::Request& src, int offset, int count) + NO_THREAD_SAFETY_ANALYSIS { + // TODO: fix when annotalysis correctly handles non-member functions. DCHECK(a->GetClass()->IsPrimitiveArray()); - T* dst = &(reinterpret_cast<T*>(a->GetRawData(sizeof(T)))[offset * sizeof(T)]); + T* dst = reinterpret_cast<T*>(a->GetRawData(sizeof(T), offset)); for (int i = 0; i < count; ++i) { *dst++ = src.ReadValue(sizeof(T)); } @@ -1926,7 +1929,7 @@ JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_fram JDWP::FrameId frame_id(GetFrameId()); JDWP::JdwpLocation location; SetLocation(location, GetMethod(), GetDexPc()); - VLOG(jdwp) << StringPrintf(" Frame %3zd: id=%3lld ", depth_, frame_id) << location; + VLOG(jdwp) << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth_, frame_id) << location; expandBufAdd8BE(buf_, frame_id); expandBufAddLocation(buf_, location); } @@ -2283,7 +2286,7 @@ void Dbg::SetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame_id, int sl visitor.WalkStack(); } -void Dbg::PostLocationEvent(const mirror::ArtMethod* m, int dex_pc, mirror::Object* this_object, +void Dbg::PostLocationEvent(mirror::ArtMethod* m, int dex_pc, mirror::Object* this_object, int event_flags, const JValue* return_value) { mirror::Class* c = m->GetDeclaringClass(); @@ -2338,7 +2341,7 @@ void Dbg::PostClassPrepare(mirror::Class* c) { } void Dbg::UpdateDebugger(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* m, uint32_t dex_pc) { + mirror::ArtMethod* m, uint32_t dex_pc) { if (!IsDebuggerActive() || dex_pc == static_cast<uint32_t>(-2) /* fake method exit */) { return; } @@ -2630,7 +2633,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize if (!m->IsRuntimeMethod()) { ++single_step_control_->stack_depth; if (single_step_control_->method == NULL) { - const mirror::DexCache* dex_cache = m->GetDeclaringClass()->GetDexCache(); + mirror::DexCache* dex_cache = m->GetDeclaringClass()->GetDexCache(); single_step_control_->method = m; *line_number_ = -1; if (dex_cache != NULL) { @@ -2699,7 +2702,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize uint32_t last_pc; }; single_step_control->dex_pcs.clear(); - const mirror::ArtMethod* m = single_step_control->method; + mirror::ArtMethod* m = single_step_control->method; if (!m->IsNative()) { DebugCallbackContext context(single_step_control, line_number); MethodHelper mh(m); @@ -3062,7 +3065,7 @@ bool Dbg::DdmHandlePacket(JDWP::Request& request, uint8_t** pReplyBuf, int* pRep // Run through and find all chunks. [Currently just find the first.] ScopedByteArrayRO contents(env, dataArray.get()); if (length != request_length) { - LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%d)", length, request_length); + LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%zd)", length, request_length); return false; } @@ -3454,7 +3457,7 @@ class HeapChunkContext { Flush(); } } - const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(start); + mirror::Object* obj = reinterpret_cast<mirror::Object*>(start); // Determine the type of this chunk. // OLD-TODO: if context.merge, see if this chunk is different from the last chunk. @@ -3497,8 +3500,8 @@ class HeapChunkContext { *p_++ = length - 1; } - uint8_t ExamineObject(const mirror::Object* o, bool is_native_heap) - SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) { + uint8_t ExamineObject(mirror::Object* o, bool is_native_heap) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { if (o == NULL) { return HPSG_STATE(SOLIDITY_FREE, 0); } @@ -3751,7 +3754,7 @@ void Dbg::DumpRecentAllocations() { << PrettyClass(record->type); for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) { - const mirror::ArtMethod* m = record->stack[stack_frame].method; + mirror::ArtMethod* m = record->stack[stack_frame].method; if (m == NULL) { break; } diff --git a/runtime/debugger.h b/runtime/debugger.h index a3f8b9c8e0..328c9cdf62 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -366,7 +366,7 @@ class Dbg { kMethodEntry = 0x04, kMethodExit = 0x08, }; - static void PostLocationEvent(const mirror::ArtMethod* method, int pcOffset, + static void PostLocationEvent(mirror::ArtMethod* method, int pcOffset, mirror::Object* thisPtr, int eventFlags, const JValue* return_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -382,7 +382,7 @@ class Dbg { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void UpdateDebugger(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t new_dex_pc) + mirror::ArtMethod* method, uint32_t new_dex_pc) LOCKS_EXCLUDED(Locks::breakpoint_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 3b2135c2cd..a459308ab7 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -44,7 +44,7 @@ inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) co inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) { const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_]; return reinterpret_cast<const TryItem*> - (RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset; + (RoundUp(reinterpret_cast<uintptr_t>(insns_end_), 4)) + offset; } static inline bool DexFileStringEquals(const DexFile* df1, uint32_t sidx1, diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index d28d9866c3..eaba7ebd8d 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -621,7 +621,7 @@ const Signature DexFile::CreateSignature(const StringPiece& signature) const { return Signature(this, *proto_id); } -int32_t DexFile::GetLineNumFromPC(const mirror::ArtMethod* method, uint32_t rel_pc) const { +int32_t DexFile::GetLineNumFromPC(mirror::ArtMethod* method, uint32_t rel_pc) const { // For native method, lineno should be -2 to indicate it is native. Note that // "line number == -2" is how libcore tells from StackTraceElement. if (method->GetCodeItemOffset() == 0) { diff --git a/runtime/dex_file.h b/runtime/dex_file.h index bc2bfde917..46df455a1f 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -794,7 +794,7 @@ class DexFile { // Returns -2 for native methods (as expected in exception traces). // // This is used by runtime; therefore use art::Method not art::DexFile::Method. - int32_t GetLineNumFromPC(const mirror::ArtMethod* method, uint32_t rel_pc) const + int32_t GetLineNumFromPC(mirror::ArtMethod* method, uint32_t rel_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 2f7c38a71f..261c217c9b 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -646,7 +646,8 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { reservation_name += file_->GetPath(); std::string error_msg; UniquePtr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(), - NULL, GetLoadedSize(), PROT_NONE, &error_msg)); + NULL, GetLoadedSize(), PROT_NONE, false, + &error_msg)); CHECK(reserve.get() != NULL) << file_->GetPath() << ": " << error_msg; base_address_ = reserve->Begin(); segments_.push_back(reserve.release()); diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index f4783664c5..20532f4399 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -282,7 +282,7 @@ enum FindFieldType { }; template<FindFieldType type, bool access_check> -static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirror::ArtMethod* referrer, +static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer, Thread* self, size_t expected_size) { bool is_primitive; bool is_set; @@ -321,8 +321,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr return nullptr; // Failure. } else { FieldHelper fh(resolved_field); - if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || - fh.FieldSize() != expected_size)) { + if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || fh.FieldSize() != expected_size)) { ThrowLocation throw_location = self->GetCurrentLocationForThrow(); DCHECK(throw_location.GetMethod() == referrer); self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;", @@ -358,7 +357,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr #define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \ template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \ mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \ - const mirror::ArtMethod* referrer, \ + mirror::ArtMethod* referrer, \ Thread* self, size_t expected_size) \ #define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ @@ -496,7 +495,7 @@ EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface); // Fast path field resolution that can't initialize classes or throw exceptions. static inline mirror::ArtField* FindFieldFast(uint32_t field_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, FindFieldType type, size_t expected_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* resolved_field = @@ -552,7 +551,7 @@ static inline mirror::ArtField* FindFieldFast(uint32_t field_idx, // Fast path method resolution that can't throw exceptions. static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx, mirror::Object* this_object, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, bool access_check, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { bool is_direct = type == kStatic || type == kDirect; @@ -593,7 +592,7 @@ static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx, } static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, bool can_run_clinit, bool verify_access) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -630,7 +629,7 @@ static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -static inline mirror::String* ResolveStringFromCode(const mirror::ArtMethod* referrer, +static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer, uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); @@ -719,21 +718,21 @@ static inline const void* GetPortableToInterpreterBridge() { return reinterpret_cast<void*>(art_portable_to_interpreter_bridge); } +static inline const void* GetPortableToQuickBridge() { + // TODO: portable to quick bridge. Bug: 8196384 + return GetPortableToInterpreterBridge(); +} + extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); static inline const void* GetQuickToInterpreterBridge() { return reinterpret_cast<void*>(art_quick_to_interpreter_bridge); } -// Return address of interpreter stub. -static inline const void* GetCompiledCodeToInterpreterBridge() { -#if defined(ART_USE_PORTABLE_COMPILER) - return GetPortableToInterpreterBridge(); -#else +static inline const void* GetQuickToPortableBridge() { + // TODO: quick to portable bridge. Bug: 8196384 return GetQuickToInterpreterBridge(); -#endif } - static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) { return class_linker->GetPortableResolutionTrampoline(); } @@ -742,15 +741,6 @@ static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker return class_linker->GetQuickResolutionTrampoline(); } -// Return address of resolution trampoline stub for defined compiler. -static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { -#if defined(ART_USE_PORTABLE_COMPILER) - return GetPortableResolutionTrampoline(class_linker); -#else - return GetQuickResolutionTrampoline(class_linker); -#endif -} - static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) { return class_linker->GetPortableImtConflictTrampoline(); } @@ -759,15 +749,6 @@ static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linke return class_linker->GetQuickImtConflictTrampoline(); } -// Return address of imt conflict trampoline stub for defined compiler. -static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) { -#if defined(ART_USE_PORTABLE_COMPILER) - return GetPortableImtConflictTrampoline(class_linker); -#else - return GetQuickImtConflictTrampoline(class_linker); -#endif -} - extern "C" void art_portable_proxy_invoke_handler(); static inline const void* GetPortableProxyInvokeHandler() { return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); @@ -778,14 +759,6 @@ static inline const void* GetQuickProxyInvokeHandler() { return reinterpret_cast<void*>(art_quick_proxy_invoke_handler); } -static inline const void* GetProxyInvokeHandler() { -#if defined(ART_USE_PORTABLE_COMPILER) - return GetPortableProxyInvokeHandler(); -#else - return GetQuickProxyInvokeHandler(); -#endif -} - extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject); static inline void* GetJniDlsymLookupStub() { return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub); diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index 0df00c2f38..8a2ce510f5 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -45,15 +45,15 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m } } uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_; -#if defined(ART_USE_PORTABLE_COMPILER) - ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); - arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset); - method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]); -#else - method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset), - (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t), - result, mh.GetShorty()[0]); -#endif + if (kUsePortableCompiler) { + ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); + arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset); + method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]); + } else { + method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset), + (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t), + result, mh.GetShorty()[0]); + } } } // namespace art diff --git a/runtime/entrypoints/portable/portable_cast_entrypoints.cc b/runtime/entrypoints/portable/portable_cast_entrypoints.cc index d343c5dc1f..a553a22df8 100644 --- a/runtime/entrypoints/portable/portable_cast_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_cast_entrypoints.cc @@ -20,16 +20,16 @@ namespace art { -extern "C" int32_t art_portable_is_assignable_from_code(const mirror::Class* dest_type, - const mirror::Class* src_type) +extern "C" int32_t art_portable_is_assignable_from_code(mirror::Class* dest_type, + mirror::Class* src_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(dest_type != NULL); DCHECK(src_type != NULL); return dest_type->IsAssignableFrom(src_type) ? 1 : 0; } -extern "C" void art_portable_check_cast_from_code(const mirror::Class* dest_type, - const mirror::Class* src_type) +extern "C" void art_portable_check_cast_from_code(mirror::Class* dest_type, + mirror::Class* src_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(dest_type->IsClass()) << PrettyClass(dest_type); DCHECK(src_type->IsClass()) << PrettyClass(src_type); @@ -38,8 +38,8 @@ extern "C" void art_portable_check_cast_from_code(const mirror::Class* dest_type } } -extern "C" void art_portable_check_put_array_element_from_code(const mirror::Object* element, - const mirror::Object* array) +extern "C" void art_portable_check_put_array_element_from_code(mirror::Object* element, + mirror::Object* array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (element == NULL) { return; diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc index 095e99ef34..0b54b9c9f1 100644 --- a/runtime/entrypoints/portable/portable_field_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc @@ -65,13 +65,13 @@ extern "C" int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, mirror::Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { field->SetObj(field->GetDeclaringClass(), new_value); return 0; } field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, Thread::Current(), - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { field->SetObj(field->GetDeclaringClass(), new_value); return 0; @@ -113,12 +113,12 @@ extern "C" mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_ mirror::ArtMethod* referrer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectRead, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(field->GetDeclaringClass()); } field = FindFieldFromCode<StaticObjectRead, true>(field_idx, referrer, Thread::Current(), - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(field->GetDeclaringClass()); } @@ -167,13 +167,13 @@ extern "C" int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, mirror::Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { field->SetObj(obj, new_value); return 0; } field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, Thread::Current(), - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { field->SetObj(obj, new_value); return 0; @@ -218,12 +218,12 @@ extern "C" mirror::Object* art_portable_get_obj_instance_from_code(uint32_t fiel mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(obj); } field = FindFieldFromCode<InstanceObjectRead, true>(field_idx, referrer, Thread::Current(), - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(obj); } diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc index 8cf4eed88f..1005d0e6fb 100644 --- a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc @@ -44,7 +44,7 @@ extern "C" void art_portable_fill_array_data_from_code(mirror::ArtMethod* method return; // Error } uint32_t size_in_bytes = payload->element_count * payload->element_width; - memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); + memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes); } } // namespace art diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc index 47ccbb126e..d34b09737f 100644 --- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc @@ -34,7 +34,7 @@ mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_ob } } DCHECK(!thread->IsExceptionPending()); - const void* code = method->GetEntryPointFromCompiledCode(); + const void* code = method->GetEntryPointFromPortableCompiledCode(); // When we return, the caller will branch to this address, so it had better not be 0! if (UNLIKELY(code == NULL)) { diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc index 2a0df9b896..1fdb8327cc 100644 --- a/runtime/entrypoints/portable/portable_throw_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc @@ -75,7 +75,7 @@ extern "C" int32_t art_portable_find_catch_block_from_code(mirror::ArtMethod* cu ThrowLocation throw_location; mirror::Throwable* exception = self->GetException(&throw_location); // Check for special deoptimization exception. - if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) { + if (UNLIKELY(reinterpret_cast<intptr_t>(exception) == -1)) { return -1; } mirror::Class* exception_type = exception->GetClass(); diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc index 2162dcc611..55fd301617 100644 --- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -47,6 +47,11 @@ class PortableArgumentVisitor { #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 #define PORTABLE_STACK_ARG_SKIP 4 +#elif defined(__x86_64__) +// TODO: implement and check these. +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 16 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 96 +#define PORTABLE_STACK_ARG_SKIP 0 #else #error "Unsupported architecture" #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 @@ -387,43 +392,42 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called // Incompatible class change should have been handled in resolve method. CHECK(!called->CheckIncompatibleClassChange(invoke_type)); } - const void* code = NULL; + const void* code = nullptr; if (LIKELY(!thread->IsExceptionPending())) { // Ensure that the called method's class is initialized. SirtRef<mirror::Class> called_class(thread, called->GetDeclaringClass()); linker->EnsureInitialized(called_class, true, true); if (LIKELY(called_class->IsInitialized())) { - code = called->GetEntryPointFromCompiledCode(); + code = called->GetEntryPointFromPortableCompiledCode(); // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } + if (code == nullptr) { + bool have_portable_code; + code = linker->GetPortableOatCodeFor(called, &have_portable_code); } } else if (called_class->IsInitializing()) { if (invoke_type == kStatic) { // Class is still initializing, go to oat and grab code (trampoline must be left in place // until class is initialized to stop races between threads). - code = linker->GetOatCodeFor(called); + bool have_portable_code; + code = linker->GetPortableOatCodeFor(called, &have_portable_code); } else { // No trampoline for non-static methods. - code = called->GetEntryPointFromCompiledCode(); + code = called->GetEntryPointFromPortableCompiledCode(); // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } + if (code == nullptr) { + bool have_portable_code; + code = linker->GetPortableOatCodeFor(called, &have_portable_code); } } } else { DCHECK(called_class->IsErroneous()); } } - if (LIKELY(code != NULL)) { + if (LIKELY(code != nullptr)) { // Expect class to at least be initializing. DCHECK(called->GetDeclaringClass()->IsInitializing()); // Don't want infinite recursion. - DCHECK(code != GetResolutionTrampoline(linker)); + DCHECK(code != GetPortableResolutionTrampoline(linker)); // Set up entry into main method *called_addr = called; } diff --git a/runtime/entrypoints/quick/quick_cast_entrypoints.cc b/runtime/entrypoints/quick/quick_cast_entrypoints.cc index ae53d6c7be..a6ab69b75d 100644 --- a/runtime/entrypoints/quick/quick_cast_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_cast_entrypoints.cc @@ -20,8 +20,7 @@ namespace art { // Assignable test for code, won't throw. Null and equality tests already performed -extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass, - const mirror::Class* ref_class) +extern "C" uint32_t artIsAssignableFromCode(mirror::Class* klass, mirror::Class* ref_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(klass != NULL); DCHECK(ref_class != NULL); diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index 003047a5f8..ab428a546f 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -26,7 +26,7 @@ namespace art { extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -38,7 +38,7 @@ extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx, } extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Called when method->dex_cache_resolved_types_[] misses. @@ -47,7 +47,7 @@ extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, } extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc index 0a533bdfbc..93ff7aa9fa 100644 --- a/runtime/entrypoints/quick/quick_field_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc @@ -26,7 +26,7 @@ namespace art { extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, @@ -43,7 +43,7 @@ extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, } extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, @@ -60,17 +60,17 @@ extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, } extern "C" mirror::Object* artGetObjStaticFromCode(uint32_t field_idx, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectRead, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(field->GetDeclaringClass()); } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode<StaticObjectRead, true>(field_idx, referrer, self, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { return field->GetObj(field->GetDeclaringClass()); } @@ -78,7 +78,7 @@ extern "C" mirror::Object* artGetObjStaticFromCode(uint32_t field_idx, } extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, @@ -101,7 +101,7 @@ extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object* } extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, @@ -124,18 +124,18 @@ extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object* } extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj, - const mirror::ArtMethod* referrer, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL && obj != NULL)) { return field->GetObj(obj); } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode<InstanceObjectRead, true>(field_idx, referrer, self, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { if (UNLIKELY(obj == NULL)) { ThrowLocation throw_location = self->GetCurrentLocationForThrow(); @@ -148,7 +148,7 @@ extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror: } extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, @@ -166,7 +166,7 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value, return -1; // failure } -extern "C" int artSet64StaticFromCode(uint32_t field_idx, const mirror::ArtMethod* referrer, +extern "C" int artSet64StaticFromCode(uint32_t field_idx, mirror::ArtMethod* referrer, uint64_t new_value, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, @@ -185,11 +185,11 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const mirror::ArtMetho } extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_value, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { if (LIKELY(!FieldHelper(field).IsPrimitiveType())) { field->SetObj(field->GetDeclaringClass(), new_value); @@ -198,7 +198,7 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_v } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, self, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { field->SetObj(field->GetDeclaringClass(), new_value); return 0; // success @@ -207,7 +207,7 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_v } extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint32_t new_value, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, @@ -261,18 +261,18 @@ extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj, mirror::Object* new_value, - const mirror::ArtMethod* referrer, Thread* self, + mirror::ArtMethod* referrer, Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL && obj != NULL)) { field->SetObj(obj, new_value); return 0; // success } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, self, - sizeof(mirror::Object*)); + sizeof(mirror::HeapReference<mirror::Object>)); if (LIKELY(field != NULL)) { if (UNLIKELY(obj == NULL)) { ThrowLocation throw_location = self->GetCurrentLocationForThrow(); diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc index ca0c92e6d5..8dac75039c 100644 --- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc @@ -56,7 +56,7 @@ extern "C" int artHandleFillArrayDataFromCode(mirror::Array* array, return -1; // Error } uint32_t size_in_bytes = payload->element_count * payload->element_width; - memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); + memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes); return 0; // Success } diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc index 5a1b3e84ad..c081768b73 100644 --- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc @@ -124,21 +124,23 @@ extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_me return 0; // Failure. } } - const void* code = method->GetEntryPointFromCompiledCode(); + const void* code = method->GetEntryPointFromQuickCompiledCode(); -#ifndef NDEBUG // When we return, the caller will branch to this address, so it had better not be 0! - if (UNLIKELY(code == NULL)) { + if (kIsDebugBuild && UNLIKELY(code == nullptr)) { MethodHelper mh(method); LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) << " location: " << mh.GetDexFile().GetLocation(); } -#endif - +#ifdef __LP64__ + UNIMPLEMENTED(FATAL); + return 0; +#else uint32_t method_uint = reinterpret_cast<uint32_t>(method); uint64_t code_uint = reinterpret_cast<uint32_t>(code); uint64_t result = ((code_uint << 32) | method_uint); return result; +#endif } template<InvokeType type, bool access_check> @@ -156,21 +158,23 @@ uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, } } DCHECK(!self->IsExceptionPending()); - const void* code = method->GetEntryPointFromCompiledCode(); + const void* code = method->GetEntryPointFromQuickCompiledCode(); -#ifndef NDEBUG // When we return, the caller will branch to this address, so it had better not be 0! - if (UNLIKELY(code == NULL)) { + if (kIsDebugBuild && UNLIKELY(code == NULL)) { MethodHelper mh(method); LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) << " location: " << mh.GetDexFile().GetLocation(); } -#endif - +#ifdef __LP64__ + UNIMPLEMENTED(FATAL); + return 0; +#else uint32_t method_uint = reinterpret_cast<uint32_t>(method); uint64_t code_uint = reinterpret_cast<uint32_t>(code); uint64_t result = ((code_uint << 32) | method_uint); return result; +#endif } // Explicit template declarations of artInvokeCommon for all invoke types. diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index b58938430e..9f301907e2 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -97,6 +97,12 @@ class QuickArgumentVisitor { #define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 28 #define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32 #define QUICK_STACK_ARG_SKIP 16 +#elif defined(__x86_64__) +// TODO: implement and check these. +#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 +#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 56 +#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 +#define QUICK_STACK_ARG_SKIP 32 #else #error "Unsupported architecture" #define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 @@ -567,15 +573,15 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, SirtRef<mirror::Class> called_class(soa.Self(), called->GetDeclaringClass()); linker->EnsureInitialized(called_class, true, true); if (LIKELY(called_class->IsInitialized())) { - code = called->GetEntryPointFromCompiledCode(); + code = called->GetEntryPointFromQuickCompiledCode(); } else if (called_class->IsInitializing()) { if (invoke_type == kStatic) { // Class is still initializing, go to oat and grab code (trampoline must be left in place // until class is initialized to stop races between threads). - code = linker->GetOatCodeFor(called); + code = linker->GetQuickOatCodeFor(called); } else { // No trampoline for non-static methods. - code = called->GetEntryPointFromCompiledCode(); + code = called->GetEntryPointFromQuickCompiledCode(); } } else { DCHECK(called_class->IsErroneous()); diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index 978faebbf1..f7b621fb7e 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -76,7 +76,7 @@ class ExceptionTest : public CommonTest { method_f_ = my_klass_->FindVirtualMethod("f", "()I"); ASSERT_TRUE(method_f_ != NULL); method_f_->SetFrameSizeInBytes(kStackAlignment); - method_f_->SetEntryPointFromCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); + method_f_->SetEntryPointFromQuickCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); method_f_->SetMappingTable(&fake_mapping_data_.GetData()[0]); method_f_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_f_->SetNativeGcMap(&fake_gc_map_[0]); @@ -84,7 +84,7 @@ class ExceptionTest : public CommonTest { method_g_ = my_klass_->FindVirtualMethod("g", "(I)V"); ASSERT_TRUE(method_g_ != NULL); method_g_->SetFrameSizeInBytes(kStackAlignment); - method_g_->SetEntryPointFromCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); + method_g_->SetEntryPointFromQuickCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); method_g_->SetMappingTable(&fake_mapping_data_.GetData()[0]); method_g_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_g_->SetNativeGcMap(&fake_gc_map_[0]); @@ -105,6 +105,7 @@ class ExceptionTest : public CommonTest { }; TEST_F(ExceptionTest, FindCatchHandler) { + ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset()); ASSERT_TRUE(code_item != NULL); @@ -151,51 +152,51 @@ TEST_F(ExceptionTest, StackTraceElement) { ASSERT_EQ(kStackAlignment, 16U); ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t)); -#if !defined(ART_USE_PORTABLE_COMPILER) - // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code - // to dex pc 3. - const uint32_t dex_pc = 3; - - // Create/push fake 16byte stack frame for method g - fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); - fake_stack.push_back(0); - fake_stack.push_back(0); - fake_stack.push_back(method_f_->ToNativePc(dex_pc)); // return pc - - // Create/push fake 16byte stack frame for method f - fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); - fake_stack.push_back(0); - fake_stack.push_back(0); - fake_stack.push_back(0xEBAD6070); // return pc - - // Pull Method* of NULL to terminate the trace - fake_stack.push_back(0); - - // Push null values which will become null incoming arguments. - fake_stack.push_back(0); - fake_stack.push_back(0); - fake_stack.push_back(0); - - // Set up thread to appear as if we called out of method_g_ at pc dex 3 - thread->SetTopOfStack(&fake_stack[0], method_g_->ToNativePc(dex_pc)); // return pc -#else - // Create/push fake 20-byte shadow frame for method g - fake_stack.push_back(0); - fake_stack.push_back(0); - fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); - fake_stack.push_back(3); - fake_stack.push_back(0); - - // Create/push fake 20-byte shadow frame for method f - fake_stack.push_back(0); - fake_stack.push_back(0); - fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); - fake_stack.push_back(3); - fake_stack.push_back(0); - - thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[5])); - thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[0])); -#endif + if (!kUsePortableCompiler) { + // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code + // to dex pc 3. + const uint32_t dex_pc = 3; + + // Create/push fake 16byte stack frame for method g + fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); + fake_stack.push_back(0); + fake_stack.push_back(0); + fake_stack.push_back(method_f_->ToNativePc(dex_pc)); // return pc + + // Create/push fake 16byte stack frame for method f + fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); + fake_stack.push_back(0); + fake_stack.push_back(0); + fake_stack.push_back(0xEBAD6070); // return pc + + // Pull Method* of NULL to terminate the trace + fake_stack.push_back(0); + + // Push null values which will become null incoming arguments. + fake_stack.push_back(0); + fake_stack.push_back(0); + fake_stack.push_back(0); + + // Set up thread to appear as if we called out of method_g_ at pc dex 3 + thread->SetTopOfStack(&fake_stack[0], method_g_->ToNativePc(dex_pc)); // return pc + } else { + // Create/push fake 20-byte shadow frame for method g + fake_stack.push_back(0); + fake_stack.push_back(0); + fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_)); + fake_stack.push_back(3); + fake_stack.push_back(0); + + // Create/push fake 20-byte shadow frame for method f + fake_stack.push_back(0); + fake_stack.push_back(0); + fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_)); + fake_stack.push_back(3); + fake_stack.push_back(0); + + thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[5])); + thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[0])); + } jobject internal = thread->CreateInternalStackTrace(soa); ASSERT_TRUE(internal != NULL); diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 02e01b86f7..ea8f89cf2b 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -19,7 +19,7 @@ #include <string> -#include "atomic_integer.h" +#include "atomic.h" #include "base/logging.h" #include "base/macros.h" #include "UniquePtr.h" @@ -165,7 +165,7 @@ class AtomicStack { void Init() { std::string error_msg; mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T), - PROT_READ | PROT_WRITE, &error_msg)); + PROT_READ | PROT_WRITE, false, &error_msg)); CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg; byte* addr = mem_map_->Begin(); CHECK(addr != NULL); diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index e099137f7d..714e6f7123 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -57,7 +57,7 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { std::string error_msg; UniquePtr<MemMap> mem_map(MemMap::MapAnonymous("card table", NULL, capacity + 256, PROT_READ | PROT_WRITE, - &error_msg)); + false, &error_msg)); CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg; // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we // don't clear the card table to avoid unnecessary pages being allocated @@ -72,11 +72,11 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { byte* biased_begin = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(cardtable_begin) - (reinterpret_cast<uintptr_t>(heap_begin) >> kCardShift)); if (((uintptr_t)biased_begin & 0xff) != kCardDirty) { - int delta = kCardDirty - (reinterpret_cast<int>(biased_begin) & 0xff); + int delta = kCardDirty - (reinterpret_cast<uintptr_t>(biased_begin) & 0xff); offset = delta + (delta < 0 ? 0x100 : 0); biased_begin += offset; } - CHECK_EQ(reinterpret_cast<int>(biased_begin) & 0xff, kCardDirty); + CHECK_EQ(reinterpret_cast<uintptr_t>(biased_begin) & 0xff, kCardDirty); return new CardTable(mem_map.release(), biased_begin, offset); } diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index 6d9dde7151..0225f29fef 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -82,9 +82,9 @@ class ModUnionUpdateObjectReferencesVisitor { if (ref != nullptr) { Object* new_ref = visitor_(ref, arg_); if (new_ref != ref) { - // Use SetFieldPtr to avoid card mark as an optimization which reduces dirtied pages and - // improves performance. - obj->SetFieldPtr(offset, new_ref, true); + // Use SetFieldObjectWithoutWriteBarrier to avoid card mark as an optimization which + // reduces dirtied pages and improves performance. + obj->SetFieldObjectWithoutWriteBarrier(offset, new_ref, true); } } } @@ -122,9 +122,8 @@ void ModUnionTableReferenceCache::ClearCards() { class AddToReferenceArrayVisitor { public: explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table, - std::vector<Object**>* references) - : mod_union_table_(mod_union_table), - references_(references) { + std::vector<mirror::HeapReference<Object>*>* references) + : mod_union_table_(mod_union_table), references_(references) { } // Extra parameters are required since we use this same visitor signature for checking objects. @@ -133,19 +132,19 @@ class AddToReferenceArrayVisitor { // Only add the reference if it is non null and fits our criteria. if (ref != nullptr && mod_union_table_->AddReference(obj, ref)) { // Push the adddress of the reference. - references_->push_back(obj->GetFieldObjectAddr(offset)); + references_->push_back(obj->GetFieldObjectReferenceAddr(offset)); } } private: ModUnionTableReferenceCache* const mod_union_table_; - std::vector<Object**>* const references_; + std::vector<mirror::HeapReference<Object>*>* const references_; }; class ModUnionReferenceVisitor { public: explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table, - std::vector<Object**>* references) + std::vector<mirror::HeapReference<Object>*>* references) : mod_union_table_(mod_union_table), references_(references) { } @@ -160,7 +159,7 @@ class ModUnionReferenceVisitor { } private: ModUnionTableReferenceCache* const mod_union_table_; - std::vector<Object**>* const references_; + std::vector<mirror::HeapReference<Object>*>* const references_; }; class CheckReferenceVisitor { @@ -173,7 +172,7 @@ class CheckReferenceVisitor { // Extra parameters are required since we use this same visitor signature for checking objects. // TODO: Fixme when anotatalysis works with visitors. - void operator()(const Object* obj, const Object* ref, + void operator()(Object* obj, Object* ref, const MemberOffset& /* offset */, bool /* is_static */) const SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) { Heap* heap = mod_union_table_->GetHeap(); @@ -219,8 +218,8 @@ class ModUnionCheckReferences { void ModUnionTableReferenceCache::Verify() { // Start by checking that everything in the mod union table is marked. for (const auto& ref_pair : references_) { - for (Object** ref : ref_pair.second) { - CHECK(heap_->IsLiveObjectLocked(*ref)); + for (mirror::HeapReference<Object>* ref : ref_pair.second) { + CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr())); } } @@ -231,8 +230,8 @@ void ModUnionTableReferenceCache::Verify() { const byte* card = ref_pair.first; if (*card == CardTable::kCardClean) { std::set<const Object*> reference_set; - for (Object** obj_ptr : ref_pair.second) { - reference_set.insert(*obj_ptr); + for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) { + reference_set.insert(obj_ptr->AsMirrorPtr()); } ModUnionCheckReferences visitor(this, reference_set); uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card)); @@ -255,8 +254,8 @@ void ModUnionTableReferenceCache::Dump(std::ostream& os) { uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr)); uintptr_t end = start + CardTable::kCardSize; os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{"; - for (Object** ref : ref_pair.second) { - os << reinterpret_cast<const void*>(*ref) << ","; + for (mirror::HeapReference<Object>* ref : ref_pair.second) { + os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ","; } os << "},"; } @@ -266,7 +265,7 @@ void ModUnionTableReferenceCache::UpdateAndMarkReferences(RootVisitor visitor, v Heap* heap = GetHeap(); CardTable* card_table = heap->GetCardTable(); - std::vector<Object**> cards_references; + std::vector<mirror::HeapReference<Object>*> cards_references; ModUnionReferenceVisitor add_visitor(this, &cards_references); for (const auto& card : cleared_cards_) { @@ -294,13 +293,13 @@ void ModUnionTableReferenceCache::UpdateAndMarkReferences(RootVisitor visitor, v cleared_cards_.clear(); size_t count = 0; for (const auto& ref : references_) { - for (const auto& obj_ptr : ref.second) { - Object* obj = *obj_ptr; + for (mirror::HeapReference<Object>* obj_ptr : ref.second) { + Object* obj = obj_ptr->AsMirrorPtr(); if (obj != nullptr) { Object* new_obj = visitor(obj, arg); // Avoid dirtying pages in the image unless necessary. if (new_obj != obj) { - *obj_ptr = new_obj; + obj_ptr->Assign(new_obj); } } } diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h index 5a99f1bb41..a89dbd1aaf 100644 --- a/runtime/gc/accounting/mod_union_table.h +++ b/runtime/gc/accounting/mod_union_table.h @@ -112,20 +112,23 @@ class ModUnionTableReferenceCache : public ModUnionTable { // Exclusive lock is required since verify uses SpaceBitmap::VisitMarkedRange and // VisitMarkedRange can't know if the callback will modify the bitmap or not. - void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + void Verify() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // Function that tells whether or not to add a reference to the table. virtual bool AddReference(const mirror::Object* obj, const mirror::Object* ref) = 0; - void Dump(std::ostream& os); + void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); protected: // Cleared card array, used to update the mod-union table. ModUnionTable::CardSet cleared_cards_; // Maps from dirty cards to their corresponding alloc space references. - SafeMap<const byte*, std::vector<mirror::Object**>, std::less<const byte*>, - GcAllocator<std::pair<const byte*, std::vector<mirror::Object**> > > > references_; + SafeMap<const byte*, std::vector<mirror::HeapReference<mirror::Object>*>, std::less<const byte*>, + GcAllocator<std::pair<const byte*, std::vector<mirror::HeapReference<mirror::Object>*> > > > + references_; }; // Card caching implementation. Keeps track of which cards we cleared and only this information. diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index 01c70facdf..d6d1b3e8aa 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -37,9 +37,11 @@ inline bool SpaceBitmap::AtomicTestAndSet(const mirror::Object* obj) { old_word = *address; // Fast path: The bit is already set. if ((old_word & mask) != 0) { + DCHECK(Test(obj)); return true; } } while (!__sync_bool_compare_and_swap(address, old_word, old_word | mask)); + DCHECK(Test(obj)); return false; } @@ -56,6 +58,15 @@ template <typename Visitor> void SpaceBitmap::VisitMarkedRange(uintptr_t visit_begin, uintptr_t visit_end, const Visitor& visitor) const { DCHECK_LT(visit_begin, visit_end); +#ifdef __LP64__ + // TODO: make the optimized code below work in the 64bit case. + for (uintptr_t i = visit_begin; i < visit_end; i += kAlignment) { + mirror::Object* obj = reinterpret_cast<mirror::Object*>(i); + if (Test(obj)) { + visitor(obj); + } + } +#else const size_t bit_index_start = (visit_begin - heap_begin_) / kAlignment; const size_t bit_index_end = (visit_end - heap_begin_ - 1) / kAlignment; @@ -114,6 +125,7 @@ void SpaceBitmap::VisitMarkedRange(uintptr_t visit_begin, uintptr_t visit_end, visitor(obj); edge_word ^= static_cast<size_t>(kWordHighBitMask) >> shift; } +#endif } inline bool SpaceBitmap::Modify(const mirror::Object* obj, bool do_set) { @@ -130,6 +142,7 @@ inline bool SpaceBitmap::Modify(const mirror::Object* obj, bool do_set) { } else { *address = old_word & ~mask; } + DCHECK_EQ(Test(obj), do_set); return (old_word & mask) != 0; } diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index b831843e61..a080beedb0 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -64,7 +64,7 @@ SpaceBitmap* SpaceBitmap::Create(const std::string& name, byte* heap_begin, size size_t bitmap_size = OffsetToIndex(RoundUp(heap_capacity, kAlignment * kBitsPerWord)) * kWordSize; std::string error_msg; UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), NULL, bitmap_size, - PROT_READ | PROT_WRITE, &error_msg)); + PROT_READ | PROT_WRITE, false, &error_msg)); if (UNLIKELY(mem_map.get() == nullptr)) { LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return NULL; diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h index 2d6cde52af..aa074ebc8a 100644 --- a/runtime/gc/accounting/space_bitmap.h +++ b/runtime/gc/accounting/space_bitmap.h @@ -72,8 +72,8 @@ class SpaceBitmap { } // Pack the bits in backwards so they come out in address order when using CLZ. - static word OffsetToMask(uintptr_t offset_) { - return static_cast<uintptr_t>(kWordHighBitMask) >> ((offset_ / kAlignment) % kBitsPerWord); + static word OffsetToMask(uintptr_t offset) { + return static_cast<uintptr_t>(kWordHighBitMask) >> ((offset / kAlignment) % kBitsPerWord); } inline bool Set(const mirror::Object* obj) { diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h index 9c1c5dc281..d148ae5b4a 100644 --- a/runtime/gc/collector/mark_sweep-inl.h +++ b/runtime/gc/collector/mark_sweep-inl.h @@ -118,7 +118,7 @@ inline void MarkSweep::VisitFieldsReferences(mirror::Object* obj, uint32_t ref_o while (ref_offsets != 0) { size_t right_shift = CLZ(ref_offsets); MemberOffset field_offset = CLASS_OFFSET_FROM_CLZ(right_shift); - mirror::Object* ref = obj->GetFieldObject<mirror::Object*>(field_offset, false); + mirror::Object* ref = obj->GetFieldObject<mirror::Object>(field_offset, false); visitor(obj, ref, field_offset, is_static); ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift); } @@ -127,17 +127,17 @@ inline void MarkSweep::VisitFieldsReferences(mirror::Object* obj, uint32_t ref_o // walk up the class inheritance hierarchy and find reference // offsets the hard way. In the static case, just consider this // class. - for (const mirror::Class* klass = is_static ? obj->AsClass() : obj->GetClass(); - klass != NULL; - klass = is_static ? NULL : klass->GetSuperClass()) { + for (mirror::Class* klass = is_static ? obj->AsClass() : obj->GetClass(); + klass != nullptr; + klass = is_static ? nullptr : klass->GetSuperClass()) { size_t num_reference_fields = (is_static ? klass->NumReferenceStaticFields() : klass->NumReferenceInstanceFields()); for (size_t i = 0; i < num_reference_fields; ++i) { mirror::ArtField* field = (is_static ? klass->GetStaticField(i) - : klass->GetInstanceField(i)); + : klass->GetInstanceField(i)); MemberOffset field_offset = field->GetOffset(); - mirror::Object* ref = obj->GetFieldObject<mirror::Object*>(field_offset, false); + mirror::Object* ref = obj->GetFieldObject<mirror::Object>(field_offset, false); visitor(obj, ref, field_offset, is_static); } } @@ -150,7 +150,7 @@ inline void MarkSweep::VisitObjectArrayReferences(mirror::ObjectArray<mirror::Ob const size_t length = static_cast<size_t>(array->GetLength()); for (size_t i = 0; i < length; ++i) { mirror::Object* element = array->GetWithoutChecks(static_cast<int32_t>(i)); - const size_t width = sizeof(mirror::Object*); + const size_t width = sizeof(mirror::HeapReference<mirror::Object>); MemberOffset offset(i * width + mirror::Array::DataOffset(width).Int32Value()); visitor(array, element, offset, false); } diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 0c27a3be59..bfedac733d 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_GC_COLLECTOR_MARK_SWEEP_H_ #define ART_RUNTIME_GC_COLLECTOR_MARK_SWEEP_H_ -#include "atomic_integer.h" +#include "atomic.h" #include "barrier.h" #include "base/macros.h" #include "base/mutex.h" diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index 3fb78b0452..03307f5310 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -600,9 +600,9 @@ void SemiSpace::ScanObject(Object* obj) { if (new_address != ref) { DCHECK(new_address != nullptr); // Don't need to mark the card since we updating the object address and not changing the - // actual objects its pointing to. Using SetFieldPtr is better in this case since it does not - // dirty cards and use additional memory. - obj->SetFieldPtr(offset, new_address, false); + // actual objects its pointing to. Using SetFieldObjectWithoutWriteBarrier is better in this + // case since it does not dirty cards and use additional memory. + obj->SetFieldObjectWithoutWriteBarrier(offset, new_address, false); } }, kMovingClasses); mirror::Class* klass = obj->GetClass(); diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index f81a7c2c88..685b33cafe 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_GC_COLLECTOR_SEMI_SPACE_H_ #define ART_RUNTIME_GC_COLLECTOR_SEMI_SPACE_H_ -#include "atomic_integer.h" +#include "atomic.h" #include "barrier.h" #include "base/macros.h" #include "base/mutex.h" diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 309adb7416..b1bbfc61ee 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -231,7 +231,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max std::string error_str; post_zygote_non_moving_space_mem_map_.reset( MemMap::MapAnonymous("post zygote non-moving space", nullptr, 64 * MB, - PROT_READ | PROT_WRITE, &error_str)); + PROT_READ | PROT_WRITE, true, &error_str)); CHECK(post_zygote_non_moving_space_mem_map_.get() != nullptr) << error_str; heap_begin = std::min(post_zygote_non_moving_space_mem_map_->Begin(), heap_begin); heap_end = std::max(post_zygote_non_moving_space_mem_map_->End(), heap_end); @@ -653,15 +653,15 @@ void Heap::ProcessReferences(TimingLogger& timings, bool clear_soft, bool Heap::IsEnqueued(mirror::Object* ref) const { // Since the references are stored as cyclic lists it means that once enqueued, the pending next // will always be non-null. - return ref->GetFieldObject<mirror::Object*>(GetReferencePendingNextOffset(), false) != nullptr; + return ref->GetFieldObject<mirror::Object>(GetReferencePendingNextOffset(), false) != nullptr; } -bool Heap::IsEnqueuable(const mirror::Object* ref) const { +bool Heap::IsEnqueuable(mirror::Object* ref) const { DCHECK(ref != nullptr); const mirror::Object* queue = - ref->GetFieldObject<mirror::Object*>(GetReferenceQueueOffset(), false); + ref->GetFieldObject<mirror::Object>(GetReferenceQueueOffset(), false); const mirror::Object* queue_next = - ref->GetFieldObject<mirror::Object*>(GetReferenceQueueNextOffset(), false); + ref->GetFieldObject<mirror::Object>(GetReferenceQueueNextOffset(), false); return queue != nullptr && queue_next == nullptr; } @@ -720,7 +720,7 @@ static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation) { std::ostringstream oss; - int64_t total_bytes_free = GetFreeMemory(); + size_t total_bytes_free = GetFreeMemory(); oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free << " free bytes"; // If the allocation failed due to fragmentation, print out the largest continuous allocation. @@ -805,7 +805,7 @@ bool Heap::IsHeapAddress(const mirror::Object* obj) const { return FindSpaceFromObject(obj, true) != nullptr; } -bool Heap::IsLiveObjectLocked(const mirror::Object* obj, bool search_allocation_stack, +bool Heap::IsLiveObjectLocked(mirror::Object* obj, bool search_allocation_stack, bool search_live_stack, bool sorted) { if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) { return false; @@ -874,7 +874,7 @@ bool Heap::IsLiveObjectLocked(const mirror::Object* obj, bool search_allocation_ return false; } -void Heap::VerifyObjectImpl(const mirror::Object* obj) { +void Heap::VerifyObjectImpl(mirror::Object* obj) { if (Thread::Current() == NULL || Runtime::Current()->GetThreadList()->GetLockOwner() == Thread::Current()->GetTid()) { return; @@ -887,9 +887,9 @@ bool Heap::VerifyClassClass(const mirror::Class* c) const { // to run const byte* raw_addr = reinterpret_cast<const byte*>(c) + mirror::Object::ClassOffset().Int32Value(); - const mirror::Class* c_c = *reinterpret_cast<mirror::Class* const *>(raw_addr); + mirror::Class* c_c = reinterpret_cast<mirror::HeapReference<mirror::Class> const *>(raw_addr)->AsMirrorPtr(); raw_addr = reinterpret_cast<const byte*>(c_c) + mirror::Object::ClassOffset().Int32Value(); - const mirror::Class* c_c_c = *reinterpret_cast<mirror::Class* const *>(raw_addr); + mirror::Class* c_c_c = reinterpret_cast<mirror::HeapReference<mirror::Class> const *>(raw_addr)->AsMirrorPtr(); return c_c == c_c_c; } @@ -910,7 +910,7 @@ void Heap::DumpSpaces(std::ostream& stream) { } } -void Heap::VerifyObjectBody(const mirror::Object* obj) { +void Heap::VerifyObjectBody(mirror::Object* obj) { CHECK(IsAligned<kObjectAlignment>(obj)) << "Object isn't aligned: " << obj; // Ignore early dawn of the universe verifications. if (UNLIKELY(static_cast<size_t>(num_bytes_allocated_.Load()) < 10 * KB)) { @@ -918,7 +918,7 @@ void Heap::VerifyObjectBody(const mirror::Object* obj) { } const byte* raw_addr = reinterpret_cast<const byte*>(obj) + mirror::Object::ClassOffset().Int32Value(); - const mirror::Class* c = *reinterpret_cast<mirror::Class* const *>(raw_addr); + mirror::Class* c = reinterpret_cast<mirror::HeapReference<mirror::Class> const *>(raw_addr)->AsMirrorPtr(); if (UNLIKELY(c == NULL)) { LOG(FATAL) << "Null class in object: " << obj; } else if (UNLIKELY(!IsAligned<kObjectAlignment>(c))) { @@ -949,7 +949,7 @@ void Heap::VerifyHeap() { GetLiveBitmap()->Walk(Heap::VerificationCallback, this); } -void Heap::RecordFree(int64_t freed_objects, int64_t freed_bytes) { +void Heap::RecordFree(size_t freed_objects, size_t freed_bytes) { DCHECK_LE(freed_bytes, num_bytes_allocated_.Load()); num_bytes_allocated_.FetchAndSub(freed_bytes); if (Runtime::Current()->HasStatsEnabled()) { @@ -1059,9 +1059,9 @@ class InstanceCounter { : classes_(classes), use_is_assignable_from_(use_is_assignable_from), counts_(counts) { } - void operator()(const mirror::Object* o) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + void operator()(mirror::Object* o) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { for (size_t i = 0; i < classes_.size(); ++i) { - const mirror::Class* instance_class = o->GetClass(); + mirror::Class* instance_class = o->GetClass(); if (use_is_assignable_from_) { if (instance_class != NULL && classes_[i]->IsAssignableFrom(instance_class)) { ++counts_[i]; @@ -1103,11 +1103,11 @@ class InstanceCollector { : class_(c), max_count_(max_count), instances_(instances) { } - void operator()(const mirror::Object* o) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const mirror::Class* instance_class = o->GetClass(); + void operator()(mirror::Object* o) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Class* instance_class = o->GetClass(); if (instance_class == class_) { if (max_count_ == 0 || instances_.size() < max_count_) { - instances_.push_back(const_cast<mirror::Object*>(o)); + instances_.push_back(o); } } } @@ -1190,8 +1190,8 @@ void Heap::TransitionCollector(CollectorType collector_type) { return; } uint64_t start_time = NanoTime(); - int32_t before_size = GetTotalMemory(); - int32_t before_allocated = num_bytes_allocated_.Load(); + uint32_t before_size = GetTotalMemory(); + uint32_t before_allocated = num_bytes_allocated_.Load(); ThreadList* tl = Runtime::Current()->GetThreadList(); Thread* self = Thread::Current(); ScopedThreadStateChange tsc(self, kWaitingPerformingGc); @@ -1718,7 +1718,7 @@ class VerifyReferenceVisitor { // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for smarter // analysis on visitors. - void operator()(const mirror::Object* obj, const mirror::Object* ref, + void operator()(mirror::Object* obj, mirror::Object* ref, const MemberOffset& offset, bool /* is_static */) const NO_THREAD_SAFETY_ANALYSIS { if (ref == nullptr || IsLive(ref)) { @@ -1813,7 +1813,7 @@ class VerifyReferenceVisitor { } } - bool IsLive(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS { + bool IsLive(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS { return heap_->IsLiveObjectLocked(obj, true, false, true); } @@ -1898,7 +1898,7 @@ class VerifyReferenceCardVisitor { // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for // annotalysis on visitors. - void operator()(const mirror::Object* obj, const mirror::Object* ref, const MemberOffset& offset, + void operator()(mirror::Object* obj, mirror::Object* ref, const MemberOffset& offset, bool is_static) const NO_THREAD_SAFETY_ANALYSIS { // Filter out class references since changing an object's class does not mark the card as dirty. // Also handles large objects, since the only reference they hold is a class reference. @@ -1926,13 +1926,13 @@ class VerifyReferenceCardVisitor { // Print which field of the object is dead. if (!obj->IsObjectArray()) { - const mirror::Class* klass = is_static ? obj->AsClass() : obj->GetClass(); + mirror::Class* klass = is_static ? obj->AsClass() : obj->GetClass(); CHECK(klass != NULL); - const mirror::ObjectArray<mirror::ArtField>* fields = is_static ? klass->GetSFields() - : klass->GetIFields(); + mirror::ObjectArray<mirror::ArtField>* fields = is_static ? klass->GetSFields() + : klass->GetIFields(); CHECK(fields != NULL); for (int32_t i = 0; i < fields->GetLength(); ++i) { - const mirror::ArtField* cur = fields->Get(i); + mirror::ArtField* cur = fields->Get(i); if (cur->GetOffset().Int32Value() == offset.Int32Value()) { LOG(ERROR) << (is_static ? "Static " : "") << "field in the live stack is " << PrettyField(cur); @@ -1940,7 +1940,7 @@ class VerifyReferenceCardVisitor { } } } else { - const mirror::ObjectArray<mirror::Object>* object_array = + mirror::ObjectArray<mirror::Object>* object_array = obj->AsObjectArray<mirror::Object>(); for (int32_t i = 0; i < object_array->GetLength(); ++i) { if (object_array->Get(i) == ref) { @@ -2278,14 +2278,14 @@ void Heap::SetReferenceReferent(mirror::Object* reference, mirror::Object* refer mirror::Object* Heap::GetReferenceReferent(mirror::Object* reference) { DCHECK(reference != NULL); DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U); - return reference->GetFieldObject<mirror::Object*>(reference_referent_offset_, true); + return reference->GetFieldObject<mirror::Object>(reference_referent_offset_, true); } void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) { ScopedObjectAccess soa(self); JValue result; ArgArray arg_array(NULL, 0); - arg_array.Append(reinterpret_cast<uint32_t>(object)); + arg_array.Append(object); soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V'); } @@ -2299,7 +2299,7 @@ void Heap::EnqueueClearedReferences() { ScopedObjectAccess soa(self); JValue result; ArgArray arg_array(NULL, 0); - arg_array.Append(reinterpret_cast<uint32_t>(cleared_references_.GetList())); + arg_array.Append(cleared_references_.GetList()); soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V'); } @@ -2477,8 +2477,8 @@ void Heap::RegisterNativeFree(JNIEnv* env, int bytes) { } while (!native_bytes_allocated_.CompareAndSwap(expected_size, new_size)); } -int64_t Heap::GetTotalMemory() const { - int64_t ret = 0; +size_t Heap::GetTotalMemory() const { + size_t ret = 0; for (const auto& space : continuous_spaces_) { // Currently don't include the image space. if (!space->IsImageSpace()) { diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 26d67a1841..499d27ca0e 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -21,7 +21,7 @@ #include <string> #include <vector> -#include "atomic_integer.h" +#include "atomic.h" #include "base/timing_logger.h" #include "gc/accounting/atomic_stack.h" #include "gc/accounting/card_table.h" @@ -204,14 +204,14 @@ class Heap { void ChangeCollector(CollectorType collector_type); // The given reference is believed to be to an object in the Java heap, check the soundness of it. - void VerifyObjectImpl(const mirror::Object* o); - void VerifyObject(const mirror::Object* o) { + void VerifyObjectImpl(mirror::Object* o); + void VerifyObject(mirror::Object* o) { if (o != nullptr && this != nullptr && verify_object_mode_ > kNoHeapVerification) { VerifyObjectImpl(o); } } // Check that c.getClass() == c.getClass().getClass(). - bool VerifyClassClass(const mirror::Class* c) const; + bool VerifyClassClass(const mirror::Class* c) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Check sanity of all live references. void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_); @@ -232,9 +232,9 @@ class Heap { // Returns true if 'obj' is a live heap object, false otherwise (including for invalid addresses). // Requires the heap lock to be held. - bool IsLiveObjectLocked(const mirror::Object* obj, bool search_allocation_stack = true, + bool IsLiveObjectLocked(mirror::Object* obj, bool search_allocation_stack = true, bool search_live_stack = true, bool sorted = false) - SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_); // Returns true if there is any chance that the object (obj) will move. bool IsMovableObject(const mirror::Object* obj) const; @@ -358,7 +358,7 @@ class Heap { // Freed bytes can be negative in cases where we copy objects from a compacted space to a // free-list backed space. - void RecordFree(int64_t freed_objects, int64_t freed_bytes); + void RecordFree(size_t freed_objects, size_t freed_bytes); // Must be called if a field of an Object in the heap changes, and before any GC safe-point. // The call is not needed if NULL is stored in the field. @@ -411,16 +411,16 @@ class Heap { // consume. For a regular VM this would relate to the -Xmx option and would return -1 if no Xmx // were specified. Android apps start with a growth limit (small heap size) which is // cleared/extended for large apps. - int64_t GetMaxMemory() const { + size_t GetMaxMemory() const { return growth_limit_; } // Implements java.lang.Runtime.totalMemory, returning the amount of memory consumed by an // application. - int64_t GetTotalMemory() const; + size_t GetTotalMemory() const; // Implements java.lang.Runtime.freeMemory. - int64_t GetFreeMemory() const { + size_t GetFreeMemory() const { return GetTotalMemory() - num_bytes_allocated_; } @@ -550,7 +550,8 @@ class Heap { static bool IsCompactingGC(CollectorType collector_type) { return collector_type == kCollectorTypeSS || collector_type == kCollectorTypeGSS; } - bool ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) const; + bool ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ALWAYS_INLINE void CheckConcurrentGC(Thread* self, size_t new_num_bytes_allocated, mirror::Object* obj); @@ -596,8 +597,8 @@ class Heap { } void EnqueueClearedReferences(); // Returns true if the reference object has not yet been enqueued. - bool IsEnqueuable(const mirror::Object* ref) const; - bool IsEnqueued(mirror::Object* ref) const; + bool IsEnqueuable(mirror::Object* ref) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsEnqueued(mirror::Object* ref) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void DelayReferenceReferent(mirror::Class* klass, mirror::Object* obj, RootVisitor mark_visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -644,7 +645,7 @@ class Heap { // No thread saftey analysis since we call this everywhere and it is impossible to find a proper // lock ordering for it. - void VerifyObjectBody(const mirror::Object *obj) NO_THREAD_SAFETY_ANALYSIS; + void VerifyObjectBody(mirror::Object *obj) NO_THREAD_SAFETY_ANALYSIS; static void VerificationCallback(mirror::Object* obj, void* arg) SHARED_LOCKS_REQUIRED(GlobalSychronization::heap_bitmap_lock_); @@ -781,13 +782,13 @@ class Heap { size_t total_objects_freed_ever_; // Number of bytes allocated. Adjusted after each allocation and free. - AtomicInteger num_bytes_allocated_; + Atomic<size_t> num_bytes_allocated_; // Bytes which are allocated and managed by native code but still need to be accounted for. - AtomicInteger native_bytes_allocated_; + Atomic<size_t> native_bytes_allocated_; // Data structure GC overhead. - AtomicInteger gc_memory_overhead_; + Atomic<size_t> gc_memory_overhead_; // Heap verification flags. const bool verify_missing_card_marks_; diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc index d006349cbb..2d73a71421 100644 --- a/runtime/gc/reference_queue.cc +++ b/runtime/gc/reference_queue.cc @@ -52,8 +52,7 @@ void ReferenceQueue::EnqueuePendingReference(mirror::Object* ref) { ref->SetFieldObject(pending_next_offset, ref, false); list_ = ref; } else { - mirror::Object* head = - list_->GetFieldObject<mirror::Object*>(pending_next_offset, false); + mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false); ref->SetFieldObject(pending_next_offset, head, false); list_->SetFieldObject(pending_next_offset, ref, false); } @@ -62,7 +61,7 @@ void ReferenceQueue::EnqueuePendingReference(mirror::Object* ref) { mirror::Object* ReferenceQueue::DequeuePendingReference() { DCHECK(!IsEmpty()); MemberOffset pending_next_offset = heap_->GetReferencePendingNextOffset(); - mirror::Object* head = list_->GetFieldObject<mirror::Object*>(pending_next_offset, false); + mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false); DCHECK(head != nullptr); mirror::Object* ref; // Note: the following code is thread-safe because it is only called from ProcessReferences which @@ -71,7 +70,7 @@ mirror::Object* ReferenceQueue::DequeuePendingReference() { ref = list_; list_ = nullptr; } else { - mirror::Object* next = head->GetFieldObject<mirror::Object*>(pending_next_offset, false); + mirror::Object* next = head->GetFieldObject<mirror::Object>(pending_next_offset, false); list_->SetFieldObject(pending_next_offset, next, false); ref = head; } @@ -84,11 +83,11 @@ void ReferenceQueue::Dump(std::ostream& os) const { os << "Reference starting at list_=" << list_ << "\n"; while (cur != nullptr) { mirror::Object* pending_next = - cur->GetFieldObject<mirror::Object*>(heap_->GetReferencePendingNextOffset(), false); + cur->GetFieldObject<mirror::Object>(heap_->GetReferencePendingNextOffset(), false); os << "PendingNext=" << pending_next; if (cur->GetClass()->IsFinalizerReferenceClass()) { os << " Zombie=" << - cur->GetFieldObject<mirror::Object*>(heap_->GetFinalizerReferenceZombieOffset(), false); + cur->GetFieldObject<mirror::Object>(heap_->GetFinalizerReferenceZombieOffset(), false); } os << "\n"; cur = pending_next; diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h index 89589c39f6..3f3069edc2 100644 --- a/runtime/gc/reference_queue.h +++ b/runtime/gc/reference_queue.h @@ -21,7 +21,7 @@ #include <string> #include <vector> -#include "atomic_integer.h" +#include "atomic.h" #include "base/timing_logger.h" #include "globals.h" #include "gtest/gtest.h" @@ -83,7 +83,7 @@ class ReferenceQueue { private: // Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously // calling AtomicEnqueueIfNotEnqueued. - Mutex lock_; + Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; // The heap contains the reference offsets. Heap* const heap_; // The actual reference list. Not a root since it will be nullptr when the GC is not running. diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc index 4dc17dfc18..a314d74390 100644 --- a/runtime/gc/space/bump_pointer_space.cc +++ b/runtime/gc/space/bump_pointer_space.cc @@ -29,7 +29,7 @@ BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capac capacity = RoundUp(capacity, kPageSize); std::string error_msg; UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE, &error_msg)); + PROT_READ | PROT_WRITE, true, &error_msg)); if (mem_map.get() == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(capacity) << " with message " << error_msg; @@ -69,7 +69,7 @@ mirror::Object* BumpPointerSpace::Alloc(Thread*, size_t num_bytes, size_t* bytes return ret; } -size_t BumpPointerSpace::AllocationSize(const mirror::Object* obj) { +size_t BumpPointerSpace::AllocationSize(mirror::Object* obj) { return AllocationSizeNonvirtual(obj); } diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h index 3e25b6b20b..d73fe3bdd1 100644 --- a/runtime/gc/space/bump_pointer_space.h +++ b/runtime/gc/space/bump_pointer_space.h @@ -49,8 +49,7 @@ class BumpPointerSpace : public ContinuousMemMapAllocSpace { mirror::Object* AllocNonvirtualWithoutAccounting(size_t num_bytes); // Return the storage space required by obj. - virtual size_t AllocationSize(const mirror::Object* obj) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + virtual size_t AllocationSize(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // NOPS unless we support free lists. virtual size_t Free(Thread*, mirror::Object*) { @@ -60,7 +59,7 @@ class BumpPointerSpace : public ContinuousMemMapAllocSpace { return 0; } - size_t AllocationSizeNonvirtual(const mirror::Object* obj) + size_t AllocationSizeNonvirtual(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return obj->SizeOf(); } @@ -135,7 +134,6 @@ class BumpPointerSpace : public ContinuousMemMapAllocSpace { byte* AllocBlock(size_t bytes) EXCLUSIVE_LOCKS_REQUIRED(block_lock_); void RevokeThreadLocalBuffersLocked(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(block_lock_); - size_t InternalAllocationSize(const mirror::Object* obj); mirror::Object* AllocWithoutGrowthLocked(size_t num_bytes, size_t* bytes_allocated) EXCLUSIVE_LOCKS_REQUIRED(lock_); diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index 9ae6a33f72..931ed2179e 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -228,7 +228,7 @@ extern "C" void* art_heap_morecore(void* mspace, intptr_t increment) { return dlmalloc_space->MoreCore(increment); } -size_t DlMallocSpace::AllocationSize(const mirror::Object* obj) { +size_t DlMallocSpace::AllocationSize(mirror::Object* obj) { return AllocationSizeNonvirtual(obj); } diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h index 24308f7857..4507c360c0 100644 --- a/runtime/gc/space/dlmalloc_space.h +++ b/runtime/gc/space/dlmalloc_space.h @@ -48,13 +48,15 @@ class DlMallocSpace : public MallocSpace { virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated) LOCKS_EXCLUDED(lock_); virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated); - virtual size_t AllocationSize(const mirror::Object* obj); - virtual size_t Free(Thread* self, mirror::Object* ptr); - virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs); + virtual size_t AllocationSize(mirror::Object* obj); + virtual size_t Free(Thread* self, mirror::Object* ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::Object* AllocNonvirtual(Thread* self, size_t num_bytes, size_t* bytes_allocated); - size_t AllocationSizeNonvirtual(const mirror::Object* obj) { + size_t AllocationSizeNonvirtual(mirror::Object* obj) { void* obj_ptr = const_cast<void*>(reinterpret_cast<const void*>(obj)); return mspace_usable_size(obj_ptr) + kChunkOverhead; } diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 4777cc6fc7..ebad8dd21b 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -35,7 +35,7 @@ namespace art { namespace gc { namespace space { -AtomicInteger ImageSpace::bitmap_index_(0); +Atomic<uint32_t> ImageSpace::bitmap_index_(0); ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map, accounting::SpaceBitmap* live_bitmap) @@ -171,7 +171,7 @@ void ImageSpace::VerifyImageAllocations() { byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment); while (current < End()) { DCHECK_ALIGNED(current, kObjectAlignment); - const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current); + mirror::Object* obj = reinterpret_cast<mirror::Object*>(current); CHECK(live_bitmap_->Test(obj)); CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class"; current += RoundUp(obj->SizeOf(), kObjectAlignment); @@ -227,7 +227,7 @@ ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str()); return nullptr; } - size_t bitmap_index = bitmap_index_.FetchAndAdd(1); + uint32_t bitmap_index = bitmap_index_.FetchAndAdd(1); std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name, bitmap_index)); UniquePtr<accounting::SpaceBitmap> bitmap( diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index c3f0ae6574..9e19774b23 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -94,7 +94,7 @@ class ImageSpace : public MemMapSpace { friend class Space; - static AtomicInteger bitmap_index_; + static Atomic<uint32_t> bitmap_index_; UniquePtr<accounting::SpaceBitmap> live_bitmap_; diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index 7fcfed4267..987a6558e2 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -60,7 +60,7 @@ mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) { std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", NULL, num_bytes, - PROT_READ | PROT_WRITE, &error_msg); + PROT_READ | PROT_WRITE, true, &error_msg); if (UNLIKELY(mem_map == NULL)) { LOG(WARNING) << "Large object allocation failed: " << error_msg; return NULL; @@ -92,9 +92,9 @@ size_t LargeObjectMapSpace::Free(Thread* self, mirror::Object* ptr) { return allocation_size; } -size_t LargeObjectMapSpace::AllocationSize(const mirror::Object* obj) { +size_t LargeObjectMapSpace::AllocationSize(mirror::Object* obj) { MutexLock mu(Thread::Current(), lock_); - MemMaps::iterator found = mem_maps_.find(const_cast<mirror::Object*>(obj)); + MemMaps::iterator found = mem_maps_.find(obj); CHECK(found != mem_maps_.end()) << "Attempted to get size of a large object which is not live"; return found->second->Size(); } @@ -134,7 +134,7 @@ FreeListSpace* FreeListSpace::Create(const std::string& name, byte* requested_be CHECK_EQ(size % kAlignment, 0U); std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size, - PROT_READ | PROT_WRITE, &error_msg); + PROT_READ | PROT_WRITE, true, &error_msg); CHECK(mem_map != NULL) << "Failed to allocate large object space mem map: " << error_msg; return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End()); } @@ -244,7 +244,7 @@ bool FreeListSpace::Contains(const mirror::Object* obj) const { return mem_map_->HasAddress(obj); } -size_t FreeListSpace::AllocationSize(const mirror::Object* obj) { +size_t FreeListSpace::AllocationSize(mirror::Object* obj) { AllocationHeader* header = GetAllocationHeader(obj); DCHECK(Contains(obj)); DCHECK(!header->IsFree()); diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h index cd7c3833dd..5274c8d320 100644 --- a/runtime/gc/space/large_object_space.h +++ b/runtime/gc/space/large_object_space.h @@ -92,7 +92,7 @@ class LargeObjectMapSpace : public LargeObjectSpace { static LargeObjectMapSpace* Create(const std::string& name); // Return the storage space required by obj. - size_t AllocationSize(const mirror::Object* obj); + size_t AllocationSize(mirror::Object* obj); mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated); size_t Free(Thread* self, mirror::Object* ptr); void Walk(DlMallocSpace::WalkCallback, void* arg) LOCKS_EXCLUDED(lock_); @@ -118,8 +118,7 @@ class FreeListSpace : public LargeObjectSpace { virtual ~FreeListSpace(); static FreeListSpace* Create(const std::string& name, byte* requested_begin, size_t capacity); - size_t AllocationSize(const mirror::Object* obj) - EXCLUSIVE_LOCKS_REQUIRED(lock_); + size_t AllocationSize(mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(lock_); mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated); size_t Free(Thread* self, mirror::Object* obj); bool Contains(const mirror::Object* obj) const; diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index 6c6cb97d7e..f90e6c7695 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -87,7 +87,7 @@ MemMap* MallocSpace::CreateMemMap(const std::string& name, size_t starting_size, std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, *capacity, - PROT_READ | PROT_WRITE, &error_msg); + PROT_READ | PROT_WRITE, true, &error_msg); if (mem_map == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(*capacity) << ": " << error_msg; diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h index 9a42e2cd88..f17bcd26e5 100644 --- a/runtime/gc/space/malloc_space.h +++ b/runtime/gc/space/malloc_space.h @@ -58,9 +58,11 @@ class MallocSpace : public ContinuousMemMapAllocSpace { // Allocate num_bytes allowing the underlying space to grow. virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) = 0; // Return the storage space required by obj. - virtual size_t AllocationSize(const mirror::Object* obj) = 0; - virtual size_t Free(Thread* self, mirror::Object* ptr) = 0; - virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) = 0; + virtual size_t AllocationSize(mirror::Object* obj) = 0; + virtual size_t Free(Thread* self, mirror::Object* ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; + virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; #ifndef NDEBUG virtual void CheckMoreCoreForPrecondition() {} // to be overridden in the debug build. @@ -136,7 +138,9 @@ class MallocSpace : public ContinuousMemMapAllocSpace { virtual void* CreateAllocator(void* base, size_t morecore_start, size_t initial_size, bool low_memory_mode) = 0; - void RegisterRecentFree(mirror::Object* ptr) EXCLUSIVE_LOCKS_REQUIRED(lock_); + void RegisterRecentFree(mirror::Object* ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + EXCLUSIVE_LOCKS_REQUIRED(lock_); virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() { return &SweepCallback; @@ -163,7 +167,8 @@ class MallocSpace : public ContinuousMemMapAllocSpace { size_t growth_limit_; private: - static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg); + static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); DISALLOW_COPY_AND_ASSIGN(MallocSpace); }; @@ -204,13 +209,14 @@ class ValgrindMallocSpace : public BaseMallocSpaceType { return result; } - virtual size_t AllocationSize(const mirror::Object* obj) { - size_t result = BaseMallocSpaceType::AllocationSize(reinterpret_cast<const mirror::Object*>( - reinterpret_cast<const byte*>(obj) - kValgrindRedZoneBytes)); + virtual size_t AllocationSize(mirror::Object* obj) { + size_t result = BaseMallocSpaceType::AllocationSize(reinterpret_cast<mirror::Object*>( + reinterpret_cast<byte*>(obj) - kValgrindRedZoneBytes)); return result - 2 * kValgrindRedZoneBytes; } - virtual size_t Free(Thread* self, mirror::Object* ptr) { + virtual size_t Free(Thread* self, mirror::Object* ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { void* obj_after_rdz = reinterpret_cast<void*>(ptr); void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes; // Make redzones undefined. @@ -221,7 +227,8 @@ class ValgrindMallocSpace : public BaseMallocSpaceType { return freed - 2 * kValgrindRedZoneBytes; } - virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) { + virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { size_t freed = 0; for (size_t i = 0; i < num_ptrs; i++) { freed += Free(self, ptrs[i]); diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index 177e38e6aa..86e441ebb9 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -220,7 +220,7 @@ extern "C" void* art_heap_rosalloc_morecore(allocator::RosAlloc* rosalloc, intpt return rosalloc_space->MoreCore(increment); } -size_t RosAllocSpace::AllocationSize(const mirror::Object* obj) { +size_t RosAllocSpace::AllocationSize(mirror::Object* obj) { return AllocationSizeNonvirtual(obj); } diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h index 555eb3cf09..4cd5a6d0a7 100644 --- a/runtime/gc/space/rosalloc_space.h +++ b/runtime/gc/space/rosalloc_space.h @@ -47,13 +47,15 @@ class RosAllocSpace : public MallocSpace { virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated) LOCKS_EXCLUDED(lock_); virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated); - virtual size_t AllocationSize(const mirror::Object* obj); - virtual size_t Free(Thread* self, mirror::Object* ptr); - virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs); + virtual size_t AllocationSize(mirror::Object* obj); + virtual size_t Free(Thread* self, mirror::Object* ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::Object* AllocNonvirtual(Thread* self, size_t num_bytes, size_t* bytes_allocated); - size_t AllocationSizeNonvirtual(const mirror::Object* obj) + size_t AllocationSizeNonvirtual(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS { // TODO: NO_THREAD_SAFETY_ANALYSIS because SizeOf() requires that mutator_lock is held. void* obj_ptr = const_cast<void*>(reinterpret_cast<const void*>(obj)); diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h index 95a79ec48d..98e6f65017 100644 --- a/runtime/gc/space/space.h +++ b/runtime/gc/space/space.h @@ -223,7 +223,7 @@ class AllocSpace { virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) = 0; // Return the storage space required by obj. - virtual size_t AllocationSize(const mirror::Object* obj) = 0; + virtual size_t AllocationSize(mirror::Object* obj) = 0; // Returns how many bytes were freed. virtual size_t Free(Thread* self, mirror::Object* ptr) = 0; diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc index 427d5471d8..9989ffefaf 100644 --- a/runtime/gc/space/space_test.cc +++ b/runtime/gc/space/space_test.cc @@ -163,6 +163,7 @@ void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) { EXPECT_TRUE(ptr5 == NULL); // Release some memory. + ScopedObjectAccess soa(self); size_t free3 = space->AllocationSize(ptr3); EXPECT_EQ(free3, ptr3_bytes_allocated); EXPECT_EQ(free3, space->Free(self, ptr3)); @@ -257,6 +258,7 @@ void SpaceTest::AllocAndFreeTestBody(CreateSpaceFn create_space) { EXPECT_TRUE(ptr5 == NULL); // Release some memory. + ScopedObjectAccess soa(self); size_t free3 = space->AllocationSize(ptr3); EXPECT_EQ(free3, ptr3_bytes_allocated); space->Free(self, ptr3); @@ -354,30 +356,36 @@ void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) { for (size_t i = 0; i < arraysize(lots_of_objects); i++) { size_t allocation_size = 0; lots_of_objects[i] = space->Alloc(self, 16, &allocation_size); - EXPECT_TRUE(lots_of_objects[i] != NULL); + EXPECT_TRUE(lots_of_objects[i] != nullptr); InstallClass(lots_of_objects[i], 16); EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i])); } - // Release memory and check pointers are NULL - space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); - for (size_t i = 0; i < arraysize(lots_of_objects); i++) { - EXPECT_TRUE(lots_of_objects[i] == NULL); + // Release memory and check pointers are NULL. + { + ScopedObjectAccess soa(self); + space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); + for (size_t i = 0; i < arraysize(lots_of_objects); i++) { + EXPECT_TRUE(lots_of_objects[i] == nullptr); + } } // Succeeds, fits by adjusting the max allowed footprint. for (size_t i = 0; i < arraysize(lots_of_objects); i++) { size_t allocation_size = 0; lots_of_objects[i] = space->AllocWithGrowth(self, 1024, &allocation_size); - EXPECT_TRUE(lots_of_objects[i] != NULL); + EXPECT_TRUE(lots_of_objects[i] != nullptr); InstallClass(lots_of_objects[i], 1024); EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i])); } // Release memory and check pointers are NULL - space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); - for (size_t i = 0; i < arraysize(lots_of_objects); i++) { - EXPECT_TRUE(lots_of_objects[i] == NULL); + { + ScopedObjectAccess soa(self); + space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); + for (size_t i = 0; i < arraysize(lots_of_objects); i++) { + EXPECT_TRUE(lots_of_objects[i] == nullptr); + } } } @@ -491,28 +499,30 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t break; } - // Free some objects - for (size_t i = 0; i < last_object; i += free_increment) { - mirror::Object* object = lots_of_objects.get()[i]; - if (object == NULL) { - continue; - } - size_t allocation_size = space->AllocationSize(object); - if (object_size > 0) { - EXPECT_GE(allocation_size, static_cast<size_t>(object_size)); - } else { - EXPECT_GE(allocation_size, 8u); + { + // Free some objects + ScopedObjectAccess soa(self); + for (size_t i = 0; i < last_object; i += free_increment) { + mirror::Object* object = lots_of_objects.get()[i]; + if (object == NULL) { + continue; + } + size_t allocation_size = space->AllocationSize(object); + if (object_size > 0) { + EXPECT_GE(allocation_size, static_cast<size_t>(object_size)); + } else { + EXPECT_GE(allocation_size, 8u); + } + space->Free(self, object); + lots_of_objects.get()[i] = NULL; + amount_allocated -= allocation_size; + footprint = space->GetFootprint(); + EXPECT_GE(space->Size(), footprint); // invariant } - space->Free(self, object); - lots_of_objects.get()[i] = NULL; - amount_allocated -= allocation_size; - footprint = space->GetFootprint(); - EXPECT_GE(space->Size(), footprint); // invariant - } - free_increment >>= 1; + free_increment >>= 1; + } } - // The space has become empty here before allocating a large object // below. For RosAlloc, revoke thread-local runs, which are kept // even when empty for a performance reason, so that they won't @@ -540,8 +550,10 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t EXPECT_LE(space->Size(), growth_limit); // Clean up - space->Free(self, large_object); - + { + ScopedObjectAccess soa(self); + space->Free(self, large_object); + } // Sanity check footprint footprint = space->GetFootprint(); EXPECT_LE(footprint, growth_limit); diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h index 10a5492b30..e0035b31a5 100644 --- a/runtime/gc/space/zygote_space.h +++ b/runtime/gc/space/zygote_space.h @@ -54,7 +54,7 @@ class ZygoteSpace : public ContinuousMemMapAllocSpace { LOG(FATAL) << "Unimplemented"; return nullptr; } - virtual size_t AllocationSize(const mirror::Object* obj) { + virtual size_t AllocationSize(mirror::Object* obj) { LOG(FATAL) << "Unimplemented"; return 0; } diff --git a/runtime/globals.h b/runtime/globals.h index b1ccbdcea2..8c3ae56ea5 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -36,7 +36,7 @@ static constexpr size_t kPointerSize = sizeof(void*); static constexpr size_t kBitsPerByte = 8; static constexpr size_t kBitsPerByteLog2 = 3; static constexpr int kBitsPerWord = kWordSize * kBitsPerByte; -static constexpr size_t kWordHighBitMask = 1 << (kBitsPerWord - 1); +static constexpr size_t kWordHighBitMask = static_cast<size_t>(1) << (kBitsPerWord - 1); // Required stack alignment static constexpr size_t kStackAlignment = 16; diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 9f899e87a3..24d403d634 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -167,14 +167,8 @@ enum HprofBasicType { hprof_basic_long = 11, }; -typedef uint32_t HprofId; -typedef HprofId HprofStringId; -typedef HprofId HprofObjectId; -typedef HprofId HprofClassObjectId; -typedef std::set<mirror::Class*> ClassSet; -typedef std::set<mirror::Class*>::iterator ClassSetIterator; -typedef SafeMap<std::string, size_t> StringMap; -typedef SafeMap<std::string, size_t>::iterator StringMapIterator; +typedef uint32_t HprofStringId; +typedef uint32_t HprofClassObjectId; // Represents a top-level hprof record, whose serialized format is: // U1 TAG: denoting the type of the record @@ -183,11 +177,8 @@ typedef SafeMap<std::string, size_t>::iterator StringMapIterator; // U1* BODY: as many bytes as specified in the above uint32_t field class HprofRecord { public: - HprofRecord() { - dirty_ = false; - alloc_length_ = 128; + HprofRecord() : alloc_length_(128), fp_(nullptr), tag_(0), time_(0), length_(0), dirty_(false) { body_ = reinterpret_cast<unsigned char*>(malloc(alloc_length_)); - fp_ = NULL; } ~HprofRecord() { @@ -233,7 +224,7 @@ class HprofRecord { int AddU1(uint8_t value) { int err = GuaranteeRecordAppend(1); - if (err != 0) { + if (UNLIKELY(err != 0)) { return err; } @@ -253,13 +244,30 @@ class HprofRecord { return AddU8List(&value, 1); } - int AddId(HprofObjectId value) { - return AddU4((uint32_t) value); + int AddObjectId(const mirror::Object* value) { + return AddU4(PointerToLowMemUInt32(value)); + } + + // The ID for the synthetic object generated to account for class static overhead. + int AddClassStaticsId(const mirror::Class* value) { + return AddU4(1 | PointerToLowMemUInt32(value)); + } + + int AddJniGlobalRefId(jobject value) { + return AddU4(PointerToLowMemUInt32(value)); + } + + int AddClassId(HprofClassObjectId value) { + return AddU4(value); + } + + int AddStringId(HprofStringId value) { + return AddU4(value); } int AddU1List(const uint8_t* values, size_t numValues) { int err = GuaranteeRecordAppend(numValues); - if (err != 0) { + if (UNLIKELY(err != 0)) { return err; } @@ -270,7 +278,7 @@ class HprofRecord { int AddU2List(const uint16_t* values, size_t numValues) { int err = GuaranteeRecordAppend(numValues * 2); - if (err != 0) { + if (UNLIKELY(err != 0)) { return err; } @@ -285,7 +293,7 @@ class HprofRecord { int AddU4List(const uint32_t* values, size_t numValues) { int err = GuaranteeRecordAppend(numValues * 4); - if (err != 0) { + if (UNLIKELY(err != 0)) { return err; } @@ -317,8 +325,16 @@ class HprofRecord { return 0; } - int AddIdList(const HprofObjectId* values, size_t numValues) { - return AddU4List((const uint32_t*) values, numValues); + int AddIdList(mirror::ObjectArray<mirror::Object>* values) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int32_t length = values->GetLength(); + for (int32_t i = 0; i < length; ++i) { + int err = AddObjectId(values->GetWithoutChecks(i)); + if (UNLIKELY(err != 0)) { + return err; + } + } + return 0; } int AddUtf8String(const char* str) { @@ -510,12 +526,11 @@ class Hprof { HprofRecord* rec = ¤t_record_; uint32_t nextSerialNumber = 1; - for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) { - const mirror::Class* c = *it; - CHECK(c != NULL); + for (mirror::Class* c : classes_) { + CHECK(c != nullptr); int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_LOAD_CLASS, HPROF_TIME); - if (err != 0) { + if (UNLIKELY(err != 0)) { return err; } @@ -525,9 +540,9 @@ class Hprof { // U4: stack trace serial number // ID: class name string ID rec->AddU4(nextSerialNumber++); - rec->AddId((HprofClassObjectId) c); + rec->AddObjectId(c); rec->AddU4(HPROF_NULL_STACK_TRACE); - rec->AddId(LookupClassNameId(c)); + rec->AddStringId(LookupClassNameId(c)); } return 0; @@ -536,9 +551,9 @@ class Hprof { int WriteStringTable() { HprofRecord* rec = ¤t_record_; - for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) { - const std::string& string = (*it).first; - size_t id = (*it).second; + for (std::pair<std::string, HprofStringId> p : strings_) { + const std::string& string = p.first; + size_t id = p.second; int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_STRING, HPROF_TIME); if (err != 0) { @@ -573,24 +588,26 @@ class Hprof { int MarkRootObject(const mirror::Object* obj, jobject jniObj); - HprofClassObjectId LookupClassId(mirror::Class* c) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (c == NULL) { - // c is the superclass of java.lang.Object or a primitive - return (HprofClassObjectId)0; + HprofClassObjectId LookupClassId(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (c == nullptr) { + // c is the superclass of java.lang.Object or a primitive. + return 0; } - std::pair<ClassSetIterator, bool> result = classes_.insert(c); - const mirror::Class* present = *result.first; + { + auto result = classes_.insert(c); + const mirror::Class* present = *result.first; + CHECK_EQ(present, c); + } // Make sure that we've assigned a string ID for this class' name LookupClassNameId(c); - CHECK_EQ(present, c); - return (HprofStringId) present; + HprofClassObjectId result = PointerToLowMemUInt32(c); + return result; } - HprofStringId LookupStringId(mirror::String* string) { + HprofStringId LookupStringId(mirror::String* string) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return LookupStringId(string->ToModifiedUtf8()); } @@ -599,7 +616,7 @@ class Hprof { } HprofStringId LookupStringId(const std::string& string) { - StringMapIterator it = strings_.find(string); + auto it = strings_.find(string); if (it != strings_.end()) { return it->second; } @@ -608,8 +625,7 @@ class Hprof { return id; } - HprofStringId LookupClassNameId(const mirror::Class* c) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + HprofStringId LookupClassNameId(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return LookupStringId(PrettyDescriptor(c)); } @@ -675,9 +691,9 @@ class Hprof { char* body_data_ptr_; size_t body_data_size_; - ClassSet classes_; - size_t next_string_id_; - StringMap strings_; + std::set<mirror::Class*> classes_; + HprofStringId next_string_id_; + SafeMap<std::string, HprofStringId> strings_; DISALLOW_COPY_AND_ASSIGN(Hprof); }; @@ -685,11 +701,8 @@ class Hprof { #define OBJECTS_PER_SEGMENT ((size_t)128) #define BYTES_PER_SEGMENT ((size_t)4096) -// The static field-name for the synthetic object generated to account -// for class static overhead. +// The static field-name for the synthetic object generated to account for class static overhead. #define STATIC_OVERHEAD_NAME "$staticOverhead" -// The ID for the synthetic object generated to account for class static overhead. -#define CLASS_STATICS_ID(c) ((HprofObjectId)(((uint32_t)(c)) | 1)) static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut) { char c = sig[0]; @@ -765,15 +778,15 @@ int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) { case HPROF_ROOT_DEBUGGER: case HPROF_ROOT_VM_INTERNAL: rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); break; // ID: object ID // ID: JNI global ref ID case HPROF_ROOT_JNI_GLOBAL: rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - rec->AddId((HprofId)jniObj); + rec->AddObjectId(obj); + rec->AddJniGlobalRefId(jniObj); break; // ID: object ID @@ -783,7 +796,7 @@ int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) { case HPROF_ROOT_JNI_MONITOR: case HPROF_ROOT_JAVA_FRAME: rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(gc_thread_serial_number_); rec->AddU4((uint32_t)-1); break; @@ -793,7 +806,7 @@ int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) { case HPROF_ROOT_NATIVE_STACK: case HPROF_ROOT_THREAD_BLOCK: rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(gc_thread_serial_number_); break; @@ -802,7 +815,7 @@ int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) { // U4: stack trace serial number case HPROF_ROOT_THREAD_OBJECT: rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(gc_thread_serial_number_); rec->AddU4((uint32_t)-1); // xxx break; @@ -859,7 +872,7 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { nameId = LookupStringId("<ILLEGAL>"); break; } - rec->AddId(nameId); + rec->AddStringId(nameId); current_heap_ = desiredHeap; } @@ -875,11 +888,11 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { // obj is a ClassObject. size_t sFieldCount = thisClass->NumStaticFields(); if (sFieldCount != 0) { - int byteLength = sFieldCount*sizeof(JValue); // TODO bogus; fields are packed + int byteLength = sFieldCount * sizeof(JValue); // TODO bogus; fields are packed // Create a byte array to reflect the allocation of the // StaticField array at the end of this class. rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP); - rec->AddId(CLASS_STATICS_ID(obj)); + rec->AddClassStaticsId(thisClass); rec->AddU4(StackTraceSerialNumber(obj)); rec->AddU4(byteLength); rec->AddU1(hprof_basic_byte); @@ -889,14 +902,14 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { } rec->AddU1(HPROF_CLASS_DUMP); - rec->AddId(LookupClassId(thisClass)); + rec->AddClassId(LookupClassId(thisClass)); rec->AddU4(StackTraceSerialNumber(thisClass)); - rec->AddId(LookupClassId(thisClass->GetSuperClass())); - rec->AddId((HprofObjectId)thisClass->GetClassLoader()); - rec->AddId((HprofObjectId)0); // no signer - rec->AddId((HprofObjectId)0); // no prot domain - rec->AddId((HprofId)0); // reserved - rec->AddId((HprofId)0); // reserved + rec->AddClassId(LookupClassId(thisClass->GetSuperClass())); + rec->AddObjectId(thisClass->GetClassLoader()); + rec->AddObjectId(nullptr); // no signer + rec->AddObjectId(nullptr); // no prot domain + rec->AddObjectId(nullptr); // reserved + rec->AddObjectId(nullptr); // reserved if (thisClass->IsClassClass()) { // ClassObjects have their static fields appended, so aren't all the same size. // But they're at least this size. @@ -916,9 +929,9 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { rec->AddU2((uint16_t)0); } else { rec->AddU2((uint16_t)(sFieldCount+1)); - rec->AddId(LookupStringId(STATIC_OVERHEAD_NAME)); + rec->AddStringId(LookupStringId(STATIC_OVERHEAD_NAME)); rec->AddU1(hprof_basic_object); - rec->AddId(CLASS_STATICS_ID(obj)); + rec->AddClassStaticsId(thisClass); for (size_t i = 0; i < sFieldCount; ++i) { mirror::ArtField* f = thisClass->GetStaticField(i); @@ -926,7 +939,7 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { size_t size; HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), &size); - rec->AddId(LookupStringId(fh.GetName())); + rec->AddStringId(LookupStringId(fh.GetName())); rec->AddU1(t); if (size == 1) { rec->AddU1(static_cast<uint8_t>(f->Get32(thisClass))); @@ -949,24 +962,24 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { mirror::ArtField* f = thisClass->GetInstanceField(i); fh.ChangeField(f); HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), NULL); - rec->AddId(LookupStringId(fh.GetName())); + rec->AddStringId(LookupStringId(fh.GetName())); rec->AddU1(t); } } else if (c->IsArrayClass()) { - const mirror::Array* aobj = obj->AsArray(); + mirror::Array* aobj = obj->AsArray(); uint32_t length = aobj->GetLength(); if (obj->IsObjectArray()) { // obj is an object array. rec->AddU1(HPROF_OBJECT_ARRAY_DUMP); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(StackTraceSerialNumber(obj)); rec->AddU4(length); - rec->AddId(LookupClassId(c)); + rec->AddClassId(LookupClassId(c)); // Dump the elements, which are always objects or NULL. - rec->AddIdList((const HprofObjectId*)aobj->GetRawData(sizeof(mirror::Object*)), length); + rec->AddIdList(aobj->AsObjectArray<mirror::Object>()); } else { size_t size; HprofBasicType t = PrimitiveToBasicTypeAndSize(c->GetComponentType()->GetPrimitiveType(), &size); @@ -974,28 +987,28 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { // obj is a primitive array. rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(StackTraceSerialNumber(obj)); rec->AddU4(length); rec->AddU1(t); // Dump the raw, packed element values. if (size == 1) { - rec->AddU1List((const uint8_t*)aobj->GetRawData(sizeof(uint8_t)), length); + rec->AddU1List((const uint8_t*)aobj->GetRawData(sizeof(uint8_t), 0), length); } else if (size == 2) { - rec->AddU2List((const uint16_t*)aobj->GetRawData(sizeof(uint16_t)), length); + rec->AddU2List((const uint16_t*)aobj->GetRawData(sizeof(uint16_t), 0), length); } else if (size == 4) { - rec->AddU4List((const uint32_t*)aobj->GetRawData(sizeof(uint32_t)), length); + rec->AddU4List((const uint32_t*)aobj->GetRawData(sizeof(uint32_t), 0), length); } else if (size == 8) { - rec->AddU8List((const uint64_t*)aobj->GetRawData(sizeof(uint64_t)), length); + rec->AddU8List((const uint64_t*)aobj->GetRawData(sizeof(uint64_t), 0), length); } } } else { // obj is an instance object. rec->AddU1(HPROF_INSTANCE_DUMP); - rec->AddId((HprofObjectId)obj); + rec->AddObjectId(obj); rec->AddU4(StackTraceSerialNumber(obj)); - rec->AddId(LookupClassId(c)); + rec->AddClassId(LookupClassId(c)); // Reserve some space for the length of the instance data, which we won't // know until we're done writing it. @@ -1004,7 +1017,7 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { // Write the instance data; fields for this class, followed by super class fields, // and so on. Don't write the klass or monitor fields of Object.class. - const mirror::Class* sclass = c; + mirror::Class* sclass = c; FieldHelper fh; while (!sclass->IsObjectClass()) { int ifieldCount = sclass->NumInstanceFields(); @@ -1019,10 +1032,9 @@ int Hprof::DumpHeapObject(mirror::Object* obj) { rec->AddU2(f->Get32(obj)); } else if (size == 4) { rec->AddU4(f->Get32(obj)); - } else if (size == 8) { - rec->AddU8(f->Get64(obj)); } else { - CHECK(false); + CHECK_EQ(size, 8U); + rec->AddU8(f->Get64(obj)); } } diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h index aee7447faf..ac83601fc0 100644 --- a/runtime/instruction_set.h +++ b/runtime/instruction_set.h @@ -29,6 +29,7 @@ enum InstructionSet { kArm, kThumb2, kX86, + kX86_64, kMips }; diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 0b1154338f..59ffdc1b5f 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -18,7 +18,7 @@ #include <sys/uio.h> -#include "atomic_integer.h" +#include "atomic.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "debugger.h" @@ -68,10 +68,21 @@ bool Instrumentation::InstallStubsForClass(mirror::Class* klass) { return true; } -static void UpdateEntrypoints(mirror::ArtMethod* method, const void* code) { - method->SetEntryPointFromCompiledCode(code); +static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code, + const void* portable_code, bool have_portable_code) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + method->SetEntryPointFromPortableCompiledCode(portable_code); + method->SetEntryPointFromQuickCompiledCode(quick_code); + bool portable_enabled = method->IsPortableCompiled(); + if (have_portable_code && !portable_enabled) { + method->SetIsPortableCompiled(); + } else if (portable_enabled) { + method->ClearIsPortableCompiled(); + } if (!method->IsResolutionMethod()) { - if (code == GetCompiledCodeToInterpreterBridge()) { + if (quick_code == GetQuickToInterpreterBridge()) { + DCHECK(portable_code == GetPortableToInterpreterBridge()); + DCHECK(!method->IsNative()) << PrettyMethod(method); method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge); } else { method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge); @@ -84,37 +95,47 @@ void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) { // Do not change stubs for these methods. return; } - const void* new_code; + const void* new_portable_code; + const void* new_quick_code; bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); bool is_class_initialized = method->GetDeclaringClass()->IsInitialized(); + bool have_portable_code = false; if (uninstall) { if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) { - new_code = GetCompiledCodeToInterpreterBridge(); + new_portable_code = GetPortableToInterpreterBridge(); + new_quick_code = GetQuickToInterpreterBridge(); } else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) { - new_code = class_linker->GetOatCodeFor(method); + new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code); + new_quick_code = class_linker->GetQuickOatCodeFor(method); } else { - new_code = GetResolutionTrampoline(class_linker); + new_portable_code = GetPortableResolutionTrampoline(class_linker); + new_quick_code = GetQuickResolutionTrampoline(class_linker); } } else { // !uninstall if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) { - new_code = GetCompiledCodeToInterpreterBridge(); + new_portable_code = GetPortableToInterpreterBridge(); + new_quick_code = GetQuickToInterpreterBridge(); } else { // Do not overwrite resolution trampoline. When the trampoline initializes the method's // class, all its static methods code will be set to the instrumentation entry point. // For more details, see ClassLinker::FixupStaticTrampolines. if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) { // Do not overwrite interpreter to prevent from posting method entry/exit events twice. - new_code = class_linker->GetOatCodeFor(method); - if (entry_exit_stubs_installed_ && new_code != GetCompiledCodeToInterpreterBridge()) { - new_code = GetQuickInstrumentationEntryPoint(); + new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code); + new_quick_code = class_linker->GetQuickOatCodeFor(method); + if (entry_exit_stubs_installed_ && new_quick_code != GetQuickToInterpreterBridge()) { + DCHECK(new_portable_code != GetPortableToInterpreterBridge()); + new_portable_code = GetPortableToInterpreterBridge(); + new_quick_code = GetQuickInstrumentationEntryPoint(); } } else { - new_code = GetResolutionTrampoline(class_linker); + new_portable_code = GetPortableResolutionTrampoline(class_linker); + new_quick_code = GetQuickResolutionTrampoline(class_linker); } } } - UpdateEntrypoints(method, new_code); + UpdateEntrypoints(method, new_quick_code, new_portable_code, have_portable_code); } // Places the instrumentation exit pc as the return PC for every quick frame. This also allows @@ -470,23 +491,38 @@ void Instrumentation::ResetQuickAllocEntryPoints() { } } -void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const { - const void* new_code; +void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code, + const void* portable_code, bool have_portable_code) const { + const void* new_portable_code; + const void* new_quick_code; + bool new_have_portable_code; if (LIKELY(!instrumentation_stubs_installed_)) { - new_code = code; + new_portable_code = portable_code; + new_quick_code = quick_code; + new_have_portable_code = have_portable_code; } else { if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) { - new_code = GetCompiledCodeToInterpreterBridge(); - } else if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker()) || - code == GetCompiledCodeToInterpreterBridge()) { - new_code = code; + new_portable_code = GetPortableToInterpreterBridge(); + new_quick_code = GetQuickToInterpreterBridge(); + new_have_portable_code = false; + } else if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) || + quick_code == GetQuickToInterpreterBridge()) { + DCHECK((portable_code == GetPortableResolutionTrampoline(Runtime::Current()->GetClassLinker())) || + (portable_code == GetPortableToInterpreterBridge())); + new_portable_code = portable_code; + new_quick_code = quick_code; + new_have_portable_code = have_portable_code; } else if (entry_exit_stubs_installed_) { - new_code = GetQuickInstrumentationEntryPoint(); + new_quick_code = GetQuickInstrumentationEntryPoint(); + new_portable_code = GetPortableToInterpreterBridge(); + new_have_portable_code = false; } else { - new_code = code; + new_portable_code = portable_code; + new_quick_code = quick_code; + new_have_portable_code = have_portable_code; } } - UpdateEntrypoints(method, new_code); + UpdateEntrypoints(method, new_quick_code, new_portable_code, new_have_portable_code); } void Instrumentation::Deoptimize(mirror::ArtMethod* method) { @@ -499,7 +535,8 @@ void Instrumentation::Deoptimize(mirror::ArtMethod* method) { CHECK(!already_deoptimized) << "Method " << PrettyMethod(method) << " is already deoptimized"; if (!interpreter_stubs_installed_) { - UpdateEntrypoints(method, GetCompiledCodeToInterpreterBridge()); + UpdateEntrypoints(method, GetQuickToInterpreterBridge(), GetPortableToInterpreterBridge(), + false); // Install instrumentation exit stub and instrumentation frames. We may already have installed // these previously so it will only cover the newly created frames. @@ -522,10 +559,15 @@ void Instrumentation::Undeoptimize(mirror::ArtMethod* method) { if (!interpreter_stubs_installed_) { // Restore its code or resolution trampoline. ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (method->IsStatic() && !method->IsConstructor() && !method->GetDeclaringClass()->IsInitialized()) { - UpdateEntrypoints(method, GetResolutionTrampoline(class_linker)); + if (method->IsStatic() && !method->IsConstructor() && + !method->GetDeclaringClass()->IsInitialized()) { + UpdateEntrypoints(method, GetQuickResolutionTrampoline(class_linker), + GetPortableResolutionTrampoline(class_linker), false); } else { - UpdateEntrypoints(method, class_linker->GetOatCodeFor(method)); + bool have_portable_code = false; + const void* quick_code = class_linker->GetQuickOatCodeFor(method); + const void* portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code); + UpdateEntrypoints(method, quick_code, portable_code, have_portable_code); } // If there is no deoptimized method left, we can restore the stack of each thread. @@ -582,21 +624,21 @@ void Instrumentation::DisableMethodTracing() { ConfigureStubs(false, false); } -const void* Instrumentation::GetQuickCodeFor(const mirror::ArtMethod* method) const { +const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method) const { Runtime* runtime = Runtime::Current(); if (LIKELY(!instrumentation_stubs_installed_)) { - const void* code = method->GetEntryPointFromCompiledCode(); + const void* code = method->GetEntryPointFromQuickCompiledCode(); DCHECK(code != NULL); if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) && code != GetQuickToInterpreterBridge())) { return code; } } - return runtime->GetClassLinker()->GetOatCodeFor(method); + return runtime->GetClassLinker()->GetQuickOatCodeFor(method); } void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc) const { auto it = method_entry_listeners_.begin(); bool is_end = (it == method_entry_listeners_.end()); @@ -610,7 +652,7 @@ void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_ } void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) const { auto it = method_exit_listeners_.begin(); bool is_end = (it == method_exit_listeners_.end()); @@ -624,7 +666,7 @@ void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_o } void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc) const { if (have_method_unwind_listeners_) { for (InstrumentationListener* listener : method_unwind_listeners_) { @@ -634,7 +676,7 @@ void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_obj } void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc) const { // TODO: STL copy-on-write collection? The copy below is due to the debug listener having an // action where it can remove itself as a listener and break the iterator. The copy only works diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 41b545d032..f01add1bda 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_INSTRUMENTATION_H_ #define ART_RUNTIME_INSTRUMENTATION_H_ -#include "atomic_integer.h" +#include "atomic.h" #include "base/macros.h" #include "locks.h" @@ -55,26 +55,26 @@ struct InstrumentationListener { // Call-back for when a method is entered. virtual void MethodEntered(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; // Call-back for when a method is exited. // TODO: its likely passing the return value would be useful, however, we may need to get and // parse the shorty to determine what kind of register holds the result. virtual void MethodExited(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; // Call-back for when a method is popped due to an exception throw. A method will either cause a // MethodExited call-back or a MethodUnwind call-back when its activation is removed. virtual void MethodUnwind(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; // Call-back for when the dex pc moves in a method. virtual void DexPcMoved(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t new_dex_pc) + mirror::ArtMethod* method, uint32_t new_dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; // Call-back when an exception is caught. @@ -171,13 +171,14 @@ class Instrumentation { void ResetQuickAllocEntryPoints(); // Update the code of a method respecting any installed stubs. - void UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const + void UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code, + const void* portable_code, bool have_portable_code) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the quick code for the given method. More efficient than asking the class linker as it // will short-cut to GetCode if instrumentation and static method resolution stubs aren't // installed. - const void* GetQuickCodeFor(const mirror::ArtMethod* method) const + const void* GetQuickCodeFor(mirror::ArtMethod* method) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ForceInterpretOnly() { @@ -218,7 +219,7 @@ class Instrumentation { // Inform listeners that a method has been entered. A dex PC is provided as we may install // listeners into executing code and get method enter events for methods already on the stack. void MethodEnterEvent(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) const + mirror::ArtMethod* method, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(HasMethodEntryListeners())) { MethodEnterEventImpl(thread, this_object, method, dex_pc); @@ -227,7 +228,7 @@ class Instrumentation { // Inform listeners that a method has been exited. void MethodExitEvent(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(HasMethodExitListeners())) { @@ -237,12 +238,12 @@ class Instrumentation { // Inform listeners that a method has been exited due to an exception. void MethodUnwindEvent(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) const + mirror::ArtMethod* method, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Inform listeners that the dex pc has moved (only supported by the interpreter). void DexPcMovedEvent(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) const + mirror::ArtMethod* method, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(HasDexPcListeners())) { DexPcMovedEventImpl(thread, this_object, method, dex_pc); @@ -289,14 +290,14 @@ class Instrumentation { } void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) const + mirror::ArtMethod* method, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void MethodExitEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) const + mirror::ArtMethod* method, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code? diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index f574a0f2cf..02a9aa6a1b 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -356,7 +356,7 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive DCHECK_LT(shorty_pos + 1, mh.GetShortyLength()); switch (shorty[shorty_pos + 1]) { case 'L': { - Object* o = reinterpret_cast<Object*>(args[arg_pos]); + Object* o = reinterpret_cast<StackReference<Object>*>(&args[arg_pos])->AsMirrorPtr(); shadow_frame->SetVRegReference(cur_reg, o); break; } diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 0f94ccdfe2..0b959fb560 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -25,15 +25,16 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame. -static inline void AssignRegister(ShadowFrame& new_shadow_frame, const ShadowFrame& shadow_frame, - size_t dest_reg, size_t src_reg) { +static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame, + size_t dest_reg, size_t src_reg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // If both register locations contains the same value, the register probably holds a reference. int32_t src_value = shadow_frame.GetVReg(src_reg); mirror::Object* o = shadow_frame.GetVRegReference<false>(src_reg); - if (src_value == reinterpret_cast<int32_t>(o)) { - new_shadow_frame.SetVRegReference(dest_reg, o); + if (src_value == reinterpret_cast<intptr_t>(o)) { + new_shadow_frame->SetVRegReference(dest_reg, o); } else { - new_shadow_frame.SetVReg(dest_reg, src_value); + new_shadow_frame->SetVReg(dest_reg, src_value); } } @@ -84,7 +85,7 @@ bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame, ++dest_reg; ++arg_offset; } - for (size_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) { + for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) { DCHECK_LT(shorty_pos + 1, mh.GetShortyLength()); const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset]; switch (shorty[shorty_pos + 1]) { @@ -131,18 +132,18 @@ bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame, const uint16_t first_src_reg = inst->VRegC_3rc(); for (size_t src_reg = first_src_reg, dest_reg = first_dest_reg; dest_reg < num_regs; ++dest_reg, ++src_reg) { - AssignRegister(*new_shadow_frame, shadow_frame, dest_reg, src_reg); + AssignRegister(new_shadow_frame, shadow_frame, dest_reg, src_reg); } } else { DCHECK_LE(num_ins, 5U); uint16_t regList = inst->Fetch16(2); uint16_t count = num_ins; if (count == 5) { - AssignRegister(*new_shadow_frame, shadow_frame, first_dest_reg + 4U, (inst_data >> 8) & 0x0f); + AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U, (inst_data >> 8) & 0x0f); --count; } for (size_t arg_index = 0; arg_index < count; ++arg_index, regList >>= 4) { - AssignRegister(*new_shadow_frame, shadow_frame, first_dest_reg + arg_index, regList & 0x0f); + AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + arg_index, regList & 0x0f); } } } @@ -289,7 +290,7 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, CHECK(field.get() != NULL); ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V"); uint32_t args[1]; - args[0] = reinterpret_cast<uint32_t>(found); + args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue(); EnterInterpreterFromInvoke(self, c, field.get(), args, NULL); result->SetL(field.get()); } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" || diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 4481210e04..768ca336db 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -218,7 +218,7 @@ static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* ins shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile))); break; case Primitive::kPrimNot: - shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile)); + shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object>(field_offset, is_volatile)); break; default: LOG(FATAL) << "Unreachable: " << field_type; @@ -529,10 +529,10 @@ static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruc oss << PrettyMethod(shadow_frame.GetMethod()) << StringPrintf("\n0x%x: ", dex_pc) << inst->DumpString(&mh.GetDexFile()) << "\n"; - for (size_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) { + for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) { uint32_t raw_value = shadow_frame.GetVReg(i); Object* ref_value = shadow_frame.GetVRegReference(i); - oss << StringPrintf(" vreg%d=0x%08X", i, raw_value); + oss << StringPrintf(" vreg%u=0x%08X", i, raw_value); if (ref_value != NULL) { if (ref_value->GetClass()->IsStringClass() && ref_value->AsString()->GetCharArray() != NULL) { diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc index ca03885aab..e8504b7a3f 100644 --- a/runtime/interpreter/interpreter_goto_table_impl.cc +++ b/runtime/interpreter/interpreter_goto_table_impl.cc @@ -568,7 +568,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_PENDING_EXCEPTION(); } else { uint32_t size_in_bytes = payload->element_count * payload->element_width; - memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); + memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes); ADVANCE(3); } } diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 7631736a5b..e5d15b17ce 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -483,7 +483,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem break; } uint32_t size_in_bytes = payload->element_count * payload->element_width; - memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); + memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes); inst = inst->Next_3xx(); break; } diff --git a/runtime/invoke_arg_array_builder.h b/runtime/invoke_arg_array_builder.h index f615e8ebac..6ecce4072c 100644 --- a/runtime/invoke_arg_array_builder.h +++ b/runtime/invoke_arg_array_builder.h @@ -78,6 +78,10 @@ class ArgArray { num_bytes_ += 4; } + void Append(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue()); + } + void AppendWide(uint64_t value) { // For ARM and MIPS portable, align wide values to 8 bytes (ArgArray starts at offset of 4). #if defined(ART_USE_PORTABLE_COMPILER) && (defined(__arm__) || defined(__mips__)) @@ -93,8 +97,8 @@ class ArgArray { void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Set receiver if non-null (method is not static) - if (receiver != NULL) { - Append(reinterpret_cast<int32_t>(receiver)); + if (receiver != nullptr) { + Append(receiver); } for (size_t i = 1; i < shorty_len_; ++i) { switch (shorty_[i]) { @@ -112,7 +116,7 @@ class ArgArray { break; } case 'L': - Append(reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(va_arg(ap, jobject)))); + Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject))); break; case 'D': { JValue value; @@ -131,8 +135,8 @@ class ArgArray { void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, jvalue* args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Set receiver if non-null (method is not static) - if (receiver != NULL) { - Append(reinterpret_cast<int32_t>(receiver)); + if (receiver != nullptr) { + Append(receiver); } for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) { switch (shorty_[i]) { @@ -153,7 +157,7 @@ class ArgArray { Append(args[args_offset].i); break; case 'L': - Append(reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(args[args_offset].l))); + Append(soa.Decode<mirror::Object*>(args[args_offset].l)); break; case 'D': case 'J': diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h index ebc844e2c4..334dca432b 100644 --- a/runtime/jdwp/jdwp.h +++ b/runtime/jdwp/jdwp.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_JDWP_JDWP_H_ #define ART_RUNTIME_JDWP_JDWP_H_ -#include "atomic_integer.h" +#include "atomic.h" #include "base/mutex.h" #include "jdwp/jdwp_bits.h" #include "jdwp/jdwp_constants.h" diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 5cd09c2090..deea5f6bc0 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -22,7 +22,7 @@ #include <utility> #include <vector> -#include "atomic_integer.h" +#include "atomic.h" #include "base/logging.h" #include "base/mutex.h" #include "base/stl_util.h" @@ -590,7 +590,7 @@ class Libraries { } // See section 11.3 "Linking Native Methods" of the JNI spec. - void* FindNativeMethod(const ArtMethod* m, std::string& detail) + void* FindNativeMethod(ArtMethod* m, std::string& detail) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string jni_short_name(JniShortName(m)); std::string jni_long_name(JniLongName(m)); @@ -2215,7 +2215,7 @@ class JNI { if (is_copy != nullptr) { *is_copy = JNI_FALSE; } - return array->GetRawData(array->GetClass()->GetComponentSize()); + return array->GetRawData(array->GetClass()->GetComponentSize(), 0); } static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* elements, jint mode) { @@ -2518,10 +2518,10 @@ class JNI { static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { if (capacity < 0) { - JniAbortF("NewDirectByteBuffer", "negative buffer capacity: %lld", capacity); + JniAbortF("NewDirectByteBuffer", "negative buffer capacity: %" PRId64, capacity); } if (address == NULL && capacity != 0) { - JniAbortF("NewDirectByteBuffer", "non-zero capacity for NULL pointer: %lld", capacity); + JniAbortF("NewDirectByteBuffer", "non-zero capacity for NULL pointer: %" PRId64, capacity); } // At the moment, the Java side is limited to 32 bits. @@ -2644,7 +2644,7 @@ class JNI { ScopedObjectAccess soa(env); Array* array = soa.Decode<Array*>(java_array); size_t component_size = array->GetClass()->GetComponentSize(); - void* array_data = array->GetRawData(component_size); + void* array_data = array->GetRawData(component_size, 0); gc::Heap* heap = Runtime::Current()->GetHeap(); bool is_copy = array_data != reinterpret_cast<void*>(elements); size_t bytes = array->GetLength() * component_size; @@ -2944,10 +2944,6 @@ JNIEnvExt::JNIEnvExt(Thread* self, JavaVMExt* vm) if (vm->check_jni) { SetCheckJniEnabled(true); } - // The JniEnv local reference values must be at a consistent offset or else cross-compilation - // errors will ensue. - CHECK_EQ(JNIEnvExt::LocalRefCookieOffset().Int32Value(), 12); - CHECK_EQ(JNIEnvExt::SegmentStateOffset().Int32Value(), 16); } JNIEnvExt::~JNIEnvExt() { diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc index 9b278f8a5a..fed734ef5e 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -131,7 +131,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); } method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V'); @@ -148,11 +148,11 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); + arg_array.Append(0U); result.SetB(-1); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B'); EXPECT_EQ(0, result.GetB()); @@ -184,11 +184,11 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); + arg_array.Append(0U); result.SetI(-1); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I'); EXPECT_EQ(0, result.GetI()); @@ -221,7 +221,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } @@ -264,12 +264,12 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); - arg_array.Append(0); + arg_array.Append(0U); + arg_array.Append(0U); result.SetI(-1); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I'); EXPECT_EQ(0, result.GetI()); @@ -310,13 +310,13 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); result.SetI(-1); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I'); EXPECT_EQ(0, result.GetI()); @@ -361,14 +361,14 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); result.SetI(-1); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I'); EXPECT_EQ(0, result.GetI()); @@ -417,15 +417,15 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); - arg_array.Append(0); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); + arg_array.Append(0U); result.SetI(-1.0); method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I'); EXPECT_EQ(0, result.GetI()); @@ -480,7 +480,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } @@ -547,7 +547,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } @@ -603,7 +603,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } @@ -668,7 +668,7 @@ class JniInternalTest : public CommonTest { JValue result; if (!is_static) { - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); args++; } @@ -1492,8 +1492,8 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) { } while (false) -#if !defined(ART_USE_PORTABLE_COMPILER) TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) { + TEST_DISABLED_FOR_PORTABLE(); Thread::Current()->TransitionFromSuspendedToRunnable(); LoadDex("AllFields"); bool started = runtime_->Start(); @@ -1524,6 +1524,7 @@ TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) { } TEST_F(JniInternalTest, GetObjectField_SetObjectField) { + TEST_DISABLED_FOR_PORTABLE(); Thread::Current()->TransitionFromSuspendedToRunnable(); LoadDex("AllFields"); runtime_->Start(); @@ -1553,7 +1554,6 @@ TEST_F(JniInternalTest, GetObjectField_SetObjectField) { env_->SetObjectField(o, i_fid, s2); ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid))); } -#endif TEST_F(JniInternalTest, NewLocalRef_NULL) { EXPECT_TRUE(env_->NewLocalRef(NULL) == NULL); @@ -1756,7 +1756,7 @@ TEST_F(JniInternalTest, StaticMainMethod) { ASSERT_TRUE(method != NULL); ArgArray arg_array(NULL, 0); - arg_array.Append(0); + arg_array.Append(0U); JValue result; // Start runtime. diff --git a/runtime/lock_word-inl.h b/runtime/lock_word-inl.h index 8b9a3cd954..414b3bb3e1 100644 --- a/runtime/lock_word-inl.h +++ b/runtime/lock_word-inl.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_LOCK_WORD_INL_H_ #include "lock_word.h" +#include "monitor_pool.h" namespace art { @@ -33,7 +34,8 @@ inline uint32_t LockWord::ThinLockCount() const { inline Monitor* LockWord::FatLockMonitor() const { DCHECK_EQ(GetState(), kFatLocked); - return reinterpret_cast<Monitor*>(value_ << kStateSize); + MonitorId mon_id = static_cast<MonitorId>(value_ & ~(kStateMask << kStateShift)); + return MonitorPool::MonitorFromMonitorId(mon_id); } inline size_t LockWord::ForwardingAddress() const { @@ -46,8 +48,7 @@ inline LockWord::LockWord() : value_(0) { } inline LockWord::LockWord(Monitor* mon) - : value_(((reinterpret_cast<uintptr_t>(mon) >> kStateSize) | (kStateFat << kStateShift)) & - 0xFFFFFFFFU) { + : value_(mon->GetMonitorId() | (kStateFat << kStateShift)) { DCHECK_EQ(FatLockMonitor(), mon); } diff --git a/runtime/lock_word.h b/runtime/lock_word.h index d24a3bbecc..ab86eaac7d 100644 --- a/runtime/lock_word.h +++ b/runtime/lock_word.h @@ -42,7 +42,7 @@ class Monitor; * * |33|222222222211111111110000000000| * |10|987654321098765432109876543210| - * |01| Monitor* >> kStateSize | + * |01| MonitorId | * * When the lock word is in hash state and its bits are formatted as follows: * diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 2795e1d1ca..393ea686f4 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -79,7 +79,7 @@ static void CheckMapRequest(byte*, size_t) { } #endif MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot, - std::string* error_msg) { + bool low_4gb, std::string* error_msg) { if (byte_count == 0) { return new MemMap(name, NULL, 0, NULL, 0, prot); } @@ -101,7 +101,11 @@ MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, in ScopedFd fd(-1); int flags = MAP_PRIVATE | MAP_ANONYMOUS; #endif - +#ifdef __LP64__ + if (low_4gb) { + flags |= MAP_32BIT; + } +#endif byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_byte_count, prot, flags, fd.get(), 0)); if (actual == MAP_FAILED) { std::string maps; diff --git a/runtime/mem_map.h b/runtime/mem_map.h index d2059b5c60..e39c10e0c9 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -39,7 +39,7 @@ class MemMap { // // On success, returns returns a MemMap instance. On failure, returns a NULL; static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot, - std::string* error_msg); + bool low_4gb, std::string* error_msg); // Map part of a file, taking care of non-page aligned offsets. The // "start" offset is absolute, not relative. diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc index cf2c9d028c..6cb59b42e4 100644 --- a/runtime/mem_map_test.cc +++ b/runtime/mem_map_test.cc @@ -23,76 +23,111 @@ namespace art { class MemMapTest : public testing::Test { public: - byte* BaseBegin(MemMap* mem_map) { + static byte* BaseBegin(MemMap* mem_map) { return reinterpret_cast<byte*>(mem_map->base_begin_); } - size_t BaseSize(MemMap* mem_map) { + static size_t BaseSize(MemMap* mem_map) { return mem_map->base_size_; } + + static void RemapAtEndTest(bool low_4gb) { + std::string error_msg; + // Cast the page size to size_t. + const size_t page_size = static_cast<size_t>(kPageSize); + // Map a two-page memory region. + MemMap* m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0", + nullptr, + 2 * page_size, + PROT_READ | PROT_WRITE, + low_4gb, + &error_msg); + // Check its state and write to it. + byte* base0 = m0->Begin(); + ASSERT_TRUE(base0 != nullptr) << error_msg; + size_t size0 = m0->Size(); + EXPECT_EQ(m0->Size(), 2 * page_size); + EXPECT_EQ(BaseBegin(m0), base0); + EXPECT_EQ(BaseSize(m0), size0); + memset(base0, 42, 2 * page_size); + // Remap the latter half into a second MemMap. + MemMap* m1 = m0->RemapAtEnd(base0 + page_size, + "MemMapTest_RemapAtEndTest_map1", + PROT_READ | PROT_WRITE, + &error_msg); + // Check the states of the two maps. + EXPECT_EQ(m0->Begin(), base0) << error_msg; + EXPECT_EQ(m0->Size(), page_size); + EXPECT_EQ(BaseBegin(m0), base0); + EXPECT_EQ(BaseSize(m0), page_size); + byte* base1 = m1->Begin(); + size_t size1 = m1->Size(); + EXPECT_EQ(base1, base0 + page_size); + EXPECT_EQ(size1, page_size); + EXPECT_EQ(BaseBegin(m1), base1); + EXPECT_EQ(BaseSize(m1), size1); + // Write to the second region. + memset(base1, 43, page_size); + // Check the contents of the two regions. + for (size_t i = 0; i < page_size; ++i) { + EXPECT_EQ(base0[i], 42); + } + for (size_t i = 0; i < page_size; ++i) { + EXPECT_EQ(base1[i], 43); + } + // Unmap the first region. + delete m0; + // Make sure the second region is still accessible after the first + // region is unmapped. + for (size_t i = 0; i < page_size; ++i) { + EXPECT_EQ(base1[i], 43); + } + delete m1; + } }; TEST_F(MemMapTest, MapAnonymousEmpty) { std::string error_msg; UniquePtr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", - NULL, + nullptr, 0, PROT_READ, + false, &error_msg)); - ASSERT_TRUE(map.get() != NULL) << error_msg; + ASSERT_TRUE(map.get() != nullptr) << error_msg; + ASSERT_TRUE(error_msg.empty()); + map.reset(MemMap::MapAnonymous("MapAnonymousEmpty", + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + false, + &error_msg)); + ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); } -TEST_F(MemMapTest, RemapAtEnd) { +#ifdef __LP64__ +TEST_F(MemMapTest, MapAnonymousEmpty32bit) { std::string error_msg; - // Cast the page size to size_t. - const size_t page_size = static_cast<size_t>(kPageSize); - // Map a two-page memory region. - MemMap* m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0", - NULL, - 2 * page_size, - PROT_READ | PROT_WRITE, - &error_msg); - // Check its state and write to it. - byte* base0 = m0->Begin(); - ASSERT_TRUE(base0 != NULL) << error_msg; - size_t size0 = m0->Size(); - EXPECT_EQ(m0->Size(), 2 * page_size); - EXPECT_EQ(BaseBegin(m0), base0); - EXPECT_EQ(BaseSize(m0), size0); - memset(base0, 42, 2 * page_size); - // Remap the latter half into a second MemMap. - MemMap* m1 = m0->RemapAtEnd(base0 + page_size, - "MemMapTest_RemapAtEndTest_map1", - PROT_READ | PROT_WRITE, - &error_msg); - // Check the states of the two maps. - EXPECT_EQ(m0->Begin(), base0) << error_msg; - EXPECT_EQ(m0->Size(), page_size); - EXPECT_EQ(BaseBegin(m0), base0); - EXPECT_EQ(BaseSize(m0), page_size); - byte* base1 = m1->Begin(); - size_t size1 = m1->Size(); - EXPECT_EQ(base1, base0 + page_size); - EXPECT_EQ(size1, page_size); - EXPECT_EQ(BaseBegin(m1), base1); - EXPECT_EQ(BaseSize(m1), size1); - // Write to the second region. - memset(base1, 43, page_size); - // Check the contents of the two regions. - for (size_t i = 0; i < page_size; ++i) { - EXPECT_EQ(base0[i], 42); - } - for (size_t i = 0; i < page_size; ++i) { - EXPECT_EQ(base1[i], 43); - } - // Unmap the first region. - delete m0; - // Make sure the second region is still accessible after the first - // region is unmapped. - for (size_t i = 0; i < page_size; ++i) { - EXPECT_EQ(base1[i], 43); - } - delete m1; + UniquePtr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + true, + &error_msg)); + ASSERT_TRUE(map.get() != nullptr) << error_msg; + ASSERT_TRUE(error_msg.empty()); + ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32); +} +#endif + +TEST_F(MemMapTest, RemapAtEnd) { + RemapAtEndTest(false); +} + +#ifdef __LP64__ +TEST_F(MemMapTest, RemapAtEnd32bit) { + RemapAtEndTest(true); } +#endif } // namespace art diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index bd81bd5e96..b2725e5451 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -27,7 +27,7 @@ namespace art { namespace mirror { -inline size_t Array::SizeOf() const { +inline size_t Array::SizeOf() { // This is safe from overflow because the array was already allocated, so we know it's sane. size_t component_size = GetClass()->GetComponentSize(); int32_t component_count = GetLength(); @@ -64,9 +64,10 @@ class SetLengthVisitor { explicit SetLengthVisitor(int32_t length) : length_(length) { } - void operator()(mirror::Object* obj) const { - mirror::Array* array = obj->AsArray(); - DCHECK(array->IsArrayInstance()); + void operator()(Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Avoid AsArray as object is not yet in live bitmap or allocation stack. + Array* array = down_cast<Array*>(obj); + // DCHECK(array->IsArrayInstance()); array->SetLength(length_); } @@ -116,6 +117,114 @@ inline void PrimitiveArray<T>::VisitRoots(RootVisitor* visitor, void* arg) { } } +// Similar to memmove except elements are of aligned appropriately for T, count is in T sized units +// copies are guaranteed not to tear when T is less-than 64bit. +template<typename T> +static inline void ArrayBackwardCopy(T* d, const T* s, int32_t count) { + d += count; + s += count; + for (int32_t i = 0; i < count; ++i) { + d--; + s--; + *d = *s; + } +} + +template<class T> +void PrimitiveArray<T>::Memmove(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos, + int32_t count) { + if (UNLIKELY(count == 0)) { + return; + } + DCHECK_GE(dst_pos, 0); + DCHECK_GE(src_pos, 0); + DCHECK_GT(count, 0); + DCHECK(src != nullptr); + DCHECK_LT(dst_pos, GetLength()); + DCHECK_LE(dst_pos, GetLength() - count); + DCHECK_LT(src_pos, src->GetLength()); + DCHECK_LE(src_pos, src->GetLength() - count); + + // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3) + // in our implementation, because they may copy byte-by-byte. + if (LIKELY(src != this) || (dst_pos < src_pos) || (dst_pos - src_pos >= count)) { + // Forward copy ok. + Memcpy(dst_pos, src, src_pos, count); + } else { + // Backward copy necessary. + void* dst_raw = GetRawData(sizeof(T), dst_pos); + const void* src_raw = src->GetRawData(sizeof(T), src_pos); + if (sizeof(T) == sizeof(uint8_t)) { + // TUNING: use memmove here? + uint8_t* d = reinterpret_cast<uint8_t*>(dst_raw); + const uint8_t* s = reinterpret_cast<const uint8_t*>(src_raw); + ArrayBackwardCopy<uint8_t>(d, s, count); + } else if (sizeof(T) == sizeof(uint16_t)) { + uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw); + const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw); + ArrayBackwardCopy<uint16_t>(d, s, count); + } else if (sizeof(T) == sizeof(uint32_t)) { + uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw); + const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw); + ArrayBackwardCopy<uint32_t>(d, s, count); + } else { + DCHECK_EQ(sizeof(T), sizeof(uint64_t)); + uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw); + const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw); + ArrayBackwardCopy<uint64_t>(d, s, count); + } + } +} + +// Similar to memcpy except elements are of aligned appropriately for T, count is in T sized units +// copies are guaranteed not to tear when T is less-than 64bit. +template<typename T> +static inline void ArrayForwardCopy(T* d, const T* s, int32_t count) { + for (int32_t i = 0; i < count; ++i) { + *d = *s; + d++; + s++; + } +} + + +template<class T> +void PrimitiveArray<T>::Memcpy(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos, + int32_t count) { + if (UNLIKELY(count == 0)) { + return; + } + DCHECK_GE(dst_pos, 0); + DCHECK_GE(src_pos, 0); + DCHECK_GT(count, 0); + DCHECK(src != nullptr); + DCHECK_LT(dst_pos, GetLength()); + DCHECK_LE(dst_pos, GetLength() - count); + DCHECK_LT(src_pos, src->GetLength()); + DCHECK_LE(src_pos, src->GetLength() - count); + + // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3) + // in our implementation, because they may copy byte-by-byte. + void* dst_raw = GetRawData(sizeof(T), dst_pos); + const void* src_raw = src->GetRawData(sizeof(T), src_pos); + if (sizeof(T) == sizeof(uint8_t)) { + memcpy(dst_raw, src_raw, count); + } else if (sizeof(T) == sizeof(uint16_t)) { + uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw); + const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw); + ArrayForwardCopy<uint16_t>(d, s, count); + } else if (sizeof(T) == sizeof(uint32_t)) { + uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw); + const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw); + ArrayForwardCopy<uint32_t>(d, s, count); + } else { + DCHECK_EQ(sizeof(T), sizeof(uint64_t)); + uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw); + const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw); + ArrayForwardCopy<uint64_t>(d, s, count); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc index 00b88db299..ca0d1f3977 100644 --- a/runtime/mirror/array.cc +++ b/runtime/mirror/array.cc @@ -103,11 +103,11 @@ Array* Array::CreateMultiArray(Thread* self, Class* element_class, IntArray* dim return new_array; } -void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) const { +void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) { art::ThrowArrayIndexOutOfBoundsException(index, GetLength()); } -void Array::ThrowArrayStoreException(Object* object) const { +void Array::ThrowArrayStoreException(Object* object) { art::ThrowArrayStoreException(object->GetClass(), this->GetClass()); } diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index 207573fa00..6e366a08f5 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -50,15 +50,15 @@ class MANAGED Array : public Object { static Array* CreateMultiArray(Thread* self, Class* element_class, IntArray* dimensions) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t SizeOf() const; + size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t GetLength() const { + int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), false); } - void SetLength(int32_t length) { + void SetLength(int32_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { CHECK_GE(length, 0); - SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false, false); } static MemberOffset LengthOffset() { @@ -74,20 +74,22 @@ class MANAGED Array : public Object { } } - void* GetRawData(size_t component_size) { - intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value(); + void* GetRawData(size_t component_size, int32_t index) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value() + + + (index * component_size); return reinterpret_cast<void*>(data); } - const void* GetRawData(size_t component_size) const { - intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value(); - return reinterpret_cast<const void*>(data); + const void* GetRawData(size_t component_size, int32_t index) const { + intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value() + + + (index * component_size); + return reinterpret_cast<void*>(data); } // Returns true if the index is valid. If not, throws an ArrayIndexOutOfBoundsException and // returns false. - bool CheckIsValidIndex(int32_t index) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool CheckIsValidIndex(int32_t index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(static_cast<uint32_t>(index) >= static_cast<uint32_t>(GetLength()))) { ThrowArrayIndexOutOfBoundsException(index); return false; @@ -96,11 +98,10 @@ class MANAGED Array : public Object { } protected: - void ThrowArrayStoreException(Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void ThrowArrayStoreException(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: - void ThrowArrayIndexOutOfBoundsException(int32_t index) const + void ThrowArrayIndexOutOfBoundsException(int32_t index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // The number of array elements. @@ -119,17 +120,15 @@ class MANAGED PrimitiveArray : public Array { static PrimitiveArray<T>* Alloc(Thread* self, size_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const T* GetData() const { - intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(sizeof(T)).Int32Value(); - return reinterpret_cast<T*>(data); + const T* GetData() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return reinterpret_cast<const T*>(GetRawData(sizeof(T), 0)); } - T* GetData() { - intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(sizeof(T)).Int32Value(); - return reinterpret_cast<T*>(data); + T* GetData() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return reinterpret_cast<T*>(GetRawData(sizeof(T), 0)); } - T Get(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + T Get(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(!CheckIsValidIndex(i))) { DCHECK(Thread::Current()->IsExceptionPending()); return T(0); @@ -137,7 +136,7 @@ class MANAGED PrimitiveArray : public Array { return GetWithoutChecks(i); } - T GetWithoutChecks(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + T GetWithoutChecks(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(CheckIsValidIndex(i)); return GetData()[i]; } @@ -155,6 +154,22 @@ class MANAGED PrimitiveArray : public Array { GetData()[i] = value; } + /* + * Works like memmove(), except we guarantee not to allow tearing of array values (ie using + * smaller than element size copies). Arguments are assumed to be within the bounds of the array + * and the arrays non-null. + */ + void Memmove(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos, int32_t count) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + /* + * Works like memcpy(), except we guarantee not to allow tearing of array values (ie using + * smaller than element size copies). Arguments are assumed to be within the bounds of the array + * and the arrays non-null. + */ + void Memcpy(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos, int32_t count) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static void SetArrayClass(Class* array_class) { CHECK(array_class_ == NULL); CHECK(array_class != NULL); diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h index d8c278c9ac..530226b4dd 100644 --- a/runtime/mirror/art_field-inl.h +++ b/runtime/mirror/art_field-inl.h @@ -29,8 +29,8 @@ namespace art { namespace mirror { -inline Class* ArtField::GetDeclaringClass() const { - Class* result = GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_), false); +inline Class* ArtField::GetDeclaringClass() { + Class* result = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_), false); DCHECK(result != NULL); DCHECK(result->IsLoaded() || result->IsErroneous()); return result; @@ -40,106 +40,106 @@ inline void ArtField::SetDeclaringClass(Class *new_declaring_class) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_), new_declaring_class, false); } -inline uint32_t ArtField::GetAccessFlags() const { +inline uint32_t ArtField::GetAccessFlags() { DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), false); } -inline MemberOffset ArtField::GetOffset() const { +inline MemberOffset ArtField::GetOffset() { DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous()); return MemberOffset(GetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), false)); } -inline MemberOffset ArtField::GetOffsetDuringLinking() const { +inline MemberOffset ArtField::GetOffsetDuringLinking() { DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); return MemberOffset(GetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), false)); } -inline uint32_t ArtField::Get32(const Object* object) const { +inline uint32_t ArtField::Get32(Object* object) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); return object->GetField32(GetOffset(), IsVolatile()); } -inline void ArtField::Set32(Object* object, uint32_t new_value) const { +inline void ArtField::Set32(Object* object, uint32_t new_value) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetField32(GetOffset(), new_value, IsVolatile()); } -inline uint64_t ArtField::Get64(const Object* object) const { +inline uint64_t ArtField::Get64(Object* object) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); return object->GetField64(GetOffset(), IsVolatile()); } -inline void ArtField::Set64(Object* object, uint64_t new_value) const { +inline void ArtField::Set64(Object* object, uint64_t new_value) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetField64(GetOffset(), new_value, IsVolatile()); } -inline Object* ArtField::GetObj(const Object* object) const { +inline Object* ArtField::GetObj(Object* object) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); - return object->GetFieldObject<Object*>(GetOffset(), IsVolatile()); + return object->GetFieldObject<Object>(GetOffset(), IsVolatile()); } -inline void ArtField::SetObj(Object* object, const Object* new_value) const { +inline void ArtField::SetObj(Object* object, Object* new_value) { DCHECK(object != NULL) << PrettyField(this); DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted()); object->SetFieldObject(GetOffset(), new_value, IsVolatile()); } -inline bool ArtField::GetBoolean(const Object* object) const { +inline bool ArtField::GetBoolean(Object* object) { DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); return Get32(object); } -inline void ArtField::SetBoolean(Object* object, bool z) const { +inline void ArtField::SetBoolean(Object* object, bool z) { DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); Set32(object, z); } -inline int8_t ArtField::GetByte(const Object* object) const { +inline int8_t ArtField::GetByte(Object* object) { DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); return Get32(object); } -inline void ArtField::SetByte(Object* object, int8_t b) const { +inline void ArtField::SetByte(Object* object, int8_t b) { DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); Set32(object, b); } -inline uint16_t ArtField::GetChar(const Object* object) const { +inline uint16_t ArtField::GetChar(Object* object) { DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); return Get32(object); } -inline void ArtField::SetChar(Object* object, uint16_t c) const { +inline void ArtField::SetChar(Object* object, uint16_t c) { DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); Set32(object, c); } -inline int16_t ArtField::GetShort(const Object* object) const { +inline int16_t ArtField::GetShort(Object* object) { DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); return Get32(object); } -inline void ArtField::SetShort(Object* object, int16_t s) const { +inline void ArtField::SetShort(Object* object, int16_t s) { DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); Set32(object, s); } -inline int32_t ArtField::GetInt(const Object* object) const { +inline int32_t ArtField::GetInt(Object* object) { #ifndef NDEBUG Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType(); CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this); @@ -147,7 +147,7 @@ inline int32_t ArtField::GetInt(const Object* object) const { return Get32(object); } -inline void ArtField::SetInt(Object* object, int32_t i) const { +inline void ArtField::SetInt(Object* object, int32_t i) { #ifndef NDEBUG Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType(); CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this); @@ -155,7 +155,7 @@ inline void ArtField::SetInt(Object* object, int32_t i) const { Set32(object, i); } -inline int64_t ArtField::GetLong(const Object* object) const { +inline int64_t ArtField::GetLong(Object* object) { #ifndef NDEBUG Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType(); CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this); @@ -163,7 +163,7 @@ inline int64_t ArtField::GetLong(const Object* object) const { return Get64(object); } -inline void ArtField::SetLong(Object* object, int64_t j) const { +inline void ArtField::SetLong(Object* object, int64_t j) { #ifndef NDEBUG Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType(); CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this); @@ -171,7 +171,7 @@ inline void ArtField::SetLong(Object* object, int64_t j) const { Set64(object, j); } -inline float ArtField::GetFloat(const Object* object) const { +inline float ArtField::GetFloat(Object* object) { DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); JValue bits; @@ -179,7 +179,7 @@ inline float ArtField::GetFloat(const Object* object) const { return bits.GetF(); } -inline void ArtField::SetFloat(Object* object, float f) const { +inline void ArtField::SetFloat(Object* object, float f) { DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); JValue bits; @@ -187,7 +187,7 @@ inline void ArtField::SetFloat(Object* object, float f) const { Set32(object, bits.GetI()); } -inline double ArtField::GetDouble(const Object* object) const { +inline double ArtField::GetDouble(Object* object) { DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); JValue bits; @@ -195,7 +195,7 @@ inline double ArtField::GetDouble(const Object* object) const { return bits.GetD(); } -inline void ArtField::SetDouble(Object* object, double d) const { +inline void ArtField::SetDouble(Object* object, double d) { DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); JValue bits; @@ -203,13 +203,13 @@ inline void ArtField::SetDouble(Object* object, double d) const { Set64(object, bits.GetJ()); } -inline Object* ArtField::GetObject(const Object* object) const { +inline Object* ArtField::GetObject(Object* object) { DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); return GetObj(object); } -inline void ArtField::SetObject(Object* object, const Object* l) const { +inline void ArtField::SetObject(Object* object, Object* l) { DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType()) << PrettyField(this); SetObj(object, l); diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h index 62bcf062e1..b33fe4be4e 100644 --- a/runtime/mirror/art_field.h +++ b/runtime/mirror/art_field.h @@ -30,98 +30,74 @@ namespace mirror { // C++ mirror of java.lang.reflect.ArtField class MANAGED ArtField : public Object { public: - Class* GetDeclaringClass() const; + Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDeclaringClass(Class *new_declaring_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint32_t GetAccessFlags() const; + uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetAccessFlags(uint32_t new_access_flags) { + void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), new_access_flags, false); } - bool IsPublic() const { + bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccPublic) != 0; } - bool IsStatic() const { + bool IsStatic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccStatic) != 0; } - bool IsFinal() const { + bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccFinal) != 0; } - uint32_t GetDexFieldIndex() const { + uint32_t GetDexFieldIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), false); } - void SetDexFieldIndex(uint32_t new_idx) { + void SetDexFieldIndex(uint32_t new_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), new_idx, false); } - // Offset to field within an Object - MemberOffset GetOffset() const; + // Offset to field within an Object. + MemberOffset GetOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static MemberOffset OffsetOffset() { return MemberOffset(OFFSETOF_MEMBER(ArtField, offset_)); } - MemberOffset GetOffsetDuringLinking() const; + MemberOffset GetOffsetDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetOffset(MemberOffset num_bytes); + void SetOffset(MemberOffset num_bytes) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // field access, null object for static fields - bool GetBoolean(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetBoolean(Object* object, bool z) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int8_t GetByte(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetByte(Object* object, int8_t b) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint16_t GetChar(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetChar(Object* object, uint16_t c) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int16_t GetShort(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetShort(Object* object, int16_t s) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t GetInt(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetInt(Object* object, int32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int64_t GetLong(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetLong(Object* object, int64_t j) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - float GetFloat(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetFloat(Object* object, float f) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - double GetDouble(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetDouble(Object* object, double d) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Object* GetObject(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetObject(Object* object, const Object* l) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - // raw field accesses - uint32_t Get32(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void Set32(Object* object, uint32_t new_value) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint64_t Get64(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void Set64(Object* object, uint64_t new_value) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Object* GetObj(const Object* object) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetObj(Object* object, const Object* new_value) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool GetBoolean(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetBoolean(Object* object, bool z) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int8_t GetByte(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetByte(Object* object, int8_t b) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint16_t GetChar(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetChar(Object* object, uint16_t c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int16_t GetShort(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetShort(Object* object, int16_t s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int32_t GetInt(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetInt(Object* object, int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int64_t GetLong(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetLong(Object* object, int64_t j) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + float GetFloat(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetFloat(Object* object, float f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + double GetDouble(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetDouble(Object* object, double d) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + Object* GetObject(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetObject(Object* object, Object* l) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Raw field accesses. + uint32_t Get32(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void Set32(Object* object, uint32_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint64_t Get64(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void Set64(Object* object, uint64_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + Object* GetObj(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetObj(Object* object, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static Class* GetJavaLangReflectArtField() { DCHECK(java_lang_reflect_ArtField_ != NULL); @@ -133,14 +109,14 @@ class MANAGED ArtField : public Object { static void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsVolatile() const { + bool IsVolatile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccVolatile) != 0; } private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of - Class* declaring_class_; + HeapReference<Class> declaring_class_; uint32_t access_flags_; diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 088f616d41..8ef3be821b 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -27,8 +27,9 @@ namespace art { namespace mirror { -inline Class* ArtMethod::GetDeclaringClass() const { - Class* result = GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_), false); +inline Class* ArtMethod::GetDeclaringClass() { + Class* result = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_), + false); DCHECK(result != NULL) << this; DCHECK(result->IsIdxLoaded() || result->IsErroneous()) << this; return result; @@ -38,44 +39,44 @@ inline void ArtMethod::SetDeclaringClass(Class *new_declaring_class) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_), new_declaring_class, false); } -inline uint32_t ArtMethod::GetAccessFlags() const { +inline uint32_t ArtMethod::GetAccessFlags() { DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), false); } -inline uint16_t ArtMethod::GetMethodIndex() const { +inline uint16_t ArtMethod::GetMethodIndex() { DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), false); } -inline uint32_t ArtMethod::GetDexMethodIndex() const { +inline uint32_t ArtMethod::GetDexMethodIndex() { #ifdef ART_SEA_IR_MODE // TODO: Re-add this check for (PORTABLE + SMALL + ) SEA IR when PORTABLE IS fixed! // DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); #else DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); #endif - return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_dex_index_), false); + return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), false); } -inline ObjectArray<String>* ArtMethod::GetDexCacheStrings() const { - return GetFieldObject<ObjectArray<String>*>( +inline ObjectArray<String>* ArtMethod::GetDexCacheStrings() { + return GetFieldObject<ObjectArray<String> >( OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_), false); } -inline ObjectArray<ArtMethod>* ArtMethod::GetDexCacheResolvedMethods() const { - return GetFieldObject<ObjectArray<ArtMethod>*>( +inline ObjectArray<ArtMethod>* ArtMethod::GetDexCacheResolvedMethods() { + return GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_), false); } -inline ObjectArray<Class>* ArtMethod::GetDexCacheResolvedTypes() const { - return GetFieldObject<ObjectArray<Class>*>( +inline ObjectArray<Class>* ArtMethod::GetDexCacheResolvedTypes() { + return GetFieldObject<ObjectArray<Class> >( OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_), false); } -inline uint32_t ArtMethod::GetCodeSize() const { +inline uint32_t ArtMethod::GetCodeSize() { DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this); - uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromCompiledCode()); + uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode()); if (code == 0) { return 0; } @@ -106,7 +107,7 @@ inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) { } } -inline void ArtMethod::AssertPcIsWithinCode(uintptr_t pc) const { +inline void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) { if (!kIsDebugBuild) { return; } @@ -116,34 +117,44 @@ inline void ArtMethod::AssertPcIsWithinCode(uintptr_t pc) const { if (pc == GetQuickInstrumentationExitPc()) { return; } - const void* code = GetEntryPointFromCompiledCode(); - if (code == GetCompiledCodeToInterpreterBridge() || code == GetQuickInstrumentationEntryPoint()) { + const void* code = GetEntryPointFromQuickCompiledCode(); + if (code == GetQuickToInterpreterBridge() || code == GetQuickInstrumentationEntryPoint()) { return; } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (code == GetResolutionTrampoline(class_linker)) { + if (code == GetQuickResolutionTrampoline(class_linker)) { return; } - DCHECK(IsWithinCode(pc)) + DCHECK(IsWithinQuickCode(pc)) << PrettyMethod(this) << " pc=" << std::hex << pc << " code=" << code << " size=" << GetCodeSize(); } -inline uint32_t ArtMethod::GetOatCodeOffset() const { +inline uint32_t ArtMethod::GetQuickOatCodeOffset() { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetEntryPointFromCompiledCode()); + return PointerToLowMemUInt32(GetEntryPointFromQuickCompiledCode()); } -inline void ArtMethod::SetOatCodeOffset(uint32_t code_offset) { +inline uint32_t ArtMethod::GetPortableOatCodeOffset() { DCHECK(!Runtime::Current()->IsStarted()); - SetEntryPointFromCompiledCode(reinterpret_cast<void*>(code_offset)); + return PointerToLowMemUInt32(GetEntryPointFromPortableCompiledCode()); } -inline uint32_t ArtMethod::GetOatMappingTableOffset() const { +inline void ArtMethod::SetQuickOatCodeOffset(uint32_t code_offset) { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetMappingTable()); + SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(code_offset)); +} + +inline void ArtMethod::SetPortableOatCodeOffset(uint32_t code_offset) { + DCHECK(!Runtime::Current()->IsStarted()); + SetEntryPointFromPortableCompiledCode(reinterpret_cast<void*>(code_offset)); +} + +inline uint32_t ArtMethod::GetOatMappingTableOffset() { + DCHECK(!Runtime::Current()->IsStarted()); + return PointerToLowMemUInt32(GetMappingTable()); } inline void ArtMethod::SetOatMappingTableOffset(uint32_t mapping_table_offset) { @@ -151,9 +162,9 @@ inline void ArtMethod::SetOatMappingTableOffset(uint32_t mapping_table_offset) { SetMappingTable(reinterpret_cast<const uint8_t*>(mapping_table_offset)); } -inline uint32_t ArtMethod::GetOatVmapTableOffset() const { +inline uint32_t ArtMethod::GetOatVmapTableOffset() { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetVmapTable()); + return PointerToLowMemUInt32(GetVmapTable()); } inline void ArtMethod::SetOatVmapTableOffset(uint32_t vmap_table_offset) { @@ -166,16 +177,16 @@ inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) { SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset)); } -inline uint32_t ArtMethod::GetOatNativeGcMapOffset() const { +inline uint32_t ArtMethod::GetOatNativeGcMapOffset() { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetNativeGcMap()); + return PointerToLowMemUInt32(GetNativeGcMap()); } -inline bool ArtMethod::IsRuntimeMethod() const { +inline bool ArtMethod::IsRuntimeMethod() { return GetDexMethodIndex() == DexFile::kDexNoIndex; } -inline bool ArtMethod::IsCalleeSaveMethod() const { +inline bool ArtMethod::IsCalleeSaveMethod() { if (!IsRuntimeMethod()) { return false; } @@ -190,14 +201,14 @@ inline bool ArtMethod::IsCalleeSaveMethod() const { return result; } -inline bool ArtMethod::IsResolutionMethod() const { +inline bool ArtMethod::IsResolutionMethod() { bool result = this == Runtime::Current()->GetResolutionMethod(); // Check that if we do think it is phony it looks like the resolution method. DCHECK(!result || IsRuntimeMethod()); return result; } -inline bool ArtMethod::IsImtConflictMethod() const { +inline bool ArtMethod::IsImtConflictMethod() { bool result = this == Runtime::Current()->GetImtConflictMethod(); // Check that if we do think it is phony it looks like the imt conflict method. DCHECK(!result || IsRuntimeMethod()); diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index f4a076cf13..575ea03519 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -47,7 +47,7 @@ void ArtMethod::VisitRoots(RootVisitor* visitor, void* arg) { } } -InvokeType ArtMethod::GetInvokeType() const { +InvokeType ArtMethod::GetInvokeType() { // TODO: kSuper? if (GetDeclaringClass()->IsInterface()) { return kInterface; @@ -100,11 +100,11 @@ size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) { return num_registers; } -bool ArtMethod::IsProxyMethod() const { +bool ArtMethod::IsProxyMethod() { return GetDeclaringClass()->IsProxyClass(); } -ArtMethod* ArtMethod::FindOverriddenMethod() const { +ArtMethod* ArtMethod::FindOverriddenMethod() { if (IsStatic()) { return NULL; } @@ -147,13 +147,16 @@ ArtMethod* ArtMethod::FindOverriddenMethod() const { return result; } -uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) const { +uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) { const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this); return pc - reinterpret_cast<uintptr_t>(code); } -uint32_t ArtMethod::ToDexPc(const uintptr_t pc) const { -#if !defined(ART_USE_PORTABLE_COMPILER) +uint32_t ArtMethod::ToDexPc(const uintptr_t pc) { + if (IsPortableCompiled()) { + // Portable doesn't use the machine pc, we just use dex pc instead. + return static_cast<uint32_t>(pc); + } MappingTable table(GetMappingTable()); if (table.TotalSize() == 0) { DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this); @@ -176,16 +179,12 @@ uint32_t ArtMethod::ToDexPc(const uintptr_t pc) const { } } LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset) - << "(PC " << reinterpret_cast<void*>(pc) << ", code=" << code - << ") in " << PrettyMethod(this); + << "(PC " << reinterpret_cast<void*>(pc) << ", code=" << code + << ") in " << PrettyMethod(this); return DexFile::kDexNoIndex; -#else - // Compiler LLVM doesn't use the machine pc, we just use dex pc instead. - return static_cast<uint32_t>(pc); -#endif } -uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) const { +uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) { MappingTable table(GetMappingTable()); if (table.TotalSize() == 0) { DCHECK_EQ(dex_pc, 0U); @@ -213,7 +212,7 @@ uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) const { } uint32_t ArtMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc, - bool* has_no_move_exception) const { + bool* has_no_move_exception) { MethodHelper mh(this); const DexFile::CodeItem* code_item = mh.GetCodeItem(); // Default to handler not found. @@ -265,16 +264,21 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* } } else { const bool kLogInvocationStartAndReturn = false; - if (GetEntryPointFromCompiledCode() != NULL) { + bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr; + bool have_portable_code = GetEntryPointFromPortableCompiledCode() != nullptr; + if (LIKELY(have_quick_code || have_portable_code)) { if (kLogInvocationStartAndReturn) { - LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode()); + LOG(INFO) << StringPrintf("Invoking '%s' %s code=%p", PrettyMethod(this).c_str(), + have_quick_code ? "quick" : "portable", + have_quick_code ? GetEntryPointFromQuickCompiledCode() + : GetEntryPointFromPortableCompiledCode()); } -#ifdef ART_USE_PORTABLE_COMPILER - (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type); -#else - (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type); -#endif - if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) { + if (!IsPortableCompiled()) { + (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type); + } else { + (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type); + } + if (UNLIKELY(reinterpret_cast<intptr_t>(self->GetException(NULL)) == -1)) { // Unusual case where we were running LLVM generated code and an // exception was thrown to force the activations to be removed from the // stack. Continue execution in the interpreter. @@ -285,11 +289,13 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result); } if (kLogInvocationStartAndReturn) { - LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode()); + LOG(INFO) << StringPrintf("Returned '%s' %s code=%p", PrettyMethod(this).c_str(), + have_quick_code ? "quick" : "portable", + have_quick_code ? GetEntryPointFromQuickCompiledCode() + : GetEntryPointFromPortableCompiledCode()); } } else { - LOG(INFO) << "Not invoking '" << PrettyMethod(this) - << "' code=" << reinterpret_cast<const void*>(GetEntryPointFromCompiledCode()); + LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null"; if (result != NULL) { result->SetJ(0); } @@ -300,9 +306,10 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* self->PopManagedStackFragment(fragment); } -bool ArtMethod::IsRegistered() const { - void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, native_method_), false); - CHECK(native_method != NULL); +bool ArtMethod::IsRegistered() { + void* native_method = + GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), false); + CHECK(native_method != nullptr); void* jni_stub = GetJniDlsymLookupStub(); return native_method != jni_stub; } @@ -323,7 +330,7 @@ void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_ // around JNI bugs, that include not giving Object** SIRT references to native methods. Direct // the native method to runtime support and store the target somewhere runtime support will // find it. -#if defined(__i386__) +#if defined(__i386__) || defined(__x86_64__) UNIMPLEMENTED(FATAL); #else SetNativeMethod(reinterpret_cast<void*>(art_work_around_app_jni_bugs)); @@ -340,7 +347,7 @@ void ArtMethod::UnregisterNative(Thread* self) { } void ArtMethod::SetNativeMethod(const void* native_method) { - SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, native_method_), + SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), native_method, false); } diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 95ca4c9975..bfa7cbe10f 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -45,7 +45,7 @@ typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh, // C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor class MANAGED ArtMethod : public Object { public: - Class* GetDeclaringClass() const; + Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDeclaringClass(Class *new_declaring_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -53,41 +53,37 @@ class MANAGED ArtMethod : public Object { return MemberOffset(OFFSETOF_MEMBER(ArtMethod, declaring_class_)); } - static MemberOffset EntryPointFromCompiledCodeOffset() { - return MemberOffset(OFFSETOF_MEMBER(ArtMethod, entry_point_from_compiled_code_)); - } - - uint32_t GetAccessFlags() const; + uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetAccessFlags(uint32_t new_access_flags) { + void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), new_access_flags, false); } // Approximate what kind of method call would be used for this method. - InvokeType GetInvokeType() const; + InvokeType GetInvokeType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns true if the method is declared public. - bool IsPublic() const { + bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccPublic) != 0; } // Returns true if the method is declared private. - bool IsPrivate() const { + bool IsPrivate() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccPrivate) != 0; } // Returns true if the method is declared static. - bool IsStatic() const { + bool IsStatic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccStatic) != 0; } // Returns true if the method is a constructor. - bool IsConstructor() const { + bool IsConstructor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccConstructor) != 0; } // Returns true if the method is static, private, or a constructor. - bool IsDirect() const { + bool IsDirect() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return IsDirect(GetAccessFlags()); } @@ -96,55 +92,70 @@ class MANAGED ArtMethod : public Object { } // Returns true if the method is declared synchronized. - bool IsSynchronized() const { + bool IsSynchronized() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized; return (GetAccessFlags() & synchonized) != 0; } - bool IsFinal() const { + bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccFinal) != 0; } - bool IsMiranda() const { + bool IsMiranda() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccMiranda) != 0; } - bool IsNative() const { + bool IsNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccNative) != 0; } - bool IsFastNative() const { + bool IsFastNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t mask = kAccFastNative | kAccNative; return (GetAccessFlags() & mask) == mask; } - bool IsAbstract() const { + bool IsAbstract() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccAbstract) != 0; } - bool IsSynthetic() const { + bool IsSynthetic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccSynthetic) != 0; } - bool IsProxyMethod() const; + bool IsProxyMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsPreverified() const { + bool IsPreverified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccPreverified) != 0; } - void SetPreverified() { + void SetPreverified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(!IsPreverified()); SetAccessFlags(GetAccessFlags() | kAccPreverified); } + bool IsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccPortableCompiled) != 0; + } + + void SetIsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(!IsPortableCompiled()); + SetAccessFlags(GetAccessFlags() | kAccPortableCompiled); + } + + void ClearIsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(IsPortableCompiled()); + SetAccessFlags(GetAccessFlags() & ~kAccPortableCompiled); + } + bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint16_t GetMethodIndex() const; + uint16_t GetMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t GetVtableIndex() const { + size_t GetVtableIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetMethodIndex(); } - void SetMethodIndex(uint16_t new_method_index) { + void SetMethodIndex(uint16_t new_method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), new_method_index, false); } @@ -152,24 +163,24 @@ class MANAGED ArtMethod : public Object { return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_); } - uint32_t GetCodeItemOffset() const { - return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, code_item_offset_), false); + uint32_t GetCodeItemOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), false); } void SetCodeItemOffset(uint32_t new_code_off) { - SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, code_item_offset_), new_code_off, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), new_code_off, false); } // Number of 32bit registers that would be required to hold all the arguments static size_t NumArgRegisters(const StringPiece& shorty); - uint32_t GetDexMethodIndex() const; + uint32_t GetDexMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDexMethodIndex(uint32_t new_idx) { - SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_dex_index_), new_idx, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx, false); } - ObjectArray<String>* GetDexCacheStrings() const; + ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -185,41 +196,62 @@ class MANAGED ArtMethod : public Object { return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_); } - ObjectArray<ArtMethod>* GetDexCacheResolvedMethods() const; + ObjectArray<ArtMethod>* GetDexCacheResolvedMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<Class>* GetDexCacheResolvedTypes() const; + ObjectArray<Class>* GetDexCacheResolvedTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_types) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find the method that this method overrides - ArtMethod* FindOverriddenMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, char result_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - EntryPointFromInterpreter* GetEntryPointFromInterpreter() const { - return GetFieldPtr<EntryPointFromInterpreter*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_), false); + EntryPointFromInterpreter* GetEntryPointFromInterpreter() { + return GetFieldPtr<EntryPointFromInterpreter*>( + OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_), false); } void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) { - SetFieldPtr<EntryPointFromInterpreter*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_), entry_point_from_interpreter, false); + SetFieldPtr<EntryPointFromInterpreter*>( + OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_), + entry_point_from_interpreter, false); } - const void* GetEntryPointFromCompiledCode() const { - return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_compiled_code_), false); + static MemberOffset EntryPointFromPortableCompiledCodeOffset() { + return MemberOffset(OFFSETOF_MEMBER(ArtMethod, entry_point_from_portable_compiled_code_)); } - void SetEntryPointFromCompiledCode(const void* entry_point_from_compiled_code) { - SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_compiled_code_), entry_point_from_compiled_code, false); + const void* GetEntryPointFromPortableCompiledCode() { + return GetFieldPtr<const void*>(EntryPointFromPortableCompiledCodeOffset(), false); } - uint32_t GetCodeSize() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetEntryPointFromPortableCompiledCode(const void* entry_point_from_portable_compiled_code) { + SetFieldPtr<const void*>(EntryPointFromPortableCompiledCodeOffset(), + entry_point_from_portable_compiled_code, false); + } + + static MemberOffset EntryPointFromQuickCompiledCodeOffset() { + return MemberOffset(OFFSETOF_MEMBER(ArtMethod, entry_point_from_quick_compiled_code_)); + } - bool IsWithinCode(uintptr_t pc) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromCompiledCode()); + const void* GetEntryPointFromQuickCompiledCode() { + return GetFieldPtr<const void*>(EntryPointFromQuickCompiledCodeOffset(), false); + } + + void SetEntryPointFromQuickCompiledCode(const void* entry_point_from_quick_compiled_code) { + SetFieldPtr<const void*>(EntryPointFromQuickCompiledCodeOffset(), + entry_point_from_quick_compiled_code, false); + } + + + uint32_t GetCodeSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + bool IsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode()); if (code == 0) { return pc == 0; } @@ -231,45 +263,44 @@ class MANAGED ArtMethod : public Object { return (code <= pc && pc <= code + GetCodeSize()); } - void AssertPcIsWithinCode(uintptr_t pc) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - uint32_t GetOatCodeOffset() const; + void AssertPcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetOatCodeOffset(uint32_t code_offset); - - static MemberOffset GetEntryPointFromCompiledCodeOffset() { - return OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_compiled_code_); - } + uint32_t GetQuickOatCodeOffset(); + uint32_t GetPortableOatCodeOffset(); + void SetQuickOatCodeOffset(uint32_t code_offset); + void SetPortableOatCodeOffset(uint32_t code_offset); // Callers should wrap the uint8_t* in a MappingTable instance for convenient access. - const uint8_t* GetMappingTable() const { - return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, mapping_table_), false); + const uint8_t* GetMappingTable() { + return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_), + false); } void SetMappingTable(const uint8_t* mapping_table) { - SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, mapping_table_), - mapping_table, false); + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_), + mapping_table, false); } - uint32_t GetOatMappingTableOffset() const; + uint32_t GetOatMappingTableOffset(); void SetOatMappingTableOffset(uint32_t mapping_table_offset); // Callers should wrap the uint8_t* in a VmapTable instance for convenient access. - const uint8_t* GetVmapTable() const { - return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, vmap_table_), false); + const uint8_t* GetVmapTable() { + return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), + false); } void SetVmapTable(const uint8_t* vmap_table) { - SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, vmap_table_), vmap_table, false); + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table, + false); } - uint32_t GetOatVmapTableOffset() const; + uint32_t GetOatVmapTableOffset(); void SetOatVmapTableOffset(uint32_t vmap_table_offset); - const uint8_t* GetNativeGcMap() const { + const uint8_t* GetNativeGcMap() { return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), false); } void SetNativeGcMap(const uint8_t* data) { @@ -278,31 +309,30 @@ class MANAGED ArtMethod : public Object { // When building the oat need a convenient place to stuff the offset of the native GC map. void SetOatNativeGcMapOffset(uint32_t gc_map_offset); - uint32_t GetOatNativeGcMapOffset() const; + uint32_t GetOatNativeGcMapOffset(); - size_t GetFrameSizeInBytes() const { + size_t GetFrameSizeInBytes() { DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); - size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, frame_size_in_bytes_), false); + size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_), false); DCHECK_LE(static_cast<size_t>(kStackAlignment), result); return result; } void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) { - DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); - SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, frame_size_in_bytes_), + SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_), new_frame_size_in_bytes, false); } - size_t GetReturnPcOffsetInBytes() const { + size_t GetReturnPcOffsetInBytes() { return GetFrameSizeInBytes() - kPointerSize; } - size_t GetSirtOffsetInBytes() const { + size_t GetSirtOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { CHECK(IsNative()); return kPointerSize; } - bool IsRegistered() const; + bool IsRegistered(); void RegisterNative(Thread* self, const void* native_method, bool is_fast) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -310,10 +340,10 @@ class MANAGED ArtMethod : public Object { void UnregisterNative(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static MemberOffset NativeMethodOffset() { - return OFFSET_OF_OBJECT_MEMBER(ArtMethod, native_method_); + return OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_); } - const void* GetNativeMethod() const { + const void* GetNativeMethod() { return reinterpret_cast<const void*>(GetField32(NativeMethodOffset(), false)); } @@ -323,47 +353,47 @@ class MANAGED ArtMethod : public Object { return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_); } - uint32_t GetCoreSpillMask() const { - return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, core_spill_mask_), false); + uint32_t GetCoreSpillMask() { + return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), false); } void SetCoreSpillMask(uint32_t core_spill_mask) { // Computed during compilation - SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, core_spill_mask_), core_spill_mask, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask, false); } - uint32_t GetFpSpillMask() const { - return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, fp_spill_mask_), false); + uint32_t GetFpSpillMask() { + return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), false); } void SetFpSpillMask(uint32_t fp_spill_mask) { // Computed during compilation - SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, fp_spill_mask_), fp_spill_mask, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask, false); } // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal // conventions for a method of managed code. Returns false for Proxy methods. - bool IsRuntimeMethod() const; + bool IsRuntimeMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Is this a hand crafted method used for something like describing callee saves? - bool IsCalleeSaveMethod() const; + bool IsCalleeSaveMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsResolutionMethod() const; + bool IsResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsImtConflictMethod() const; + bool IsImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uintptr_t NativePcOffset(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a native PC to a dex PC. - uint32_t ToDexPc(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t ToDexPc(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a dex PC to a native PC. - uintptr_t ToNativePc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uintptr_t ToNativePc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find the catch block for the given exception type and dex_pc. When a catch block is found, // indicates whether the found catch block is responsible for clearing the exception or whether // a move-exception instruction is present. - uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc, bool* has_no_move_exception) const + uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc, bool* has_no_move_exception) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void SetClass(Class* java_lang_reflect_ArtMethod); @@ -379,65 +409,83 @@ class MANAGED ArtMethod : public Object { protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". - // The class we are a part of - Class* declaring_class_; + // The class we are a part of. + HeapReference<Class> declaring_class_; - // short cuts to declaring_class_->dex_cache_ member for fast compiled code access - ObjectArray<ArtMethod>* dex_cache_resolved_methods_; + // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. + HeapReference<ObjectArray<ArtMethod> > dex_cache_resolved_methods_; - // short cuts to declaring_class_->dex_cache_ member for fast compiled code access - ObjectArray<Class>* dex_cache_resolved_types_; + // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. + HeapReference<ObjectArray<Class> > dex_cache_resolved_types_; - // short cuts to declaring_class_->dex_cache_ member for fast compiled code access - ObjectArray<String>* dex_cache_strings_; + // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. + HeapReference<ObjectArray<String> > dex_cache_strings_; - // Access flags; low 16 bits are defined by spec. - uint32_t access_flags_; + // Method dispatch from the interpreter invokes this pointer which may cause a bridge into + // compiled code. + uint64_t entry_point_from_interpreter_; - // Offset to the CodeItem. - uint32_t code_item_offset_; + // Pointer to JNI function registered to this method, or a function to resolve the JNI function. + uint64_t entry_point_from_jni_; + + // Method dispatch from portable compiled code invokes this pointer which may cause bridging into + // quick compiled code or the interpreter. + uint64_t entry_point_from_portable_compiled_code_; - // Architecture-dependent register spill mask - uint32_t core_spill_mask_; + // Method dispatch from quick compiled code invokes this pointer which may cause bridging into + // portable compiled code or the interpreter. + uint64_t entry_point_from_quick_compiled_code_; - // Compiled code associated with this method for callers from managed code. - // May be compiled managed code or a bridge for invoking a native method. - // TODO: Break apart this into portable and quick. - const void* entry_point_from_compiled_code_; + // Pointer to a data structure created by the compiler and used by the garbage collector to + // determine which registers hold live references to objects within the heap. Keyed by native PC + // offsets for the quick compiler and dex PCs for the portable. + uint64_t gc_map_; + + // --- Quick compiler meta-data. --- + // TODO: merge and place in native heap, such as done with the code size. + + // Pointer to a data structure created by the quick compiler to map between dex PCs and native + // PCs, and vice-versa. + uint64_t quick_mapping_table_; + + // When a register is promoted into a register, the spill mask holds which registers hold dex + // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth + // is vmap_table_[N]. vmap_table_[0] holds the length of the table. + uint64_t quick_vmap_table_; - // Called by the interpreter to execute this method. - EntryPointFromInterpreter* entry_point_from_interpreter_; + // --- End of quick compiler meta-data. --- - // Architecture-dependent register spill mask - uint32_t fp_spill_mask_; + // Access flags; low 16 bits are defined by spec. + uint32_t access_flags_; - // Total size in bytes of the frame - size_t frame_size_in_bytes_; + /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */ - // Garbage collection map of native PC offsets (quick) or dex PCs (portable) to reference bitmaps. - const uint8_t* gc_map_; + // Offset to the CodeItem. + uint32_t dex_code_item_offset_; - // Mapping from native pc to dex pc - const uint32_t* mapping_table_; + // Index into method_ids of the dex file associated with this method. + uint32_t dex_method_index_; - // Index into method_ids of the dex file associated with this method - uint32_t method_dex_index_; + /* End of dex file fields. */ - // For concrete virtual methods, this is the offset of the method in Class::vtable_. - // - // For abstract methods in an interface class, this is the offset of the method in - // "iftable_->Get(n)->GetMethodArray()". - // - // For static and direct methods this is the index in the direct methods table. + // Entry within a dispatch table for this method. For static/direct methods the index is into + // the declaringClass.directMethods, for virtual methods the vtable and for interface methods the + // ifTable. uint32_t method_index_; - // The target native method registered with this method - const void* native_method_; + // --- Quick compiler meta-data. --- + // TODO: merge and place in native heap, such as done with the code size. - // When a register is promoted into a register, the spill mask holds which registers hold dex - // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth - // is vmap_table_[N]. vmap_table_[0] holds the length of the table. - const uint16_t* vmap_table_; + // Bit map of spilled machine registers. + uint32_t quick_core_spill_mask_; + + // Bit map of spilled floating point machine registers. + uint32_t quick_fp_spill_mask_; + + // Fixed frame size for this method when executed. + uint32_t quick_frame_size_in_bytes_; + + // --- End of quick compiler meta-data. --- static Class* java_lang_reflect_ArtMethod_; diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 8ddaeb2d20..a5f743ba7c 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -33,63 +33,61 @@ namespace art { namespace mirror { -inline size_t Class::GetObjectSize() const { +inline uint32_t Class::GetObjectSize() { DCHECK(!IsVariableSize()) << " class=" << PrettyTypeOf(this); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), false); } -inline Class* Class::GetSuperClass() const { +inline Class* Class::GetSuperClass() { // Can only get super class for loaded classes (hack for when runtime is // initializing) DCHECK(IsLoaded() || !Runtime::Current()->IsStarted()) << IsLoaded(); - return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false); + return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false); } -inline ClassLoader* Class::GetClassLoader() const { - return GetFieldObject<ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false); +inline ClassLoader* Class::GetClassLoader() { + return GetFieldObject<ClassLoader>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false); } -inline DexCache* Class::GetDexCache() const { - return GetFieldObject<DexCache*>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), false); +inline DexCache* Class::GetDexCache() { + return GetFieldObject<DexCache>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), false); } -inline ObjectArray<ArtMethod>* Class::GetDirectMethods() const { +inline ObjectArray<ArtMethod>* Class::GetDirectMethods() { DCHECK(IsLoaded() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtMethod>*>( + return GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false); } inline void Class::SetDirectMethods(ObjectArray<ArtMethod>* new_direct_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(NULL == GetFieldObject<ObjectArray<ArtMethod>*>( + DCHECK(NULL == GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false)); DCHECK_NE(0, new_direct_methods->GetLength()); SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), new_direct_methods, false); } -inline ArtMethod* Class::GetDirectMethod(int32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtMethod* Class::GetDirectMethod(int32_t i) { return GetDirectMethods()->Get(i); } inline void Class::SetDirectMethod(uint32_t i, ArtMethod* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ObjectArray<ArtMethod>* direct_methods = - GetFieldObject<ObjectArray<ArtMethod>*>( + GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false); direct_methods->Set(i, f); } // Returns the number of static, private, and constructor methods. -inline size_t Class::NumDirectMethods() const { +inline uint32_t Class::NumDirectMethods() { return (GetDirectMethods() != NULL) ? GetDirectMethods()->GetLength() : 0; } -inline ObjectArray<ArtMethod>* Class::GetVirtualMethods() const { +inline ObjectArray<ArtMethod>* Class::GetVirtualMethods() { DCHECK(IsLoaded() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtMethod>*>( + return GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false); } @@ -101,18 +99,16 @@ inline void Class::SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods new_virtual_methods, false); } -inline size_t Class::NumVirtualMethods() const { +inline uint32_t Class::NumVirtualMethods() { return (GetVirtualMethods() != NULL) ? GetVirtualMethods()->GetLength() : 0; } -inline ArtMethod* Class::GetVirtualMethod(uint32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtMethod* Class::GetVirtualMethod(uint32_t i) { DCHECK(IsResolved() || IsErroneous()); return GetVirtualMethods()->Get(i); } -inline ArtMethod* Class::GetVirtualMethodDuringLinking(uint32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtMethod* Class::GetVirtualMethodDuringLinking(uint32_t i) { DCHECK(IsLoaded() || IsErroneous()); return GetVirtualMethods()->Get(i); } @@ -120,35 +116,34 @@ inline ArtMethod* Class::GetVirtualMethodDuringLinking(uint32_t i) const inline void Class::SetVirtualMethod(uint32_t i, ArtMethod* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ObjectArray<ArtMethod>* virtual_methods = - GetFieldObject<ObjectArray<ArtMethod>*>( + GetFieldObject<ObjectArray<ArtMethod> >( OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false); virtual_methods->Set(i, f); } -inline ObjectArray<ArtMethod>* Class::GetVTable() const { +inline ObjectArray<ArtMethod>* Class::GetVTable() { DCHECK(IsResolved() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false); + return GetFieldObject<ObjectArray<ArtMethod> >(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false); } -inline ObjectArray<ArtMethod>* Class::GetVTableDuringLinking() const { +inline ObjectArray<ArtMethod>* Class::GetVTableDuringLinking() { DCHECK(IsLoaded() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false); + return GetFieldObject<ObjectArray<ArtMethod> >(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false); } -inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false); } -inline ObjectArray<ArtMethod>* Class::GetImTable() const { - return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false); +inline ObjectArray<ArtMethod>* Class::GetImTable() { + return GetFieldObject<ObjectArray<ArtMethod> >(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false); } inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false); } -inline bool Class::Implements(const Class* klass) const { +inline bool Class::Implements(Class* klass) { DCHECK(klass != NULL); DCHECK(klass->IsInterface()) << PrettyClass(this); // All interfaces implemented directly and by our superclass, and @@ -183,13 +178,13 @@ inline bool Class::Implements(const Class* klass) const { // Don't forget about primitive types. // Object[] = int[] --> false // -inline bool Class::IsArrayAssignableFromArray(const Class* src) const { +inline bool Class::IsArrayAssignableFromArray(Class* src) { DCHECK(IsArrayClass()) << PrettyClass(this); DCHECK(src->IsArrayClass()) << PrettyClass(src); return GetComponentType()->IsAssignableFrom(src->GetComponentType()); } -inline bool Class::IsAssignableFromArray(const Class* src) const { +inline bool Class::IsAssignableFromArray(Class* src) { DCHECK(!IsInterface()) << PrettyClass(this); // handled first in IsAssignableFrom DCHECK(src->IsArrayClass()) << PrettyClass(src); if (!IsArrayClass()) { @@ -205,13 +200,13 @@ inline bool Class::IsAssignableFromArray(const Class* src) const { template <bool throw_on_failure, bool use_referrers_cache> inline bool Class::ResolvedFieldAccessTest(Class* access_to, ArtField* field, - uint32_t field_idx, const DexCache* dex_cache) { + uint32_t field_idx, DexCache* dex_cache) { DCHECK_EQ(use_referrers_cache, dex_cache == nullptr); if (UNLIKELY(!this->CanAccess(access_to))) { // The referrer class can't access the field's declaring class but may still be able // to access the field if the FieldId specifies an accessible subclass of the declaring // class rather than the declaring class itself. - const DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache; + DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache; uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_; // The referenced class has already been resolved with the field, get it from the dex cache. Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx); @@ -236,14 +231,14 @@ inline bool Class::ResolvedFieldAccessTest(Class* access_to, ArtField* field, template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type> inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method, - uint32_t method_idx, const DexCache* dex_cache) { + uint32_t method_idx, DexCache* dex_cache) { COMPILE_ASSERT(throw_on_failure || throw_invoke_type == kStatic, non_default_throw_invoke_type); DCHECK_EQ(use_referrers_cache, dex_cache == nullptr); if (UNLIKELY(!this->CanAccess(access_to))) { // The referrer class can't access the method's declaring class but may still be able // to access the method if the MethodId specifies an accessible subclass of the declaring // class rather than the declaring class itself. - const DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache; + DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache; uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_; // The referenced class has already been resolved with the method, get it from the dex cache. Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx); @@ -268,8 +263,8 @@ inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method, } inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field, - const DexCache& dex_cache, uint32_t field_idx) { - return ResolvedFieldAccessTest<false, false>(access_to, field, field_idx, &dex_cache); + DexCache* dex_cache, uint32_t field_idx) { + return ResolvedFieldAccessTest<false, false>(access_to, field, field_idx, dex_cache); } inline bool Class::CheckResolvedFieldAccess(Class* access_to, ArtField* field, @@ -278,8 +273,8 @@ inline bool Class::CheckResolvedFieldAccess(Class* access_to, ArtField* field, } inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method, - const DexCache& dex_cache, uint32_t method_idx) { - return ResolvedMethodAccessTest<false, false, kStatic>(access_to, method, method_idx, &dex_cache); + DexCache* dex_cache, uint32_t method_idx) { + return ResolvedMethodAccessTest<false, false, kStatic>(access_to, method, method_idx, dex_cache); } template <InvokeType throw_invoke_type> @@ -289,10 +284,10 @@ inline bool Class::CheckResolvedMethodAccess(Class* access_to, ArtMethod* method nullptr); } -inline bool Class::IsSubClass(const Class* klass) const { +inline bool Class::IsSubClass(Class* klass) { DCHECK(!IsInterface()) << PrettyClass(this); DCHECK(!IsArrayClass()) << PrettyClass(this); - const Class* current = this; + Class* current = this; do { if (current == klass) { return true; @@ -302,7 +297,7 @@ inline bool Class::IsSubClass(const Class* klass) const { return false; } -inline ArtMethod* Class::FindVirtualMethodForInterface(ArtMethod* method) const { +inline ArtMethod* Class::FindVirtualMethodForInterface(ArtMethod* method) { Class* declaring_class = method->GetDeclaringClass(); DCHECK(declaring_class != NULL) << PrettyClass(this); DCHECK(declaring_class->IsInterface()) << PrettyMethod(method); @@ -317,21 +312,19 @@ inline ArtMethod* Class::FindVirtualMethodForInterface(ArtMethod* method) const return NULL; } -inline ArtMethod* Class::FindVirtualMethodForVirtual(ArtMethod* method) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtMethod* Class::FindVirtualMethodForVirtual(ArtMethod* method) { DCHECK(!method->GetDeclaringClass()->IsInterface() || method->IsMiranda()); // The argument method may from a super class. // Use the index to a potentially overridden one for this instance's class. return GetVTable()->Get(method->GetMethodIndex()); } -inline ArtMethod* Class::FindVirtualMethodForSuper(ArtMethod* method) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtMethod* Class::FindVirtualMethodForSuper(ArtMethod* method) { DCHECK(!method->GetDeclaringClass()->IsInterface()); return GetSuperClass()->GetVTable()->Get(method->GetMethodIndex()); } -inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const { +inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* method) { if (method->IsDirect()) { return method; } @@ -341,11 +334,11 @@ inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* metho return FindVirtualMethodForVirtual(method); } -inline IfTable* Class::GetIfTable() const { - return GetFieldObject<IfTable*>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false); +inline IfTable* Class::GetIfTable() { + return GetFieldObject<IfTable>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false); } -inline int32_t Class::GetIfTableCount() const { +inline int32_t Class::GetIfTableCount() { IfTable* iftable = GetIfTable(); if (iftable == NULL) { return 0; @@ -357,59 +350,58 @@ inline void Class::SetIfTable(IfTable* new_iftable) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false); } -inline ObjectArray<ArtField>* Class::GetIFields() const { +inline ObjectArray<ArtField>* Class::GetIFields() { DCHECK(IsLoaded() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false); + return GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false); } inline void Class::SetIFields(ObjectArray<ArtField>* new_ifields) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(NULL == GetFieldObject<ObjectArray<ArtField>*>( + DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >( OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false)); SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false); } -inline ObjectArray<ArtField>* Class::GetSFields() const { +inline ObjectArray<ArtField>* Class::GetSFields() { DCHECK(IsLoaded() || IsErroneous()); - return GetFieldObject<ObjectArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false); + return GetFieldObject<ObjectArray<ArtField> >(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false); } inline void Class::SetSFields(ObjectArray<ArtField>* new_sfields) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(NULL == GetFieldObject<ObjectArray<ArtField>*>( + DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >( OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false)); SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false); } -inline size_t Class::NumStaticFields() const { +inline uint32_t Class::NumStaticFields() { return (GetSFields() != NULL) ? GetSFields()->GetLength() : 0; } -inline ArtField* Class::GetStaticField(uint32_t i) const // TODO: uint16_t +inline ArtField* Class::GetStaticField(uint32_t i) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetSFields()->Get(i); } inline void Class::SetStaticField(uint32_t i, ArtField* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ObjectArray<ArtField>* sfields= GetFieldObject<ObjectArray<ArtField>*>( + ObjectArray<ArtField>* sfields= GetFieldObject<ObjectArray<ArtField> >( OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false); sfields->Set(i, f); } -inline size_t Class::NumInstanceFields() const { +inline uint32_t Class::NumInstanceFields() { return (GetIFields() != NULL) ? GetIFields()->GetLength() : 0; } -inline ArtField* Class::GetInstanceField(uint32_t i) const // TODO: uint16_t - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +inline ArtField* Class::GetInstanceField(uint32_t i) { // TODO: uint16_t DCHECK_NE(NumInstanceFields(), 0U); return GetIFields()->Get(i); } inline void Class::SetInstanceField(uint32_t i, ArtField* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ObjectArray<ArtField>* ifields= GetFieldObject<ObjectArray<ArtField>*>( + ObjectArray<ArtField>* ifields= GetFieldObject<ObjectArray<ArtField> >( OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false); ifields->Set(i, f); } @@ -419,7 +411,7 @@ inline void Class::SetVerifyErrorClass(Class* klass) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false); } -inline uint32_t Class::GetAccessFlags() const { +inline uint32_t Class::GetAccessFlags() { // Check class is loaded or this is java.lang.String that has a // circularity issue during loading the names of its members DCHECK(IsLoaded() || IsErroneous() || @@ -429,8 +421,8 @@ inline uint32_t Class::GetAccessFlags() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false); } -inline String* Class::GetName() const { - return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false); +inline String* Class::GetName() { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false); } inline void Class::SetName(String* name) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index bd965fa462..8051c9b979 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -125,7 +125,7 @@ void Class::SetDexCache(DexCache* new_dex_cache) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache, false); } -void Class::SetClassSize(size_t new_class_size) { +void Class::SetClassSize(uint32_t new_class_size) { if (kIsDebugBuild && (new_class_size < GetClassSize())) { DumpClass(LOG(ERROR), kDumpClassFullDetail); CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); @@ -177,7 +177,7 @@ String* Class::ComputeName() { return name; } -void Class::DumpClass(std::ostream& os, int flags) const { +void Class::DumpClass(std::ostream& os, int flags) { if ((flags & kDumpClassFullDetail) == 0) { os << PrettyClass(this); if ((flags & kDumpClassClassLoader) != 0) { @@ -281,9 +281,9 @@ bool Class::IsInSamePackage(const StringPiece& descriptor1, const StringPiece& d } } -bool Class::IsInSamePackage(const Class* that) const { - const Class* klass1 = this; - const Class* klass2 = that; +bool Class::IsInSamePackage(Class* that) { + Class* klass1 = this; + Class* klass2 = that; if (klass1 == klass2) { return true; } @@ -307,7 +307,7 @@ bool Class::IsInSamePackage(const Class* that) const { ClassHelper(klass2).GetDescriptor()); } -bool Class::IsClassClass() const { +bool Class::IsClassClass() { Class* java_lang_Class = GetClass()->GetClass(); return this == java_lang_Class; } @@ -316,17 +316,17 @@ bool Class::IsStringClass() const { return this == String::GetJavaLangString(); } -bool Class::IsThrowableClass() const { +bool Class::IsThrowableClass() { return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this); } -bool Class::IsArtFieldClass() const { +bool Class::IsArtFieldClass() { Class* java_lang_Class = GetClass(); Class* java_lang_reflect_ArtField = java_lang_Class->GetInstanceField(0)->GetClass(); return this == java_lang_reflect_ArtField; } -bool Class::IsArtMethodClass() const { +bool Class::IsArtMethodClass() { return this == ArtMethod::GetJavaLangReflectArtMethod(); } @@ -334,7 +334,7 @@ void Class::SetClassLoader(ClassLoader* new_class_loader) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false); } -ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) const { +ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) { // Check the current class before checking the interfaces. ArtMethod* method = FindDeclaredVirtualMethod(name, signature); if (method != NULL) { @@ -352,7 +352,7 @@ ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& return NULL; } -ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { +ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) { // Check the current class before checking the interfaces. ArtMethod* method = FindDeclaredVirtualMethod(dex_cache, dex_method_idx); if (method != NULL) { @@ -370,7 +370,7 @@ ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_me return NULL; } -ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const { +ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) { MethodHelper mh; for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); @@ -382,7 +382,7 @@ ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const String return NULL; } -ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const { +ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) { MethodHelper mh; for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); @@ -394,7 +394,7 @@ ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signat return NULL; } -ArtMethod* Class::FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { +ArtMethod* Class::FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) { if (GetDexCache() == dex_cache) { for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); @@ -406,8 +406,8 @@ ArtMethod* Class::FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t d return NULL; } -ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& signature) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& signature) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature); if (method != NULL) { return method; @@ -416,8 +416,8 @@ ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& s return NULL; } -ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature); if (method != NULL) { return method; @@ -426,8 +426,8 @@ ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& sig return NULL; } -ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx); if (method != NULL) { return method; @@ -436,7 +436,7 @@ ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_metho return NULL; } -ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const { +ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) { MethodHelper mh; for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); @@ -449,7 +449,7 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Strin } ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, - const Signature& signature) const { + const Signature& signature) { MethodHelper mh; for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); @@ -461,7 +461,7 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, return NULL; } -ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { +ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) { if (GetDexCache() == dex_cache) { for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); @@ -473,8 +473,8 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t return NULL; } -ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& signature) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature); if (method != NULL) { return method; @@ -483,8 +483,8 @@ ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& return NULL; } -ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature); if (method != NULL) { return method; @@ -493,8 +493,8 @@ ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& si return NULL; } -ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { - for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { +ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) { + for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx); if (method != NULL) { return method; @@ -503,7 +503,7 @@ ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_meth return NULL; } -ArtMethod* Class::FindClassInitializer() const { +ArtMethod* Class::FindClassInitializer() { for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); if (method->IsConstructor() && method->IsStatic()) { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index a692381f92..cbec4764df 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -120,7 +120,7 @@ class MANAGED Class : public Object { kStatusMax = 10, }; - Status GetStatus() const { + Status GetStatus() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_EQ(sizeof(Status), sizeof(uint32_t)); return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), true)); } @@ -132,107 +132,107 @@ class MANAGED Class : public Object { } // Returns true if the class has failed to link. - bool IsErroneous() const { + bool IsErroneous() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() == kStatusError; } // Returns true if the class has been loaded. - bool IsIdxLoaded() const { + bool IsIdxLoaded() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusIdx; } // Returns true if the class has been loaded. - bool IsLoaded() const { + bool IsLoaded() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusLoaded; } // Returns true if the class has been linked. - bool IsResolved() const { + bool IsResolved() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusResolved; } // Returns true if the class was compile-time verified. - bool IsCompileTimeVerified() const { + bool IsCompileTimeVerified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusRetryVerificationAtRuntime; } // Returns true if the class has been verified. - bool IsVerified() const { + bool IsVerified() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusVerified; } // Returns true if the class is initializing. - bool IsInitializing() const { + bool IsInitializing() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() >= kStatusInitializing; } // Returns true if the class is initialized. - bool IsInitialized() const { + bool IsInitialized() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStatus() == kStatusInitialized; } - uint32_t GetAccessFlags() const; + uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetAccessFlags(uint32_t new_access_flags) { + void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false); } // Returns true if the class is an interface. - bool IsInterface() const { + bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccInterface) != 0; } // Returns true if the class is declared public. - bool IsPublic() const { + bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccPublic) != 0; } // Returns true if the class is declared final. - bool IsFinal() const { + bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccFinal) != 0; } - bool IsFinalizable() const { + bool IsFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccClassIsFinalizable) != 0; } - void SetFinalizable() { + void SetFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false); SetAccessFlags(flags | kAccClassIsFinalizable); } // Returns true if the class is abstract. - bool IsAbstract() const { + bool IsAbstract() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccAbstract) != 0; } // Returns true if the class is an annotation. - bool IsAnnotation() const { + bool IsAnnotation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccAnnotation) != 0; } // Returns true if the class is synthetic. - bool IsSynthetic() const { + bool IsSynthetic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccSynthetic) != 0; } - bool IsReferenceClass() const { + bool IsReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccClassIsReference) != 0; } - bool IsWeakReferenceClass() const { + bool IsWeakReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccClassIsWeakReference) != 0; } - bool IsSoftReferenceClass() const { + bool IsSoftReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccReferenceFlagsMask) == kAccClassIsReference; } - bool IsFinalizerReferenceClass() const { + bool IsFinalizerReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccClassIsFinalizerReference) != 0; } - bool IsPhantomReferenceClass() const { + bool IsPhantomReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccClassIsPhantomReference) != 0; } @@ -241,7 +241,7 @@ class MANAGED Class : public Object { // For array classes, where all the classes are final due to there being no sub-classes, an // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other // types as the component is final. - bool CannotBeAssignedFromOtherTypes() const { + bool CannotBeAssignedFromOtherTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (!IsArrayClass()) { return IsFinal(); } else { @@ -254,12 +254,12 @@ class MANAGED Class : public Object { } } - String* GetName() const; // Returns the cached name. + String* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the cached name. void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sets the cached name. // Computes the name, then sets the cached value. String* ComputeName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsProxyClass() const { + bool IsProxyClass() { // Read access flags without using getter as whether something is a proxy can be check in // any loaded state // TODO: switch to a check if the super class is java.lang.reflect.Proxy? @@ -267,91 +267,91 @@ class MANAGED Class : public Object { return (access_flags & kAccClassIsProxy) != 0; } - Primitive::Type GetPrimitiveType() const { + Primitive::Type GetPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t)); return static_cast<Primitive::Type>( GetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), false)); } - void SetPrimitiveType(Primitive::Type new_type) { + void SetPrimitiveType(Primitive::Type new_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t)); SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false); } // Returns true if the class is a primitive type. - bool IsPrimitive() const { + bool IsPrimitive() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() != Primitive::kPrimNot; } - bool IsPrimitiveBoolean() const { + bool IsPrimitiveBoolean() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimBoolean; } - bool IsPrimitiveByte() const { + bool IsPrimitiveByte() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimByte; } - bool IsPrimitiveChar() const { + bool IsPrimitiveChar() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimChar; } - bool IsPrimitiveShort() const { + bool IsPrimitiveShort() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimShort; } - bool IsPrimitiveInt() const { + bool IsPrimitiveInt() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimInt; } - bool IsPrimitiveLong() const { + bool IsPrimitiveLong() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimLong; } - bool IsPrimitiveFloat() const { + bool IsPrimitiveFloat() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimFloat; } - bool IsPrimitiveDouble() const { + bool IsPrimitiveDouble() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimDouble; } - bool IsPrimitiveVoid() const { + bool IsPrimitiveVoid() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetPrimitiveType() == Primitive::kPrimVoid; } - bool IsPrimitiveArray() const { + bool IsPrimitiveArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return IsArrayClass() && GetComponentType()->IsPrimitive(); } // Depth of class from java.lang.Object - size_t Depth() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - size_t depth = 0; + uint32_t Depth() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t depth = 0; for (Class* klass = this; klass->GetSuperClass() != NULL; klass = klass->GetSuperClass()) { depth++; } return depth; } - bool IsArrayClass() const { + bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetComponentType() != NULL; } - bool IsClassClass() const; + bool IsClassClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsStringClass() const; - bool IsThrowableClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsThrowableClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArtFieldClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsArtFieldClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArtMethodClass() const; + bool IsArtMethodClass(); static MemberOffset ComponentTypeOffset() { return OFFSET_OF_OBJECT_MEMBER(Class, component_type_); } - Class* GetComponentType() const { - return GetFieldObject<Class*>(ComponentTypeOffset(), false); + Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<Class>(ComponentTypeOffset(), false); } void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -360,18 +360,18 @@ class MANAGED Class : public Object { SetFieldObject(ComponentTypeOffset(), new_component_type, false); } - size_t GetComponentSize() const { + size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return Primitive::ComponentSize(GetComponentType()->GetPrimitiveType()); } - bool IsObjectClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool IsObjectClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return !IsPrimitive() && GetSuperClass() == NULL; } - bool IsInstantiable() const { + bool IsInstantiable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (!IsPrimitive() && !IsInterface() && !IsAbstract()) || ((IsAbstract()) && IsArrayClass()); } - bool IsObjectArrayClass() const { + bool IsObjectArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetComponentType() != NULL && !GetComponentType()->IsPrimitive(); } @@ -385,48 +385,44 @@ class MANAGED Class : public Object { Object* AllocNonMovableObject(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsVariableSize() const { + bool IsVariableSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Classes and arrays vary in size, and so the object_size_ field cannot // be used to get their instance size return IsClassClass() || IsArrayClass(); } - size_t SizeOf() const { - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); + uint32_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false); } - size_t GetClassSize() const { - DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); + uint32_t GetClassSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false); } - void SetClassSize(size_t new_class_size) + void SetClassSize(uint32_t new_class_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t GetObjectSize() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t GetObjectSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetObjectSize(size_t new_object_size) { + void SetObjectSize(uint32_t new_object_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(!IsVariableSize()); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false); } // Returns true if this class is in the same packages as that class. - bool IsInSamePackage(const Class* that) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsInSamePackage(Class* that) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static bool IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2); // Returns true if this class can access that class. - bool CanAccess(Class* that) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool CanAccess(Class* that) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return that->IsPublic() || this->IsInSamePackage(that); } // Can this class access a member in the provided class with the provided member access flags? // Note that access to the class isn't checked in case the declaring class is protected and the // method has been exposed by a public sub-class - bool CanAccessMember(Class* access_to, uint32_t member_flags) const + bool CanAccessMember(Class* access_to, uint32_t member_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Classes can access all of their own members if (this == access_to) { @@ -454,7 +450,7 @@ class MANAGED Class : public Object { // Note that access to field's class is checked and this may require looking up the class // referenced by the FieldId in the DexFile in case the declaring class is inaccessible. bool CanAccessResolvedField(Class* access_to, ArtField* field, - const DexCache& dex_cache, uint32_t field_idx) + DexCache* dex_cache, uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool CheckResolvedFieldAccess(Class* access_to, ArtField* field, uint32_t field_idx) @@ -464,22 +460,21 @@ class MANAGED Class : public Object { // Note that access to methods's class is checked and this may require looking up the class // referenced by the MethodId in the DexFile in case the declaring class is inaccessible. bool CanAccessResolvedMethod(Class* access_to, ArtMethod* resolved_method, - const DexCache& dex_cache, uint32_t method_idx) + DexCache* dex_cache, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template <InvokeType throw_invoke_type> bool CheckResolvedMethodAccess(Class* access_to, ArtMethod* resolved_method, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsSubClass(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsSubClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Can src be assigned to this class? For example, String can be assigned to Object (by an // upcast), however, an Object cannot be assigned to a String as a potentially exception throwing // downcast would be necessary. Similarly for interfaces, a class that implements (or an interface // that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign // to themselves. Classes for primitive types may not assign to each other. - inline bool IsAssignableFrom(const Class* src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + inline bool IsAssignableFrom(Class* src) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(src != NULL); if (this == src) { // Can always assign to things of the same type. @@ -496,18 +491,18 @@ class MANAGED Class : public Object { } } - Class* GetSuperClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + Class* GetSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetSuperClass(Class *new_super_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // super class is assigned once, except during class linker initialization - Class* old_super_class = GetFieldObject<Class*>( - OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false); - DCHECK(old_super_class == NULL || old_super_class == new_super_class); - DCHECK(new_super_class != NULL); + // Super class is assigned once, except during class linker initialization. + Class* old_super_class = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), + false); + DCHECK(old_super_class == nullptr || old_super_class == new_super_class); + DCHECK(new_super_class != nullptr); SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false); } - bool HasSuperClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool HasSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetSuperClass() != NULL; } @@ -515,7 +510,7 @@ class MANAGED Class : public Object { return MemberOffset(OFFSETOF_MEMBER(Class, super_class_)); } - ClassLoader* GetClassLoader() const; + ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetClassLoader(ClassLoader* new_cl) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -529,46 +524,43 @@ class MANAGED Class : public Object { kDumpClassInitialized = (1 << 2), }; - void DumpClass(std::ostream& os, int flags) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void DumpClass(std::ostream& os, int flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - DexCache* GetDexCache() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDexCache(DexCache* new_dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<ArtMethod>* GetDirectMethods() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ObjectArray<ArtMethod>* GetDirectMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDirectMethods(ObjectArray<ArtMethod>* new_direct_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* GetDirectMethod(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* GetDirectMethod(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDirectMethod(uint32_t i, ArtMethod* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the number of static, private, and constructor methods. - size_t NumDirectMethods() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t NumDirectMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<ArtMethod>* GetVirtualMethods() const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ObjectArray<ArtMethod>* GetVirtualMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the number of non-inherited virtual methods. - size_t NumVirtualMethods() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t NumVirtualMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* GetVirtualMethod(uint32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* GetVirtualMethod(uint32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* GetVirtualMethodDuringLinking(uint32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* GetVirtualMethodDuringLinking(uint32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetVirtualMethod(uint32_t i, ArtMethod* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<ArtMethod>* GetVTable() const; + ObjectArray<ArtMethod>* GetVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<ArtMethod>* GetVTableDuringLinking() const; + ObjectArray<ArtMethod>* GetVTableDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetVTable(ObjectArray<ArtMethod>* new_vtable) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -577,7 +569,7 @@ class MANAGED Class : public Object { return OFFSET_OF_OBJECT_MEMBER(Class, vtable_); } - ObjectArray<ArtMethod>* GetImTable() const; + ObjectArray<ArtMethod>* GetImTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetImTable(ObjectArray<ArtMethod>* new_imtable) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -588,105 +580,102 @@ class MANAGED Class : public Object { // Given a method implemented by this class but potentially from a super class, return the // specific implementation method for this class. - ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) const + ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Given a method implemented by this class' super class, return the specific implementation // method for this class. - ArtMethod* FindVirtualMethodForSuper(ArtMethod* method) const + ArtMethod* FindVirtualMethodForSuper(ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Given a method implemented by this class, but potentially from a // super class or interface, return the specific implementation // method for this class. - ArtMethod* FindVirtualMethodForInterface(ArtMethod* method) const + ArtMethod* FindVirtualMethodForInterface(ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE; - ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const + ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature) const + ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const StringPiece& name, const Signature& signature) const + ArtMethod* FindDirectMethod(const StringPiece& name, const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const StringPiece& name, const Signature& signature) const + ArtMethod* FindVirtualMethod(const StringPiece& name, const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindClassInitializer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* FindClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t GetIfTableCount() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int32_t GetIfTableCount() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - IfTable* GetIfTable() const; + IfTable* GetIfTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetIfTable(IfTable* new_iftable) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get instance fields of the class (See also GetSFields). - ObjectArray<ArtField>* GetIFields() const; + ObjectArray<ArtField>* GetIFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetIFields(ObjectArray<ArtField>* new_ifields) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t NumInstanceFields() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t NumInstanceFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtField* GetInstanceField(uint32_t i) const // TODO: uint16_t + ArtField* GetInstanceField(uint32_t i) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetInstanceField(uint32_t i, ArtField* f) // TODO: uint16_t SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the number of instance fields containing reference types. - size_t NumReferenceInstanceFields() const { + uint32_t NumReferenceInstanceFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsResolved() || IsErroneous()); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false); } - size_t NumReferenceInstanceFieldsDuringLinking() const { + uint32_t NumReferenceInstanceFieldsDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsLoaded() || IsErroneous()); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false); } - void SetNumReferenceInstanceFields(size_t new_num) { - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); + void SetNumReferenceInstanceFields(uint32_t new_num) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num, false); } - uint32_t GetReferenceInstanceOffsets() const { + uint32_t GetReferenceInstanceOffsets() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsResolved() || IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false); } @@ -700,39 +689,39 @@ class MANAGED Class : public Object { } // Returns the number of static fields containing reference types. - size_t NumReferenceStaticFields() const { + uint32_t NumReferenceStaticFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsResolved() || IsErroneous()); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false); } - size_t NumReferenceStaticFieldsDuringLinking() const { + uint32_t NumReferenceStaticFieldsDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsLoaded() || IsErroneous()); - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false); } - void SetNumReferenceStaticFields(size_t new_num) { - DCHECK_EQ(sizeof(size_t), sizeof(int32_t)); + void SetNumReferenceStaticFields(uint32_t new_num) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false); } // Gets the static fields of the class. - ObjectArray<ArtField>* GetSFields() const; + ObjectArray<ArtField>* GetSFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetSFields(ObjectArray<ArtField>* new_sfields) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t NumStaticFields() const; + uint32_t NumStaticFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtField* GetStaticField(uint32_t i) const; // TODO: uint16_t + // TODO: uint16_t + ArtField* GetStaticField(uint32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetStaticField(uint32_t i, ArtField* f); // TODO: uint16_t + // TODO: uint16_t + void SetStaticField(uint32_t i, ArtField* f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint32_t GetReferenceStaticOffsets() const { + uint32_t GetReferenceStaticOffsets() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_), false); } - void SetReferenceStaticOffsets(uint32_t new_reference_offsets); + void SetReferenceStaticOffsets(uint32_t new_reference_offsets) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find a static or instance field using the JLS resolution order ArtField* FindField(const StringPiece& name, const StringPiece& type) @@ -768,33 +757,33 @@ class MANAGED Class : public Object { ArtField* FindDeclaredStaticField(const DexCache* dex_cache, uint32_t dex_field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - pid_t GetClinitThreadId() const { + pid_t GetClinitThreadId() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(IsIdxLoaded() || IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false); } - void SetClinitThreadId(pid_t new_clinit_thread_id) { + void SetClinitThreadId(pid_t new_clinit_thread_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id, false); } - Class* GetVerifyErrorClass() const { + Class* GetVerifyErrorClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // DCHECK(IsErroneous()); - return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); + return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); } - uint16_t GetDexClassDefIndex() const { + uint16_t GetDexClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), false); } - void SetDexClassDefIndex(uint16_t class_def_idx) { + void SetDexClassDefIndex(uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false); } - uint16_t GetDexTypeIndex() const { + uint16_t GetDexTypeIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false); } - void SetDexTypeIndex(uint16_t type_idx) { + void SetDexTypeIndex(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false); } @@ -817,35 +806,32 @@ class MANAGED Class : public Object { template <bool throw_on_failure, bool use_referrers_cache> bool ResolvedFieldAccessTest(Class* access_to, ArtField* field, - uint32_t field_idx, const DexCache* dex_cache) + uint32_t field_idx, DexCache* dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type> bool ResolvedMethodAccessTest(Class* access_to, ArtMethod* resolved_method, - uint32_t method_idx, const DexCache* dex_cache) + uint32_t method_idx, DexCache* dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool Implements(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArrayAssignableFromArray(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsAssignableFromArray(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool Implements(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsArrayAssignableFromArray(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsAssignableFromArray(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void CheckObjectAlloc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // defining class loader, or NULL for the "bootstrap" system loader - ClassLoader* class_loader_; + HeapReference<ClassLoader> class_loader_; // For array classes, the component class object for instanceof/checkcast // (for String[][][], this will be String[][]). NULL for non-array classes. - Class* component_type_; + HeapReference<Class> component_type_; // DexCache of resolved constant pool entries (will be NULL for classes generated by the // runtime such as arrays and primitive classes). - DexCache* dex_cache_; + HeapReference<DexCache> dex_cache_; // static, private, and <init> methods - ObjectArray<ArtMethod>* direct_methods_; + HeapReference<ObjectArray<ArtMethod> > direct_methods_; // instance fields // @@ -857,7 +843,7 @@ class MANAGED Class : public Object { // All instance fields that refer to objects are guaranteed to be at // the beginning of the field list. num_reference_instance_fields_ // specifies the number of reference fields. - ObjectArray<ArtField>* ifields_; + HeapReference<ObjectArray<ArtField> > ifields_; // The interface table (iftable_) contains pairs of a interface class and an array of the // interface methods. There is one pair per interface supported by this class. That means one @@ -870,38 +856,38 @@ class MANAGED Class : public Object { // // For every interface a concrete class implements, we create an array of the concrete vtable_ // methods for the methods in the interface. - IfTable* iftable_; + HeapReference<IfTable> iftable_; // Interface method table (imt), for quick "invoke-interface". - ObjectArray<ArtMethod>* imtable_; + HeapReference<ObjectArray<ArtMethod> > imtable_; - // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName - String* name_; + // Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName + HeapReference<String> name_; // Static fields - ObjectArray<ArtField>* sfields_; + HeapReference<ObjectArray<ArtField>> sfields_; // The superclass, or NULL if this is java.lang.Object, an interface or primitive type. - Class* super_class_; + HeapReference<Class> super_class_; // If class verify fails, we must return same error on subsequent tries. - Class* verify_error_class_; + HeapReference<Class> verify_error_class_; // Virtual methods defined in this class; invoked through vtable. - ObjectArray<ArtMethod>* virtual_methods_; + HeapReference<ObjectArray<ArtMethod> > virtual_methods_; // Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is // copied in, and virtual methods from our class either replace those from the super or are // appended. For abstract classes, methods may be created in the vtable that aren't in // virtual_ methods_ for miranda methods. - ObjectArray<ArtMethod>* vtable_; + HeapReference<ObjectArray<ArtMethod> > vtable_; // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. - size_t class_size_; + uint32_t class_size_; // Tid used to check for recursive <clinit> invocation. pid_t clinit_thread_id_; @@ -915,15 +901,15 @@ class MANAGED Class : public Object { int32_t dex_type_idx_; // Number of instance fields that are object refs. - size_t num_reference_instance_fields_; + uint32_t num_reference_instance_fields_; // Number of static fields that are object refs, - size_t num_reference_static_fields_; + uint32_t num_reference_static_fields_; // Total object size; used when allocating storage on gc heap. // (For interfaces and abstract classes this will be zero.) // See also class_size_. - size_t object_size_; + uint32_t object_size_; // Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes. Primitive::Type primitive_type_; diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h index 415cb67c6c..69accf5834 100644 --- a/runtime/mirror/class_loader.h +++ b/runtime/mirror/class_loader.h @@ -32,9 +32,9 @@ namespace mirror { class MANAGED ClassLoader : public Object { private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". - Object* packages_; - ClassLoader* parent_; - Object* proxyCache_; + HeapReference<Object> packages_; + HeapReference<ClassLoader> parent_; + HeapReference<Object> proxyCache_; friend struct art::ClassLoaderOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader); diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index da26be59b9..f59c3a22a1 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -22,7 +22,7 @@ namespace art { namespace mirror { -inline ArtMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const +inline ArtMethod* DexCache::GetResolvedMethod(uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ArtMethod* method = GetResolvedMethods()->Get(method_idx); // Hide resolution trampoline methods from the caller diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index a5fe598f5c..99529f09b4 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -52,8 +52,8 @@ class MANAGED DexCache : public Object { void Fixup(ArtMethod* trampoline) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - String* GetLocation() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), false); + String* GetLocation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), false); } static MemberOffset StringsOffset() { @@ -68,24 +68,23 @@ class MANAGED DexCache : public Object { return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_methods_); } - size_t NumStrings() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + size_t NumStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStrings()->GetLength(); } - size_t NumResolvedTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + size_t NumResolvedTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetResolvedTypes()->GetLength(); } - size_t NumResolvedMethods() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + size_t NumResolvedMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetResolvedMethods()->GetLength(); } - size_t NumResolvedFields() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + size_t NumResolvedFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetResolvedFields()->GetLength(); } - String* GetResolvedString(uint32_t string_idx) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + String* GetResolvedString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetStrings()->Get(string_idx); } @@ -94,8 +93,7 @@ class MANAGED DexCache : public Object { GetStrings()->Set(string_idx, resolved); } - Class* GetResolvedType(uint32_t type_idx) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Class* GetResolvedType(uint32_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetResolvedTypes()->Get(type_idx); } @@ -104,16 +102,14 @@ class MANAGED DexCache : public Object { GetResolvedTypes()->Set(type_idx, resolved); } - ArtMethod* GetResolvedMethod(uint32_t method_idx) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* GetResolvedMethod(uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetResolvedMethod(uint32_t method_idx, ArtMethod* resolved) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { GetResolvedMethods()->Set(method_idx, resolved); } - ArtField* GetResolvedField(uint32_t field_idx) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ArtField* GetResolvedField(uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetResolvedFields()->Get(field_idx); } @@ -122,28 +118,24 @@ class MANAGED DexCache : public Object { GetResolvedFields()->Set(field_idx, resolved); } - ObjectArray<String>* GetStrings() const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetFieldObject< ObjectArray<String>* >(StringsOffset(), false); + ObjectArray<String>* GetStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject< ObjectArray<String> >(StringsOffset(), false); } - ObjectArray<Class>* GetResolvedTypes() const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetFieldObject< ObjectArray<Class>* >( + ObjectArray<Class>* GetResolvedTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<ObjectArray<Class> >( OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), false); } - ObjectArray<ArtMethod>* GetResolvedMethods() const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetFieldObject< ObjectArray<ArtMethod>* >(ResolvedMethodsOffset(), false); + ObjectArray<ArtMethod>* GetResolvedMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject< ObjectArray<ArtMethod> >(ResolvedMethodsOffset(), false); } - ObjectArray<ArtField>* GetResolvedFields() const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetFieldObject< ObjectArray<ArtField>* >(ResolvedFieldsOffset(), false); + ObjectArray<ArtField>* GetResolvedFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<ObjectArray<ArtField> >(ResolvedFieldsOffset(), false); } - const DexFile* GetDexFile() const { + const DexFile* GetDexFile() { return GetFieldPtr<const DexFile*>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), false); } @@ -152,13 +144,13 @@ class MANAGED DexCache : public Object { } private: - Object* dex_; - String* location_; - ObjectArray<ArtField>* resolved_fields_; - ObjectArray<ArtMethod>* resolved_methods_; - ObjectArray<Class>* resolved_types_; - ObjectArray<String>* strings_; - uint32_t dex_file_; + HeapReference<Object> dex_; + HeapReference<String> location_; + HeapReference<ObjectArray<ArtField> > resolved_fields_; + HeapReference<ObjectArray<ArtMethod> > resolved_methods_; + HeapReference<ObjectArray<Class> > resolved_types_; + HeapReference<ObjectArray<String> > strings_; + uint64_t dex_file_; friend struct art::DexCacheOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache); diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h index 421893d3db..be83d034b8 100644 --- a/runtime/mirror/iftable.h +++ b/runtime/mirror/iftable.h @@ -24,7 +24,7 @@ namespace mirror { class MANAGED IfTable : public ObjectArray<Object> { public: - Class* GetInterface(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Class* GetInterface(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Class* interface = Get((i * kMax) + kInterface)->AsClass(); DCHECK(interface != NULL); return interface; @@ -32,15 +32,14 @@ class MANAGED IfTable : public ObjectArray<Object> { void SetInterface(int32_t i, Class* interface) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ObjectArray<ArtMethod>* GetMethodArray(int32_t i) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ObjectArray<ArtMethod>* GetMethodArray(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ObjectArray<ArtMethod>* method_array = down_cast<ObjectArray<ArtMethod>*>(Get((i * kMax) + kMethodArray)); DCHECK(method_array != NULL); return method_array; } - size_t GetMethodArrayCount(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + size_t GetMethodArrayCount(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ObjectArray<ArtMethod>* method_array = down_cast<ObjectArray<ArtMethod>*>(Get((i * kMax) + kMethodArray)); if (method_array == NULL) { @@ -56,7 +55,7 @@ class MANAGED IfTable : public ObjectArray<Object> { Set((i * kMax) + kMethodArray, new_ma); } - size_t Count() const { + size_t Count() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetLength() / kMax; } diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 9161bc578c..afa411204b 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -32,19 +32,18 @@ namespace art { namespace mirror { -inline Class* Object::GetClass() const { - return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false); +inline Class* Object::GetClass() { + return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false); } inline void Object::SetClass(Class* new_klass) { - // new_klass may be NULL prior to class linker initialization - // We don't mark the card since the class is guaranteed to be referenced from another location. - // Proxy classes are held live by the class loader, and other classes are roots of the class - // linker. - SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false, false); + // new_klass may be NULL prior to class linker initialization. + // We don't mark the card as this occurs as part of object allocation. Not all objects have + // backing cards, such as large objects. + SetFieldObjectWithoutWriteBarrier(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false, false); } -inline LockWord Object::GetLockWord() const { +inline LockWord Object::GetLockWord() { return LockWord(GetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), true)); } @@ -85,19 +84,19 @@ inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) { Monitor::Wait(self, this, ms, ns, true, kTimedWaiting); } -inline bool Object::VerifierInstanceOf(const Class* klass) const { +inline bool Object::VerifierInstanceOf(Class* klass) { DCHECK(klass != NULL); DCHECK(GetClass() != NULL); return klass->IsInterface() || InstanceOf(klass); } -inline bool Object::InstanceOf(const Class* klass) const { +inline bool Object::InstanceOf(Class* klass) { DCHECK(klass != NULL); DCHECK(GetClass() != NULL); return klass->IsAssignableFrom(GetClass()); } -inline bool Object::IsClass() const { +inline bool Object::IsClass() { Class* java_lang_Class = GetClass()->GetClass(); return GetClass() == java_lang_Class; } @@ -107,12 +106,7 @@ inline Class* Object::AsClass() { return down_cast<Class*>(this); } -inline const Class* Object::AsClass() const { - DCHECK(IsClass()); - return down_cast<const Class*>(this); -} - -inline bool Object::IsObjectArray() const { +inline bool Object::IsObjectArray() { return IsArrayInstance() && !GetClass()->GetComponentType()->IsPrimitive(); } @@ -122,17 +116,11 @@ inline ObjectArray<T>* Object::AsObjectArray() { return down_cast<ObjectArray<T>*>(this); } -template<class T> -inline const ObjectArray<T>* Object::AsObjectArray() const { - DCHECK(IsObjectArray()); - return down_cast<const ObjectArray<T>*>(this); -} - -inline bool Object::IsArrayInstance() const { +inline bool Object::IsArrayInstance() { return GetClass()->IsArrayClass(); } -inline bool Object::IsArtField() const { +inline bool Object::IsArtField() { return GetClass()->IsArtFieldClass(); } @@ -141,12 +129,7 @@ inline ArtField* Object::AsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_ return down_cast<ArtField*>(this); } -inline const ArtField* Object::AsArtField() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(IsArtField()); - return down_cast<const ArtField*>(this); -} - -inline bool Object::IsArtMethod() const { +inline bool Object::IsArtMethod() { return GetClass()->IsArtMethodClass(); } @@ -155,12 +138,7 @@ inline ArtMethod* Object::AsArtMethod() { return down_cast<ArtMethod*>(this); } -inline const ArtMethod* Object::AsArtMethod() const { - DCHECK(IsArtMethod()); - return down_cast<const ArtMethod*>(this); -} - -inline bool Object::IsReferenceInstance() const { +inline bool Object::IsReferenceInstance() { return GetClass()->IsReferenceClass(); } @@ -169,11 +147,6 @@ inline Array* Object::AsArray() { return down_cast<Array*>(this); } -inline const Array* Object::AsArray() const { - DCHECK(IsArrayInstance()); - return down_cast<const Array*>(this); -} - inline BooleanArray* Object::AsBooleanArray() { DCHECK(GetClass()->IsArrayClass()); DCHECK(GetClass()->GetComponentType()->IsPrimitiveBoolean()); @@ -186,6 +159,13 @@ inline ByteArray* Object::AsByteArray() { return down_cast<ByteArray*>(this); } +inline ByteArray* Object::AsByteSizedArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveByte() || + GetClass()->GetComponentType()->IsPrimitiveBoolean()); + return down_cast<ByteArray*>(this); +} + inline CharArray* Object::AsCharArray() { DCHECK(GetClass()->IsArrayClass()); DCHECK(GetClass()->GetComponentType()->IsPrimitiveChar()); @@ -198,6 +178,13 @@ inline ShortArray* Object::AsShortArray() { return down_cast<ShortArray*>(this); } +inline ShortArray* Object::AsShortSizedArray() { + DCHECK(GetClass()->IsArrayClass()); + DCHECK(GetClass()->GetComponentType()->IsPrimitiveShort() || + GetClass()->GetComponentType()->IsPrimitiveChar()); + return down_cast<ShortArray*>(this); +} + inline IntArray* Object::AsIntArray() { DCHECK(GetClass()->IsArrayClass()); DCHECK(GetClass()->GetComponentType()->IsPrimitiveInt() || @@ -222,23 +209,23 @@ inline Throwable* Object::AsThrowable() { return down_cast<Throwable*>(this); } -inline bool Object::IsWeakReferenceInstance() const { +inline bool Object::IsWeakReferenceInstance() { return GetClass()->IsWeakReferenceClass(); } -inline bool Object::IsSoftReferenceInstance() const { +inline bool Object::IsSoftReferenceInstance() { return GetClass()->IsSoftReferenceClass(); } -inline bool Object::IsFinalizerReferenceInstance() const { +inline bool Object::IsFinalizerReferenceInstance() { return GetClass()->IsFinalizerReferenceClass(); } -inline bool Object::IsPhantomReferenceInstance() const { +inline bool Object::IsPhantomReferenceInstance() { return GetClass()->IsPhantomReferenceClass(); } -inline size_t Object::SizeOf() const { +inline size_t Object::SizeOf() { size_t result; if (IsArrayInstance()) { result = AsArray()->SizeOf(); @@ -253,13 +240,13 @@ inline size_t Object::SizeOf() const { return result; } -inline uint32_t Object::GetField32(MemberOffset field_offset, bool is_volatile) const { +inline uint32_t Object::GetField32(MemberOffset field_offset, bool is_volatile) { VerifyObject(this); const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value(); const int32_t* word_addr = reinterpret_cast<const int32_t*>(raw_addr); if (UNLIKELY(is_volatile)) { int32_t result = *(reinterpret_cast<volatile int32_t*>(const_cast<int32_t*>(word_addr))); - QuasiAtomic::MembarLoadLoad(); + QuasiAtomic::MembarLoadLoad(); // Ensure volatile loads don't re-order. return result; } else { return *word_addr; @@ -276,7 +263,7 @@ inline void Object::SetField32(MemberOffset field_offset, uint32_t new_value, bo if (UNLIKELY(is_volatile)) { QuasiAtomic::MembarStoreStore(); // Ensure this store occurs after others in the queue. *word_addr = new_value; - QuasiAtomic::MembarStoreLoad(); // Ensure this store occurs before any loads. + QuasiAtomic::MembarStoreLoad(); // Ensure this store occurs before any volatile loads. } else { *word_addr = new_value; } @@ -289,28 +276,31 @@ inline bool Object::CasField32(MemberOffset field_offset, uint32_t old_value, ui return __sync_bool_compare_and_swap(addr, old_value, new_value); } -inline uint64_t Object::GetField64(MemberOffset field_offset, bool is_volatile) const { +inline uint64_t Object::GetField64(MemberOffset field_offset, bool is_volatile) { VerifyObject(this); const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value(); const int64_t* addr = reinterpret_cast<const int64_t*>(raw_addr); if (UNLIKELY(is_volatile)) { uint64_t result = QuasiAtomic::Read64(addr); - QuasiAtomic::MembarLoadLoad(); + QuasiAtomic::MembarLoadLoad(); // Ensure volatile loads don't re-order. return result; } else { return *addr; } } -inline void Object::SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile) { - VerifyObject(this); +inline void Object::SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile, + bool this_is_valid) { + if (this_is_valid) { + VerifyObject(this); + } byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); int64_t* addr = reinterpret_cast<int64_t*>(raw_addr); if (UNLIKELY(is_volatile)) { QuasiAtomic::MembarStoreStore(); // Ensure this store occurs after others in the queue. QuasiAtomic::Write64(addr, new_value); if (!QuasiAtomic::LongAtomicsUseMutexes()) { - QuasiAtomic::MembarStoreLoad(); // Ensure this store occurs before any loads. + QuasiAtomic::MembarStoreLoad(); // Ensure this store occurs before any volatile loads. } else { // Fence from from mutex is enough. } @@ -319,12 +309,69 @@ inline void Object::SetField64(MemberOffset field_offset, uint64_t new_value, bo } } -inline void Object::WriteBarrierField(const Object* dst, MemberOffset field_offset, - const Object* new_value) { - Runtime::Current()->GetHeap()->WriteBarrierField(dst, field_offset, new_value); +inline bool Object::CasField64(MemberOffset field_offset, uint64_t old_value, uint64_t new_value) { + VerifyObject(this); + byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); + volatile uint64_t* addr = reinterpret_cast<volatile uint64_t*>(raw_addr); + return __sync_bool_compare_and_swap(addr, old_value, new_value); +} + +template<class T> +inline T* Object::GetFieldObject(MemberOffset field_offset, bool is_volatile) { + VerifyObject(this); + byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); + HeapReference<T>* objref_addr = reinterpret_cast<HeapReference<T>*>(raw_addr); + HeapReference<T> objref = *objref_addr; + + if (UNLIKELY(is_volatile)) { + QuasiAtomic::MembarLoadLoad(); // Ensure loads don't re-order. + } + T* result = objref.AsMirrorPtr(); + VerifyObject(result); + return result; +} + +inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value, + bool is_volatile, bool this_is_valid) { + if (this_is_valid) { + VerifyObject(this); + } + VerifyObject(new_value); + HeapReference<Object> objref(HeapReference<Object>::FromMirrorPtr(new_value)); + byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); + HeapReference<Object>* objref_addr = reinterpret_cast<HeapReference<Object>*>(raw_addr); + if (UNLIKELY(is_volatile)) { + QuasiAtomic::MembarStoreStore(); // Ensure this store occurs after others in the queue. + objref_addr->Assign(new_value); + QuasiAtomic::MembarStoreLoad(); // Ensure this store occurs before any loads. + } else { + objref_addr->Assign(new_value); + } +} + +inline void Object::SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile, + bool this_is_valid) { + SetFieldObjectWithoutWriteBarrier(field_offset, new_value, is_volatile, this_is_valid); + if (new_value != nullptr) { + CheckFieldAssignment(field_offset, new_value); + Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value); + } +} + +inline bool Object::CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value) { + VerifyObject(this); + byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); + volatile uint32_t* addr = reinterpret_cast<volatile uint32_t*>(raw_addr); + HeapReference<Object> old_ref(HeapReference<Object>::FromMirrorPtr(old_value)); + HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_value)); + bool success = __sync_bool_compare_and_swap(addr, old_ref.reference_, new_ref.reference_); + if (success) { + Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value); + } + return success; } -inline void Object::VerifyObject(const Object* obj) { +inline void Object::VerifyObject(Object* obj) { if (kIsDebugBuild) { Runtime::Current()->GetHeap()->VerifyObject(obj); } diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index bdb3250d57..1251852c8f 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -52,7 +52,7 @@ static Object* CopyObject(Thread* self, mirror::Object* dest, mirror::Object* sr Class* c = src->GetClass(); if (c->IsArrayClass()) { if (!c->GetComponentType()->IsPrimitive()) { - const ObjectArray<Object>* array = dest->AsObjectArray<Object>(); + ObjectArray<Object>* array = dest->AsObjectArray<Object>(); heap->WriteBarrierArray(dest, 0, array->GetLength()); } } else { @@ -139,14 +139,15 @@ int32_t Object::IdentityHashCode() const { return 0; } -void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, const Object* new_value) { - const Class* c = GetClass(); +void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, Object* new_value) { + Class* c = GetClass(); if (Runtime::Current()->GetClassLinker() == NULL || + !Runtime::Current()->IsStarted() || !Runtime::Current()->GetHeap()->IsObjectValidationEnabled() || !c->IsResolved()) { return; } - for (const Class* cur = c; cur != NULL; cur = cur->GetSuperClass()) { + for (Class* cur = c; cur != NULL; cur = cur->GetSuperClass()) { ObjectArray<ArtField>* fields = cur->GetIFields(); if (fields != NULL) { size_t num_ref_ifields = cur->NumReferenceInstanceFields(); diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 058aee7948..6fe8b73a1c 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -21,6 +21,7 @@ #include "base/logging.h" #include "base/macros.h" #include "cutils/atomic-inline.h" +#include "object_reference.h" #include "offsets.h" namespace art { @@ -51,17 +52,13 @@ typedef PrimitiveArray<int16_t> ShortArray; class String; class Throwable; -// Classes shared with the managed side of the world need to be packed so that they don't have -// extra platform specific padding. -#define MANAGED PACKED(4) - // Fields within mirror objects aren't accessed directly so that the appropriate amount of // handshaking is done with GC (for example, read and write barriers). This macro is used to // compute an offset for the Set/Get methods defined in Object that can safely access fields. #define OFFSET_OF_OBJECT_MEMBER(type, field) \ MemberOffset(OFFSETOF_MEMBER(type, field)) -const bool kCheckFieldAssignments = false; +constexpr bool kCheckFieldAssignments = false; // C++ mirror of java.lang.Object class MANAGED Object { @@ -70,19 +67,17 @@ class MANAGED Object { return OFFSET_OF_OBJECT_MEMBER(Object, klass_); } - Class* GetClass() const; + Class* GetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetClass(Class* new_klass); + void SetClass(Class* new_klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // The verifier treats all interfaces as java.lang.Object and relies on runtime checks in // invoke-interface to detect incompatible interface types. - bool VerifierInstanceOf(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool VerifierInstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool InstanceOf(const Class* klass) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t SizeOf() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Object* Clone(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -92,9 +87,9 @@ class MANAGED Object { return OFFSET_OF_OBJECT_MEMBER(Object, monitor_); } - LockWord GetLockWord() const; + LockWord GetLockWord(); void SetLockWord(LockWord new_val); - bool CasLockWord(LockWord old_val, LockWord new_val); + bool CasLockWord(LockWord old_val, LockWord new_val) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); uint32_t GetLockOwnerThreadId(); void MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) @@ -111,111 +106,113 @@ class MANAGED Object { void Wait(Thread* self, int64_t timeout, int32_t nanos) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsClass() const; - - Class* AsClass(); + bool IsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const Class* AsClass() const; + Class* AsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsObjectArray() const; + bool IsObjectArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template<class T> - ObjectArray<T>* AsObjectArray(); + ObjectArray<T>* AsObjectArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - template<class T> - const ObjectArray<T>* AsObjectArray() const; + bool IsArrayInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArrayInstance() const; + Array* AsArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Array* AsArray(); + BooleanArray* AsBooleanArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ByteArray* AsByteArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ByteArray* AsByteSizedArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const Array* AsArray() const; + CharArray* AsCharArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ShortArray* AsShortArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ShortArray* AsShortSizedArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - BooleanArray* AsBooleanArray(); - ByteArray* AsByteArray(); - CharArray* AsCharArray(); - ShortArray* AsShortArray(); - IntArray* AsIntArray(); - LongArray* AsLongArray(); + IntArray* AsIntArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + LongArray* AsLongArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - String* AsString(); + String* AsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArtMethod() const; - - ArtMethod* AsArtMethod(); + bool IsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const ArtMethod* AsArtMethod() const; + ArtMethod* AsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsArtField() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ArtField* AsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const ArtField* AsArtField() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - bool IsReferenceInstance() const; + bool IsReferenceInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsWeakReferenceInstance() const; + bool IsWeakReferenceInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsSoftReferenceInstance() const; + bool IsSoftReferenceInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsFinalizerReferenceInstance() const; + bool IsFinalizerReferenceInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsPhantomReferenceInstance() const; + bool IsPhantomReferenceInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Accessors for Java type fields - template<class T> - T GetFieldObject(MemberOffset field_offset, bool is_volatile) const { - T result = reinterpret_cast<T>(GetField32(field_offset, is_volatile)); - VerifyObject(result); - return result; - } - - void SetFieldObject(MemberOffset field_offset, const Object* new_value, bool is_volatile, - bool this_is_valid = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - VerifyObject(new_value); - SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid); - if (new_value != NULL) { - CheckFieldAssignment(field_offset, new_value); - WriteBarrierField(this, field_offset, new_value); - } - } + // Accessor for Java type fields. + template<class T> T* GetFieldObject(MemberOffset field_offset, bool is_volatile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value, + bool is_volatile, bool this_is_valid = true) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile, + bool this_is_valid = true) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Object** GetFieldObjectAddr(MemberOffset field_offset) ALWAYS_INLINE { + HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset) ALWAYS_INLINE { VerifyObject(this); - return reinterpret_cast<Object**>(reinterpret_cast<byte*>(this) + field_offset.Int32Value()); + return reinterpret_cast<HeapReference<Object>*>(reinterpret_cast<byte*>(this) + + field_offset.Int32Value()); } - uint32_t GetField32(MemberOffset field_offset, bool is_volatile) const; + uint32_t GetField32(MemberOffset field_offset, bool is_volatile); void SetField32(MemberOffset field_offset, uint32_t new_value, bool is_volatile, bool this_is_valid = true); - bool CasField32(MemberOffset field_offset, uint32_t old_value, uint32_t new_value); + bool CasField32(MemberOffset field_offset, uint32_t old_value, uint32_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint64_t GetField64(MemberOffset field_offset, bool is_volatile) const; + uint64_t GetField64(MemberOffset field_offset, bool is_volatile); - void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile); + void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile, + bool this_is_valid = true); + + bool CasField64(MemberOffset field_offset, uint64_t old_value, uint64_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template<typename T> - void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) { + void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, + bool this_is_valid = true) { +#ifndef __LP64__ SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid); +#else + SetField64(field_offset, reinterpret_cast<uint64_t>(new_value), is_volatile, this_is_valid); +#endif } protected: // Accessors for non-Java type fields template<class T> - T GetFieldPtr(MemberOffset field_offset, bool is_volatile) const { + T GetFieldPtr(MemberOffset field_offset, bool is_volatile) { +#ifndef __LP64__ return reinterpret_cast<T>(GetField32(field_offset, is_volatile)); +#else + return reinterpret_cast<T>(GetField64(field_offset, is_volatile)); +#endif } private: - static void VerifyObject(const Object* obj) ALWAYS_INLINE; + static void VerifyObject(Object* obj) ALWAYS_INLINE; // Verify the type correctness of stores to fields. - void CheckFieldAssignmentImpl(MemberOffset field_offset, const Object* new_value) + void CheckFieldAssignmentImpl(MemberOffset field_offset, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void CheckFieldAssignment(MemberOffset field_offset, const Object* new_value) + void CheckFieldAssignment(MemberOffset field_offset, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (kCheckFieldAssignments) { CheckFieldAssignmentImpl(field_offset, new_value); @@ -225,11 +222,9 @@ class MANAGED Object { // Generate an identity hash code. static int32_t GenerateIdentityHashCode(); - // Write barrier called post update to a reference bearing field. - static void WriteBarrierField(const Object* dst, MemberOffset offset, const Object* new_value); - - Class* klass_; - + // The Class representing the type of the object. + HeapReference<Class> klass_; + // Monitor and hash code information. uint32_t monitor_; friend class art::ImageWriter; diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 6a50dfe019..c3424793e9 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -25,6 +25,7 @@ #include "runtime.h" #include "sirt_ref.h" #include "thread.h" +#include <string> namespace art { namespace mirror { @@ -32,8 +33,8 @@ namespace mirror { template<class T> inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, Class* object_array_class, int32_t length, gc::AllocatorType allocator_type) { - Array* array = Array::Alloc<true>(self, object_array_class, length, sizeof(Object*), - allocator_type); + Array* array = Array::Alloc<true>(self, object_array_class, length, + sizeof(HeapReference<Object>), allocator_type); if (UNLIKELY(array == nullptr)) { return nullptr; } else { @@ -49,12 +50,12 @@ inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, Class* object_array_c } template<class T> -inline T* ObjectArray<T>::Get(int32_t i) const { +inline T* ObjectArray<T>::Get(int32_t i) { if (UNLIKELY(!CheckIsValidIndex(i))) { DCHECK(Thread::Current()->IsExceptionPending()); return NULL; } - return GetWithoutChecks(i); + return GetFieldObject<T>(OffsetOfElement(i), false); } template<class T> @@ -72,7 +73,7 @@ inline bool ObjectArray<T>::CheckAssignable(T* object) { template<class T> inline void ObjectArray<T>::Set(int32_t i, T* object) { if (LIKELY(CheckIsValidIndex(i) && CheckAssignable(object))) { - SetWithoutChecks(i, object); + SetFieldObject(OffsetOfElement(i), object, false); } else { DCHECK(Thread::Current()->IsExceptionPending()); } @@ -82,72 +83,123 @@ template<class T> inline void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) { DCHECK(CheckIsValidIndex(i)); DCHECK(CheckAssignable(object)); - MemberOffset data_offset(DataOffset(sizeof(Object*)).Int32Value() + i * sizeof(Object*)); - SetFieldObject(data_offset, object, false); + SetFieldObject(OffsetOfElement(i), object, false); } template<class T> -inline void ObjectArray<T>::SetPtrWithoutChecks(int32_t i, T* object) { +inline void ObjectArray<T>::SetWithoutChecksAndWriteBarrier(int32_t i, T* object) { DCHECK(CheckIsValidIndex(i)); - // TODO enable this check. It fails when writing the image in ImageWriter::FixupObjectArray. + // TODO: enable this check. It fails when writing the image in ImageWriter::FixupObjectArray. // DCHECK(CheckAssignable(object)); - MemberOffset data_offset(DataOffset(sizeof(Object*)).Int32Value() + i * sizeof(Object*)); - SetFieldPtr(data_offset, object, false); + SetFieldObjectWithoutWriteBarrier(OffsetOfElement(i), object, false); } template<class T> -inline T* ObjectArray<T>::GetWithoutChecks(int32_t i) const { +inline T* ObjectArray<T>::GetWithoutChecks(int32_t i) { DCHECK(CheckIsValidIndex(i)); - MemberOffset data_offset(DataOffset(sizeof(Object*)).Int32Value() + i * sizeof(Object*)); - return GetFieldObject<T*>(data_offset, false); + return GetFieldObject<T>(OffsetOfElement(i), false); } template<class T> -inline void ObjectArray<T>::Copy(const ObjectArray<T>* src, int src_pos, - ObjectArray<T>* dst, int dst_pos, - size_t length) { - if (src->CheckIsValidIndex(src_pos) && - src->CheckIsValidIndex(src_pos + length - 1) && - dst->CheckIsValidIndex(dst_pos) && - dst->CheckIsValidIndex(dst_pos + length - 1)) { - MemberOffset src_offset(DataOffset(sizeof(Object*)).Int32Value() + src_pos * sizeof(Object*)); - MemberOffset dst_offset(DataOffset(sizeof(Object*)).Int32Value() + dst_pos * sizeof(Object*)); - Class* array_class = dst->GetClass(); - gc::Heap* heap = Runtime::Current()->GetHeap(); - if (array_class == src->GetClass()) { - // No need for array store checks if arrays are of the same type - for (size_t i = 0; i < length; i++) { - Object* object = src->GetFieldObject<Object*>(src_offset, false); - heap->VerifyObject(object); - // directly set field, we do a bulk write barrier at the end - dst->SetField32(dst_offset, reinterpret_cast<uint32_t>(object), false, true); - src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*)); - dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*)); - } +inline void ObjectArray<T>::AssignableMemmove(int32_t dst_pos, ObjectArray<T>* src, + int32_t src_pos, int32_t count) { + if (kIsDebugBuild) { + for (int i = 0; i < count; ++i) { + // The Get will perform the VerifyObject. + src->GetWithoutChecks(src_pos + i); + } + } + // Perform the memmove using int memmove then perform the write barrier. + CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t)); + IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this); + IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src); + dstAsIntArray->Memmove(dst_pos, srcAsIntArray, src_pos, count); + Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); + if (kIsDebugBuild) { + for (int i = 0; i < count; ++i) { + // The Get will perform the VerifyObject. + GetWithoutChecks(dst_pos + i); + } + } +} + +template<class T> +inline void ObjectArray<T>::AssignableMemcpy(int32_t dst_pos, ObjectArray<T>* src, + int32_t src_pos, int32_t count) { + if (kIsDebugBuild) { + for (int i = 0; i < count; ++i) { + // The Get will perform the VerifyObject. + src->GetWithoutChecks(src_pos + i); + } + } + // Perform the memmove using int memcpy then perform the write barrier. + CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t)); + IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this); + IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src); + dstAsIntArray->Memcpy(dst_pos, srcAsIntArray, src_pos, count); + Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); + if (kIsDebugBuild) { + for (int i = 0; i < count; ++i) { + // The Get will perform the VerifyObject. + GetWithoutChecks(dst_pos + i); + } + } +} + +template<class T> +inline void ObjectArray<T>::AssignableCheckingMemcpy(int32_t dst_pos, ObjectArray<T>* src, + int32_t src_pos, int32_t count, + bool throw_exception) { + DCHECK_NE(this, src) + << "This case should be handled with memmove that handles overlaps correctly"; + // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that + // we know is assignable to the destination array's component type. + Class* dst_class = GetClass()->GetComponentType(); + Class* lastAssignableElementClass = dst_class; + + Object* o = nullptr; + int i = 0; + for (; i < count; ++i) { + // The follow get operations force the objects to be verified. + o = src->GetWithoutChecks(src_pos + i); + if (o == nullptr) { + // Null is always assignable. + SetWithoutChecks(dst_pos + i, nullptr); } else { - Class* element_class = array_class->GetComponentType(); - CHECK(!element_class->IsPrimitive()); - for (size_t i = 0; i < length; i++) { - Object* object = src->GetFieldObject<Object*>(src_offset, false); - if (object != NULL && !object->InstanceOf(element_class)) { - dst->ThrowArrayStoreException(object); - return; - } - heap->VerifyObject(object); - // directly set field, we do a bulk write barrier at the end - dst->SetField32(dst_offset, reinterpret_cast<uint32_t>(object), false, true); - src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*)); - dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*)); + // TODO: use the underlying class reference to avoid uncompression when not necessary. + Class* o_class = o->GetClass(); + if (LIKELY(lastAssignableElementClass == o_class)) { + SetWithoutChecks(dst_pos + i, o); + } else if (LIKELY(dst_class->IsAssignableFrom(o_class))) { + lastAssignableElementClass = o_class; + SetWithoutChecks(dst_pos + i, o); + } else { + // Can't put this element into the array, break to perform write-barrier and throw + // exception. + break; } } - heap->WriteBarrierArray(dst, dst_pos, length); - } else { - DCHECK(Thread::Current()->IsExceptionPending()); + } + Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); + if (UNLIKELY(i != count)) { + std::string actualSrcType(PrettyTypeOf(o)); + std::string dstType(PrettyTypeOf(this)); + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + if (throw_exception) { + self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;", + "source[%d] of type %s cannot be stored in destination array of type %s", + src_pos + i, actualSrcType.c_str(), dstType.c_str()); + } else { + LOG(FATAL) << StringPrintf("source[%d] of type %s cannot be stored in destination array of type %s", + src_pos + i, actualSrcType.c_str(), dstType.c_str()); + } } } template<class T> inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) { + DCHECK_GE(new_length, 0); // We may get copied by a compacting GC. SirtRef<ObjectArray<T> > sirt_this(self, this); gc::Heap* heap = Runtime::Current()->GetHeap(); @@ -155,11 +207,17 @@ inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) heap->GetCurrentNonMovingAllocator(); ObjectArray<T>* new_array = Alloc(self, GetClass(), new_length, allocator_type); if (LIKELY(new_array != nullptr)) { - Copy(sirt_this.get(), 0, new_array, 0, std::min(sirt_this->GetLength(), new_length)); + new_array->AssignableMemcpy(0, sirt_this.get(), 0, std::min(sirt_this->GetLength(), new_length)); } return new_array; } +template<class T> +inline MemberOffset ObjectArray<T>::OffsetOfElement(int32_t i) { + return MemberOffset(DataOffset(sizeof(HeapReference<Object>)).Int32Value() + + (i * sizeof(HeapReference<Object>))); +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h index 5da8845196..347494e2ab 100644 --- a/runtime/mirror/object_array.h +++ b/runtime/mirror/object_array.h @@ -33,7 +33,7 @@ class MANAGED ObjectArray : public Array { static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - T* Get(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + T* Get(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns true if the object can be stored into the array. If not, throws // an ArrayStoreException and returns false. @@ -44,22 +44,30 @@ class MANAGED ObjectArray : public Array { // Set element without bound and element type checks, to be used in limited // circumstances, such as during boot image writing void SetWithoutChecks(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetWithoutChecksAndWriteBarrier(int32_t i, T* object) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + T* GetWithoutChecks(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Set element without bound and element type checks, to be used in limited circumstances, such - // as during boot image writing. Does not do write barrier. - void SetPtrWithoutChecks(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Copy src into this array (dealing with overlaps as memmove does) without assignability checks. + void AssignableMemmove(int32_t dst_pos, ObjectArray<T>* src, int32_t src_pos, + int32_t count) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - T* GetWithoutChecks(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Copy src into this array assuming no overlap and without assignability checks. + void AssignableMemcpy(int32_t dst_pos, ObjectArray<T>* src, int32_t src_pos, + int32_t count) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static void Copy(const ObjectArray<T>* src, int src_pos, - ObjectArray<T>* dst, int dst_pos, - size_t length) + // Copy src into this array with assignability checks. + void AssignableCheckingMemcpy(int32_t dst_pos, ObjectArray<T>* src, int32_t src_pos, + int32_t count, bool throw_exception) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ObjectArray<T>* CopyOf(Thread* self, int32_t new_length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: + static MemberOffset OffsetOfElement(int32_t i); + DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectArray); }; diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h new file mode 100644 index 0000000000..b30890f99a --- /dev/null +++ b/runtime/mirror/object_reference.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_ +#define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_ + +#include "locks.h" + +namespace art { +namespace mirror { + +class Object; + +// Classes shared with the managed side of the world need to be packed so that they don't have +// extra platform specific padding. +#define MANAGED PACKED(4) + +// Value type representing a reference to a mirror::Object of type MirrorType. +template<bool kPoisonReferences, class MirrorType> +class MANAGED ObjectReference { + public: + MirrorType* AsMirrorPtr() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return UnCompress(); + } + + void Assign(MirrorType* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + reference_ = Compress(other); + } + + void Clear() { + reference_ = 0; + } + + uint32_t AsVRegValue() const { + return reference_; + } + + protected: + ObjectReference<kPoisonReferences, MirrorType>(MirrorType* mirror_ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : reference_(Compress(mirror_ptr)) { + } + + // Compress reference to its bit representation. + static uint32_t Compress(MirrorType* mirror_ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uintptr_t as_bits = reinterpret_cast<uintptr_t>(mirror_ptr); + return static_cast<uint32_t>(kPoisonReferences ? -as_bits : as_bits); + } + + // Uncompress an encoded reference from its bit representation. + MirrorType* UnCompress() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uintptr_t as_bits = kPoisonReferences ? -reference_ : reference_; + return reinterpret_cast<MirrorType*>(as_bits); + } + + friend class Object; + + // The encoded reference to a mirror::Object. + uint32_t reference_; +}; + +// References between objects within the managed heap. +template<class MirrorType> +class MANAGED HeapReference : public ObjectReference<false, MirrorType> { + public: + static HeapReference<MirrorType> FromMirrorPtr(MirrorType* mirror_ptr) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return HeapReference<MirrorType>(mirror_ptr); + } + private: + HeapReference<MirrorType>(MirrorType* mirror_ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : ObjectReference<false, MirrorType>(mirror_ptr) {} +}; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_ diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 36371810f4..2af32dacd2 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -77,7 +77,7 @@ TEST_F(ObjectTest, AsmConstants) { EXPECT_EQ(CLASS_COMPONENT_TYPE_OFFSET, Class::ComponentTypeOffset().Int32Value()); EXPECT_EQ(ARRAY_LENGTH_OFFSET, Array::LengthOffset().Int32Value()); - EXPECT_EQ(OBJECT_ARRAY_DATA_OFFSET, Array::DataOffset(sizeof(Object*)).Int32Value()); + EXPECT_EQ(OBJECT_ARRAY_DATA_OFFSET, Array::DataOffset(sizeof(HeapReference<Object>)).Int32Value()); EXPECT_EQ(STRING_VALUE_OFFSET, String::ValueOffset().Int32Value()); EXPECT_EQ(STRING_COUNT_OFFSET, String::CountOffset().Int32Value()); @@ -85,7 +85,8 @@ TEST_F(ObjectTest, AsmConstants) { EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value()); EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); - EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value()); + EXPECT_EQ(METHOD_PORTABLE_CODE_OFFSET, ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value()); + EXPECT_EQ(METHOD_QUICK_CODE_OFFSET, ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); } TEST_F(ObjectTest, IsInSamePackage) { @@ -295,7 +296,7 @@ TEST_F(ObjectTest, StaticFieldFromCode) { uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id); ArtField* field = FindFieldFromCode<StaticObjectRead, true>(field_idx, clinit, Thread::Current(), - sizeof(Object*)); + sizeof(HeapReference<Object>)); Object* s0 = field->GetObj(klass); EXPECT_TRUE(s0 != NULL); diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h index 18a84dcbdb..ff019c6a27 100644 --- a/runtime/mirror/proxy.h +++ b/runtime/mirror/proxy.h @@ -29,24 +29,28 @@ namespace mirror { // has the static fields used to implement reflection on proxy objects. class MANAGED SynthesizedProxyClass : public Class { public: - ObjectArray<Class>* GetInterfaces() { - return interfaces_; + ObjectArray<Class>* GetInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<ObjectArray<Class> >(OFFSET_OF_OBJECT_MEMBER(SynthesizedProxyClass, + interfaces_), + false); } - ObjectArray<ObjectArray<Class> >* GetThrows() { - return throws_; + ObjectArray<ObjectArray<Class> >* GetThrows() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<ObjectArray<ObjectArray<Class> > >(OFFSET_OF_OBJECT_MEMBER(SynthesizedProxyClass, + throws_), + false); } private: - ObjectArray<Class>* interfaces_; - ObjectArray<ObjectArray<Class> >* throws_; + HeapReference<ObjectArray<Class> > interfaces_; + HeapReference<ObjectArray<ObjectArray<Class> > > throws_; DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass); }; // C++ mirror of java.lang.reflect.Proxy. class MANAGED Proxy : public Object { private: - Object* h_; + HeapReference<Object> h_; friend struct art::ProxyOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(Proxy); diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h index d1be4dcfde..73d2673ea0 100644 --- a/runtime/mirror/stack_trace_element.h +++ b/runtime/mirror/stack_trace_element.h @@ -29,24 +29,23 @@ namespace mirror { // C++ mirror of java.lang.StackTraceElement class MANAGED StackTraceElement : public Object { public: - const String* GetDeclaringClass() const { - return GetFieldObject<const String*>( - OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_), false); + String* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_), + false); } - const String* GetMethodName() const { - return GetFieldObject<const String*>( - OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_), false); + String* GetMethodName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_), + false); } - const String* GetFileName() const { - return GetFieldObject<const String*>( - OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_), false); + String* GetFileName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_), + false); } - int32_t GetLineNumber() const { - return GetField32( - OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_), false); + int32_t GetLineNumber() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_), false); } static StackTraceElement* Alloc(Thread* self, @@ -63,9 +62,9 @@ class MANAGED StackTraceElement : public Object { private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". - String* declaring_class_; - String* file_name_; - String* method_name_; + HeapReference<String> declaring_class_; + HeapReference<String> file_name_; + HeapReference<String> method_name_; int32_t line_number_; static Class* GetStackTraceElement() { diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index 1f756a1e53..10ae06619e 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -29,23 +29,19 @@ namespace art { namespace mirror { -const CharArray* String::GetCharArray() const { - return GetFieldObject<const CharArray*>(ValueOffset(), false); -} - CharArray* String::GetCharArray() { - return GetFieldObject<CharArray*>(ValueOffset(), false); + return GetFieldObject<CharArray>(ValueOffset(), false); } void String::ComputeHashCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength())); } -int32_t String::GetUtfLength() const { +int32_t String::GetUtfLength() { return CountUtf8Bytes(GetCharArray()->GetData() + GetOffset(), GetLength()); } -int32_t String::FastIndexOf(int32_t ch, int32_t start) const { +int32_t String::FastIndexOf(int32_t ch, int32_t start) { int32_t count = GetLength(); if (start < 0) { start = 0; @@ -97,13 +93,13 @@ int32_t String::GetHashCode() { return result; } -int32_t String::GetLength() const { +int32_t String::GetLength() { int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), false); DCHECK(result >= 0 && result <= GetCharArray()->GetLength()); return result; } -uint16_t String::CharAt(int32_t index) const { +uint16_t String::CharAt(int32_t index) { // TODO: do we need this? Equals is the only caller, and could // bounds check itself. DCHECK_GE(count_, 0); // ensures the unsigned comparison is safe. @@ -179,7 +175,7 @@ String* String::Alloc(Thread* self, const SirtRef<CharArray>& array) { return string; } -bool String::Equals(const String* that) const { +bool String::Equals(String* that) { if (this == that) { // Quick reference equality test return true; @@ -201,7 +197,7 @@ bool String::Equals(const String* that) const { } } -bool String::Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) const { +bool String::Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) { if (this->GetLength() != that_length) { return false; } else { @@ -214,7 +210,7 @@ bool String::Equals(const uint16_t* that_chars, int32_t that_offset, int32_t tha } } -bool String::Equals(const char* modified_utf8) const { +bool String::Equals(const char* modified_utf8) { for (int32_t i = 0; i < GetLength(); ++i) { uint16_t ch = GetUtf16FromUtf8(&modified_utf8); if (ch == '\0' || ch != CharAt(i)) { @@ -224,7 +220,7 @@ bool String::Equals(const char* modified_utf8) const { return *modified_utf8 == '\0'; } -bool String::Equals(const StringPiece& modified_utf8) const { +bool String::Equals(const StringPiece& modified_utf8) { const char* p = modified_utf8.data(); for (int32_t i = 0; i < GetLength(); ++i) { uint16_t ch = GetUtf16FromUtf8(&p); @@ -236,7 +232,7 @@ bool String::Equals(const StringPiece& modified_utf8) const { } // Create a modified UTF-8 encoded std::string from a java/lang/String object. -std::string String::ToModifiedUtf8() const { +std::string String::ToModifiedUtf8() { const uint16_t* chars = GetCharArray()->GetData() + GetOffset(); size_t byte_count = GetUtfLength(); std::string result(byte_count, static_cast<char>(0)); @@ -259,9 +255,9 @@ static uint32_t MemCmp16(const uint16_t* s0, const uint16_t* s1, size_t count) { } #endif -int32_t String::CompareTo(String* rhs) const { +int32_t String::CompareTo(String* rhs) { // Quick test for comparison of a string with itself. - const String* lhs = this; + String* lhs = this; if (lhs == rhs) { return 0; } diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 4bbcb9c606..a82b26cd3a 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -44,24 +44,23 @@ class MANAGED String : public Object { return OFFSET_OF_OBJECT_MEMBER(String, offset_); } - const CharArray* GetCharArray() const; - CharArray* GetCharArray(); + CharArray* GetCharArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t GetOffset() const { + int32_t GetOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { int32_t result = GetField32(OffsetOffset(), false); DCHECK_LE(0, result); return result; } - int32_t GetLength() const; + int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); int32_t GetHashCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ComputeHashCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t GetUtfLength() const; + int32_t GetUtfLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uint16_t CharAt(int32_t index) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint16_t CharAt(int32_t index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); String* Intern() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -78,29 +77,28 @@ class MANAGED String : public Object { const char* utf8_data_in) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool Equals(const char* modified_utf8) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool Equals(const char* modified_utf8) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // TODO: do we need this overload? give it a more intention-revealing name. - bool Equals(const StringPiece& modified_utf8) const + bool Equals(const StringPiece& modified_utf8) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool Equals(const String* that) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool Equals(String* that) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Compare UTF-16 code point values not in a locale-sensitive manner int Compare(int32_t utf16_length, const char* utf8_data_in); // TODO: do we need this overload? give it a more intention-revealing name. bool Equals(const uint16_t* that_chars, int32_t that_offset, - int32_t that_length) const + int32_t that_length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Create a modified UTF-8 encoded std::string from a java/lang/String object. - std::string ToModifiedUtf8() const; + std::string ToModifiedUtf8() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t FastIndexOf(int32_t ch, int32_t start) const; + int32_t FastIndexOf(int32_t ch, int32_t start) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - int32_t CompareTo(String* other) const; + int32_t CompareTo(String* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static Class* GetJavaLangString() { DCHECK(java_lang_String_ != NULL); @@ -123,7 +121,7 @@ class MANAGED String : public Object { SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false); } - void SetOffset(int32_t new_offset) { + void SetOffset(int32_t new_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_LE(0, new_offset); DCHECK_GE(GetLength(), new_offset); SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false); @@ -138,7 +136,7 @@ class MANAGED String : public Object { void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". - CharArray* array_; + HeapReference<CharArray> array_; int32_t count_; @@ -155,8 +153,8 @@ class MANAGED String : public Object { class MANAGED StringClass : public Class { private: - CharArray* ASCII_; - Object* CASE_INSENSITIVE_ORDER_; + HeapReference<CharArray> ASCII_; + HeapReference<Object> CASE_INSENSITIVE_ORDER_; uint32_t REPLACEMENT_CHAR_; int64_t serialVersionUID_; friend struct art::StringClassOffsets; // for verifying offset information diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index b55db729b8..2318b74ec8 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -33,22 +33,22 @@ namespace mirror { Class* Throwable::java_lang_Throwable_ = NULL; void Throwable::SetCause(Throwable* cause) { - CHECK(cause != NULL); + CHECK(cause != nullptr); CHECK(cause != this); - Throwable* current_cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), - false); + Throwable* current_cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), + false); CHECK(current_cause == NULL || current_cause == this); SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false); } -bool Throwable::IsCheckedException() const { +bool Throwable::IsCheckedException() { if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) { return false; } return !InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_RuntimeException)); } -std::string Throwable::Dump() const { +std::string Throwable::Dump() { std::string result(PrettyTypeOf(this)); result += ": "; String* msg = GetDetailMessage(); @@ -74,7 +74,7 @@ std::string Throwable::Dump() const { source_file, line_number); } } - Throwable* cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false); + Throwable* cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false); if (cause != NULL && cause != this) { // Constructor makes cause == this by default. result += "Caused by: "; result += cause->Dump(); diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index 5a905990d8..bc9848abcf 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -33,16 +33,16 @@ class MANAGED Throwable : public Object { void SetDetailMessage(String* new_detail_message) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message, false); } - String* GetDetailMessage() const { - return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false); + String* GetDetailMessage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false); } - std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + std::string Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // This is a runtime version of initCause, you shouldn't use it if initCause may have been // overridden. Also it asserts rather than throwing exceptions. Currently this is only used // in cases like the verifier where the checks cannot fail and initCause isn't overridden. void SetCause(Throwable* cause) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsCheckedException() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static Class* GetJavaLangThrowable() { DCHECK(java_lang_Throwable_ != NULL); @@ -55,16 +55,16 @@ class MANAGED Throwable : public Object { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: - Object* GetStackState() const { - return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), true); + Object* GetStackState() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), true); } // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". - Throwable* cause_; - String* detail_message_; - Object* stack_state_; // Note this is Java volatile: - Object* stack_trace_; - Object* suppressed_exceptions_; + HeapReference<Throwable> cause_; + HeapReference<String> detail_message_; + HeapReference<Object> stack_state_; // Note this is Java volatile: + HeapReference<Object> stack_trace_; + HeapReference<Object> suppressed_exceptions_; static Class* java_lang_Throwable_; diff --git a/runtime/modifiers.h b/runtime/modifiers.h index 4e365be8e0..0addd51fc6 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -47,6 +47,7 @@ static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex onl static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) static const uint32_t kAccPreverified = 0x00080000; // method (dex only) static const uint32_t kAccFastNative = 0x0080000; // method (dex only) +static const uint32_t kAccPortableCompiled = 0x0100000; // method (dex only) // Special runtime-only flags. // Note: if only kAccClassIsReference is set, we have a soft reference. diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 41866935af..72220e0877 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -79,7 +79,7 @@ void Monitor::Init(uint32_t lock_profiling_threshold, bool (*is_sensitive_thread is_sensitive_thread_hook_ = is_sensitive_thread_hook; } -Monitor::Monitor(Thread* owner, mirror::Object* obj, int32_t hash_code) +Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code) : monitor_lock_("a monitor lock", kMonitorLock), monitor_contenders_("monitor contenders", monitor_lock_), num_waiters_(0), @@ -89,10 +89,11 @@ Monitor::Monitor(Thread* owner, mirror::Object* obj, int32_t hash_code) wait_set_(NULL), hash_code_(hash_code), locking_method_(NULL), - locking_dex_pc_(0) { + locking_dex_pc_(0), + monitor_id_(MonitorPool::CreateMonitorId(self, this)) { // We should only inflate a lock if the owner is ourselves or suspended. This avoids a race // with the owner unlocking the thin-lock. - CHECK(owner == nullptr || owner == Thread::Current() || owner->IsSuspended()); + CHECK(owner == nullptr || owner == self || owner->IsSuspended()); // The identity hash code is set for the life time of the monitor. } @@ -145,6 +146,7 @@ bool Monitor::Install(Thread* self) { } Monitor::~Monitor() { + MonitorPool::ReleaseMonitorId(monitor_id_); // Deflated monitors have a null object. } @@ -219,7 +221,7 @@ void Monitor::Lock(Thread* self) { // Contended. const bool log_contention = (lock_profiling_threshold_ != 0); uint64_t wait_start_ms = log_contention ? 0 : MilliTime(); - const mirror::ArtMethod* owners_method = locking_method_; + mirror::ArtMethod* owners_method = locking_method_; uint32_t owners_dex_pc = locking_dex_pc_; monitor_lock_.Unlock(self); // Let go of locks in order. { @@ -411,7 +413,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, if (ms < 0 || ns < 0 || ns > 999999) { ThrowLocation throw_location = self->GetCurrentLocationForThrow(); self->ThrowNewExceptionF(throw_location, "Ljava/lang/IllegalArgumentException;", - "timeout arguments out of range: ms=%lld ns=%d", ms, ns); + "timeout arguments out of range: ms=%" PRId64 " ns=%d", ms, ns); monitor_lock_.Unlock(self); return; } @@ -430,7 +432,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, int prev_lock_count = lock_count_; lock_count_ = 0; owner_ = NULL; - const mirror::ArtMethod* saved_method = locking_method_; + mirror::ArtMethod* saved_method = locking_method_; locking_method_ = NULL; uintptr_t saved_dex_pc = locking_dex_pc_; locking_dex_pc_ = 0; @@ -611,7 +613,7 @@ void Monitor::Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t DCHECK(self != NULL); DCHECK(obj != NULL); // Allocate and acquire a new monitor. - UniquePtr<Monitor> m(new Monitor(owner, obj, hash_code)); + UniquePtr<Monitor> m(new Monitor(self, owner, obj, hash_code)); if (m->Install(self)) { VLOG(monitor) << "monitor: thread " << owner->GetThreadId() << " created monitor " << m.get() << " for object " << obj; @@ -1008,7 +1010,7 @@ bool Monitor::IsLocked() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return owner_ != nullptr; } -void Monitor::TranslateLocation(const mirror::ArtMethod* method, uint32_t dex_pc, +void Monitor::TranslateLocation(mirror::ArtMethod* method, uint32_t dex_pc, const char** source_file, uint32_t* line_number) const { // If method is null, location is unknown if (method == NULL) { diff --git a/runtime/monitor.h b/runtime/monitor.h index 16e9410957..85a8c48e50 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -24,7 +24,7 @@ #include <list> #include <vector> -#include "atomic_integer.h" +#include "atomic.h" #include "base/mutex.h" #include "root_visitor.h" #include "sirt_ref.h" @@ -40,6 +40,8 @@ class LockWord; class Thread; class StackVisitor; +typedef uint32_t MonitorId; + class Monitor { public: // The default number of spins that are done before thread suspension is used to forcibly inflate @@ -108,6 +110,10 @@ class Monitor { return hash_code_.Load() != 0; } + MonitorId GetMonitorId() const { + return monitor_id_; + } + static void InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, LockWord lock_word, uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS; @@ -115,7 +121,7 @@ class Monitor { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: - explicit Monitor(Thread* owner, mirror::Object* obj, int32_t hash_code) + explicit Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Install the monitor into its object, may fail if another thread installs a different monitor @@ -162,7 +168,7 @@ class Monitor { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Translates the provided method and pc into its declaring class' source file and line number. - void TranslateLocation(const mirror::ArtMethod* method, uint32_t pc, + void TranslateLocation(mirror::ArtMethod* method, uint32_t pc, const char** source_file, uint32_t* line_number) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -195,9 +201,12 @@ class Monitor { // Method and dex pc where the lock owner acquired the lock, used when lock // sampling is enabled. locking_method_ may be null if the lock is currently // unlocked, or if the lock is acquired by the system when the stack is empty. - const mirror::ArtMethod* locking_method_ GUARDED_BY(monitor_lock_); + mirror::ArtMethod* locking_method_ GUARDED_BY(monitor_lock_); uint32_t locking_dex_pc_ GUARDED_BY(monitor_lock_); + // The denser encoded version of this monitor as stored in the lock word. + MonitorId monitor_id_; + friend class MonitorInfo; friend class MonitorList; friend class mirror::Object; diff --git a/runtime/monitor_pool.cc b/runtime/monitor_pool.cc new file mode 100644 index 0000000000..eadd7a6cb1 --- /dev/null +++ b/runtime/monitor_pool.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 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 "monitor_pool.h" + +#include "base/logging.h" +#include "base/mutex-inl.h" +#include "monitor.h" + +namespace art { + +MonitorPool::MonitorPool() : allocated_ids_lock_("allocated monitor ids lock") { +} + +Monitor* MonitorPool::LookupMonitorFromTable(MonitorId mon_id) { + ReaderMutexLock mu(Thread::Current(), allocated_ids_lock_); + return table_.Get(mon_id); +} + +MonitorId MonitorPool::AllocMonitorIdFromTable(Thread* self, Monitor* mon) { + WriterMutexLock mu(self, allocated_ids_lock_); + for (size_t i = 0; i < allocated_ids_.size(); ++i) { + if (!allocated_ids_[i]) { + allocated_ids_.set(i); + MonitorId mon_id = i + 1; // Zero is reserved to mean "invalid". + table_.Put(mon_id, mon); + return mon_id; + } + } + LOG(FATAL) << "Out of internal monitor ids"; + return 0; +} + +void MonitorPool::ReleaseMonitorIdFromTable(MonitorId mon_id) { + WriterMutexLock mu(Thread::Current(), allocated_ids_lock_); + DCHECK(table_.Get(mon_id) != nullptr); + table_.erase(mon_id); + --mon_id; // Zero is reserved to mean "invalid". + DCHECK(allocated_ids_[mon_id]) << mon_id; + allocated_ids_.reset(mon_id); +} + +} // namespace art diff --git a/runtime/monitor_pool.h b/runtime/monitor_pool.h new file mode 100644 index 0000000000..32f3f4ebe3 --- /dev/null +++ b/runtime/monitor_pool.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ART_RUNTIME_MONITOR_POOL_H_ +#define ART_RUNTIME_MONITOR_POOL_H_ + +#include "monitor.h" + +#include "safe_map.h" + +#include <stdint.h> + +namespace art { + +// Abstraction to keep monitors small enough to fit in a lock word (32bits). On 32bit systems the +// monitor id loses the alignment bits of the Monitor*. +class MonitorPool { + public: + static MonitorPool* Create() { +#ifndef __LP64__ + return nullptr; +#else + return new MonitorPool(); +#endif + } + + static Monitor* MonitorFromMonitorId(MonitorId mon_id) { +#ifndef __LP64__ + return reinterpret_cast<Monitor*>(mon_id << 3); +#else + return Runtime::Current()->GetMonitorPool()->LookupMonitorFromTable(mon_id); +#endif + } + + static MonitorId MonitorIdFromMonitor(Monitor* mon) { +#ifndef __LP64__ + return reinterpret_cast<MonitorId>(mon) >> 3; +#else + return mon->GetMonitorId(); +#endif + } + + static MonitorId CreateMonitorId(Thread* self, Monitor* mon) { +#ifndef __LP64__ + UNUSED(self); + return MonitorIdFromMonitor(mon); +#else + return Runtime::Current()->GetMonitorPool()->AllocMonitorIdFromTable(self, mon); +#endif + } + + static void ReleaseMonitorId(MonitorId mon_id) { +#ifndef __LP64__ + UNUSED(mon_id); +#else + Runtime::Current()->GetMonitorPool()->ReleaseMonitorIdFromTable(mon_id); +#endif + } + + private: +#ifdef __LP64__ + MonitorPool(); + + Monitor* LookupMonitorFromTable(MonitorId mon_id); + + MonitorId LookupMonitorIdFromTable(Monitor* mon); + + MonitorId AllocMonitorIdFromTable(Thread* self, Monitor* mon); + + void ReleaseMonitorIdFromTable(MonitorId mon_id); + + ReaderWriterMutex allocated_ids_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + static constexpr uint32_t kMaxMonitorId = 0xFFFF; + std::bitset<kMaxMonitorId> allocated_ids_ GUARDED_BY(allocated_ids_lock_); + SafeMap<MonitorId, Monitor*> table_ GUARDED_BY(allocated_ids_lock_); +#endif +}; + +} // namespace art + +#endif // ART_RUNTIME_MONITOR_POOL_H_ diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 2c75ecc01e..1a3ceb80d8 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -290,7 +290,7 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename return JNI_TRUE; } if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() - != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) { + != reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin())) { if (kDebugLogging) { ScopedObjectAccess soa(env); LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index c9e255c99b..e1b5f97429 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -90,7 +90,7 @@ static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) { ThrowRuntimeException("Trying to get address of movable array object"); return 0; } - return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize())); + return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize(), 0)); } static void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) { @@ -181,7 +181,8 @@ static void VMRuntime_concurrentGC(JNIEnv* env, jobject) { typedef std::map<std::string, mirror::String*> StringTable; -static mirror::Object* PreloadDexCachesStringsVisitor(mirror::Object* root, void* arg) { +static mirror::Object* PreloadDexCachesStringsVisitor(mirror::Object* root, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { StringTable& table = *reinterpret_cast<StringTable*>(arg); mirror::String* string = const_cast<mirror::Object*>(root)->AsString(); // LOG(INFO) << "VMRuntime.preloadDexCaches interned=" << string->ToModifiedUtf8(); diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc index f91536544a..7e02e29d3f 100644 --- a/runtime/native/dalvik_system_VMStack.cc +++ b/runtime/native/dalvik_system_VMStack.cc @@ -79,7 +79,7 @@ static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject ja ClosestUserClassLoaderVisitor(Thread* thread, mirror::Object* bootstrap, mirror::Object* system) : StackVisitor(thread, NULL), bootstrap(bootstrap), system(system), class_loader(NULL) {} - bool VisitFrame() { + bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(class_loader == NULL); mirror::Class* c = GetMethod()->GetDeclaringClass(); mirror::Object* cl = c->GetClassLoader(); diff --git a/runtime/native/dalvik_system_Zygote.cc b/runtime/native/dalvik_system_Zygote.cc index 7fa9457eb3..22c543055b 100644 --- a/runtime/native/dalvik_system_Zygote.cc +++ b/runtime/native/dalvik_system_Zygote.cc @@ -47,8 +47,10 @@ #if defined(__linux__) #include <sys/personality.h> #include <sys/utsname.h> +#if defined(HAVE_ANDROID_OS) #include <sys/capability.h> #endif +#endif namespace art { diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index ea78e04702..6bbe642217 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -24,150 +24,14 @@ #include "mirror/object_array-inl.h" #include "scoped_fast_native_object_access.h" -/* - * We make guarantees about the atomicity of accesses to primitive - * variables. These guarantees also apply to elements of arrays. - * In particular, 8-bit, 16-bit, and 32-bit accesses must be atomic and - * must not cause "word tearing". Accesses to 64-bit array elements must - * either be atomic or treated as two 32-bit operations. References are - * always read and written atomically, regardless of the number of bits - * used to represent them. - * - * We can't rely on standard libc functions like memcpy(3) and memmove(3) - * in our implementation of System.arraycopy, because they may copy - * byte-by-byte (either for the full run or for "unaligned" parts at the - * start or end). We need to use functions that guarantee 16-bit or 32-bit - * atomicity as appropriate. - * - * System.arraycopy() is heavily used, so having an efficient implementation - * is important. The bionic libc provides a platform-optimized memory move - * function that should be used when possible. If it's not available, - * the trivial "reference implementation" versions below can be used until - * a proper version can be written. - * - * For these functions, The caller must guarantee that dst/src are aligned - * appropriately for the element type, and that n is a multiple of the - * element size. - */ +namespace art { /* - * Works like memmove(), except: - * - if all arguments are at least 32-bit aligned, we guarantee that we - * will use operations that preserve atomicity of 32-bit values - * - if not, we guarantee atomicity of 16-bit values - * - * If all three arguments are not at least 16-bit aligned, the behavior - * of this function is undefined. (We could remove this restriction by - * testing for unaligned values and punting to memmove(), but that's - * not currently useful.) - * - * TODO: add loop for 64-bit alignment - * TODO: use __builtin_prefetch - * TODO: write ARM/MIPS/x86 optimized versions + * We make guarantees about the atomicity of accesses to primitive variables. These guarantees + * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not + * cause "word tearing". Accesses to 64-bit array elements may be two 32-bit operations. + * References are never torn regardless of the number of bits used to represent them. */ -void MemmoveWords(void* dst, const void* src, size_t n) { - DCHECK_EQ((((uintptr_t) dst | (uintptr_t) src | n) & 0x01), 0U); - - char* d = reinterpret_cast<char*>(dst); - const char* s = reinterpret_cast<const char*>(src); - size_t copyCount; - - // If the source and destination pointers are the same, this is - // an expensive no-op. Testing for an empty move now allows us - // to skip a check later. - if (n == 0 || d == s) { - return; - } - - // Determine if the source and destination buffers will overlap if - // we copy data forward (i.e. *dst++ = *src++). - // - // It's okay if the destination buffer starts before the source and - // there is some overlap, because the reader is always ahead of the - // writer. - if (LIKELY((d < s) || ((size_t)(d - s) >= n))) { - // Copy forward. We prefer 32-bit loads and stores even for 16-bit - // data, so sort that out. - if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) { - // Not 32-bit aligned. Two possibilities: - // (1) Congruent, we can align to 32-bit by copying one 16-bit val - // (2) Non-congruent, we can do one of: - // a. copy whole buffer as a series of 16-bit values - // b. load/store 32 bits, using shifts to ensure alignment - // c. just copy the as 32-bit values and assume the CPU - // will do a reasonable job - // - // We're currently using (a), which is suboptimal. - if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) { - copyCount = n; - } else { - copyCount = 2; - } - n -= copyCount; - copyCount /= sizeof(uint16_t); - - while (copyCount--) { - *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s); - d += sizeof(uint16_t); - s += sizeof(uint16_t); - } - } - - // Copy 32-bit aligned words. - copyCount = n / sizeof(uint32_t); - while (copyCount--) { - *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s); - d += sizeof(uint32_t); - s += sizeof(uint32_t); - } - - // Check for leftovers. Either we finished exactly, or we have one remaining 16-bit chunk. - if ((n & 0x02) != 0) { - *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s); - } - } else { - // Copy backward, starting at the end. - d += n; - s += n; - - if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) { - // try for 32-bit alignment. - if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) { - copyCount = n; - } else { - copyCount = 2; - } - n -= copyCount; - copyCount /= sizeof(uint16_t); - - while (copyCount--) { - d -= sizeof(uint16_t); - s -= sizeof(uint16_t); - *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s); - } - } - - // Copy 32-bit aligned words. - copyCount = n / sizeof(uint32_t); - while (copyCount--) { - d -= sizeof(uint32_t); - s -= sizeof(uint32_t); - *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s); - } - - // Copy leftovers. - if ((n & 0x02) != 0) { - d -= sizeof(uint16_t); - s -= sizeof(uint16_t); - *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s); - } - } -} - -#define move16 MemmoveWords -#define move32 MemmoveWords - -namespace art { static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -178,168 +42,132 @@ static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror:: "%s of type %s is not an array", identifier, actualType.c_str()); } -static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) { +static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, + jint dstPos, jint length) { + // The API is defined in terms of length, but length is somewhat overloaded so we use count. + const jint count = length; ScopedFastNativeObjectAccess soa(env); // Null pointer checks. - if (UNLIKELY(javaSrc == NULL)) { - ThrowNullPointerException(NULL, "src == null"); + if (UNLIKELY(javaSrc == nullptr)) { + ThrowNullPointerException(nullptr, "src == null"); return; } - if (UNLIKELY(javaDst == NULL)) { - ThrowNullPointerException(NULL, "dst == null"); + if (UNLIKELY(javaDst == nullptr)) { + ThrowNullPointerException(nullptr, "dst == null"); return; } // Make sure source and destination are both arrays. mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc); - mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst); if (UNLIKELY(!srcObject->IsArrayInstance())) { ThrowArrayStoreException_NotAnArray("source", srcObject); return; } + mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst); if (UNLIKELY(!dstObject->IsArrayInstance())) { ThrowArrayStoreException_NotAnArray("destination", dstObject); return; } mirror::Array* srcArray = srcObject->AsArray(); mirror::Array* dstArray = dstObject->AsArray(); - mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); - mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); // Bounds checking. - if (UNLIKELY(srcPos < 0 || dstPos < 0 || length < 0 || srcPos > srcArray->GetLength() - length || dstPos > dstArray->GetLength() - length)) { + if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) || + UNLIKELY(srcPos > srcArray->GetLength() - count) || + UNLIKELY(dstPos > dstArray->GetLength() - count)) { ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;", "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", - srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, length); + srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, + count); return; } - // Handle primitive arrays. - if (srcComponentType->IsPrimitive() || dstComponentType->IsPrimitive()) { - // If one of the arrays holds a primitive type the other array must hold the exact same type. - if (UNLIKELY(srcComponentType != dstComponentType)) { - std::string srcType(PrettyTypeOf(srcArray)); - std::string dstType(PrettyTypeOf(dstArray)); - ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); - soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;", - "Incompatible types: src=%s, dst=%s", - srcType.c_str(), dstType.c_str()); - return; - } - - size_t width = srcArray->GetClass()->GetComponentSize(); - uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width)); - const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width)); - - switch (width) { - case 1: - memmove(dstBytes + dstPos, srcBytes + srcPos, length); - break; - case 2: - move16(dstBytes + dstPos * 2, srcBytes + srcPos * 2, length * 2); - break; - case 4: - move32(dstBytes + dstPos * 4, srcBytes + srcPos * 4, length * 4); - break; - case 8: - // We don't need to guarantee atomicity of the entire 64-bit word. - move32(dstBytes + dstPos * 8, srcBytes + srcPos * 8, length * 8); - break; - default: - LOG(FATAL) << "Unknown primitive array type: " << PrettyTypeOf(srcArray); - } - - return; - } - - // Neither class is primitive. Are the types trivially compatible? - const size_t width = sizeof(mirror::Object*); - uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width)); - const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width)); - if (dstArray == srcArray || dstComponentType->IsAssignableFrom(srcComponentType)) { - // Yes. Bulk copy. - COMPILE_ASSERT(sizeof(width) == sizeof(uint32_t), move32_assumes_Object_references_are_32_bit); - move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width); - Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length); - return; - } - - // The arrays are not trivially compatible. However, we may still be able to copy some or all of - // the elements if the source objects are compatible (for example, copying an Object[] to - // String[], the Objects being copied might actually be Strings). - // We can't do a bulk move because that would introduce a check-use race condition, so we copy - // elements one by one. - - // We already dealt with overlapping copies, so we don't need to cope with that case below. - CHECK_NE(dstArray, srcArray); - - mirror::Object* const * srcObjects = - reinterpret_cast<mirror::Object* const *>(srcBytes + srcPos * width); - mirror::Object** dstObjects = reinterpret_cast<mirror::Object**>(dstBytes + dstPos * width); - mirror::Class* dstClass = dstArray->GetClass()->GetComponentType(); - - // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that - // we know is assignable to the destination array's component type. - mirror::Class* lastAssignableElementClass = dstClass; - - mirror::Object* o = NULL; - int i = 0; - for (; i < length; ++i) { - o = srcObjects[i]; - if (o != NULL) { - mirror::Class* oClass = o->GetClass(); - if (lastAssignableElementClass == oClass) { - dstObjects[i] = o; - } else if (dstClass->IsAssignableFrom(oClass)) { - lastAssignableElementClass = oClass; - dstObjects[i] = o; - } else { - // Can't put this element into the array. - break; + mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); + mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); + Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType(); + + if (LIKELY(srcComponentType == dstComponentType)) { + // Trivial assignability. + switch (dstComponentPrimitiveType) { + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable, cannot have arrays of type void"; + return; + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U); + dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); + return; + case Primitive::kPrimChar: + case Primitive::kPrimShort: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U); + dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); + return; + case Primitive::kPrimInt: + case Primitive::kPrimFloat: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U); + dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); + return; + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U); + dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); + return; + case Primitive::kPrimNot: { + mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>(); + mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>(); + dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); + return; } - } else { - dstObjects[i] = NULL; + default: + LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray); + return; } } - - Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length); - if (UNLIKELY(i != length)) { - std::string actualSrcType(PrettyTypeOf(o)); + // If one of the arrays holds a primitive type the other array must hold the exact same type. + if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) || + srcComponentType->IsPrimitive())) { + std::string srcType(PrettyTypeOf(srcArray)); std::string dstType(PrettyTypeOf(dstArray)); ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;", - "source[%d] of type %s cannot be stored in destination array of type %s", - srcPos + i, actualSrcType.c_str(), dstType.c_str()); + "Incompatible types: src=%s, dst=%s", + srcType.c_str(), dstType.c_str()); + return; + } + // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove. + mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>(); + mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>(); + // If we're assigning into say Object[] then we don't need per element checks. + if (dstComponentType->IsAssignableFrom(srcComponentType)) { + dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count); return; } + dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true); } -static void System_arraycopyCharUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) { +static void System_arraycopyCharUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, + jobject javaDst, jint dstPos, jint count) { ScopedFastNativeObjectAccess soa(env); - DCHECK(javaSrc != NULL); - DCHECK(javaDst != NULL); mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc); mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst); - DCHECK(srcObject->IsArrayInstance()); - DCHECK(dstObject->IsArrayInstance()); + DCHECK(srcObject != nullptr); + DCHECK(dstObject != nullptr); mirror::Array* srcArray = srcObject->AsArray(); mirror::Array* dstArray = dstObject->AsArray(); - DCHECK(srcPos >= 0 && dstPos >= 0 && length >= 0 && - srcPos + length <= srcArray->GetLength() && dstPos + length <= dstArray->GetLength()); - DCHECK_EQ(srcArray->GetClass()->GetComponentType(), dstArray->GetClass()->GetComponentType()); - DCHECK(srcArray->GetClass()->GetComponentType()->IsPrimitive()); - DCHECK(dstArray->GetClass()->GetComponentType()->IsPrimitive()); - DCHECK_EQ(srcArray->GetClass()->GetComponentSize(), static_cast<size_t>(2)); - DCHECK_EQ(dstArray->GetClass()->GetComponentSize(), static_cast<size_t>(2)); - uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(2)); - const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(2)); - move16(dstBytes + dstPos * 2, srcBytes + srcPos * 2, length * 2); + DCHECK_GE(srcPos, 0); + DCHECK_GE(dstPos, 0); + DCHECK_GE(count, 0); + DCHECK_LE(srcPos + count, srcArray->GetLength()); + DCHECK_LE(dstPos + count, dstArray->GetLength()); + DCHECK_EQ(srcArray->GetClass(), dstArray->GetClass()); + DCHECK_EQ(srcArray->GetClass()->GetComponentType()->GetPrimitiveType(), Primitive::kPrimChar); + dstArray->AsCharArray()->Memmove(dstPos, srcArray->AsCharArray(), srcPos, count); } static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) { - if (javaObject == nullptr) { + if (UNLIKELY(javaObject == nullptr)) { return 0; } ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index b5fc7e7be5..6c22003396 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "atomic.h" #include "gc/accounting/card_table-inl.h" #include "jni_internal.h" #include "mirror/object.h" @@ -23,40 +22,30 @@ namespace art { -static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint expectedValue, jint newValue) { +static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jint expectedValue, jint newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); - byte* raw_addr = reinterpret_cast<byte*>(obj) + offset; - volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr); - // Note: android_atomic_release_cas() returns 0 on success, not failure. - int result = android_atomic_release_cas(expectedValue, newValue, address); - return (result == 0) ? JNI_TRUE : JNI_FALSE; + bool success = obj->CasField32(MemberOffset(offset), expectedValue, newValue); + return success ? JNI_TRUE : JNI_FALSE; } -static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong expectedValue, jlong newValue) { +static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jlong expectedValue, jlong newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); - byte* raw_addr = reinterpret_cast<byte*>(obj) + offset; - volatile int64_t* address = reinterpret_cast<volatile int64_t*>(raw_addr); - // Note: android_atomic_cmpxchg() returns 0 on success, not failure. - bool success = QuasiAtomic::Cas64(expectedValue, newValue, address); + bool success = obj->CasField64(MemberOffset(offset), expectedValue, newValue); return success ? JNI_TRUE : JNI_FALSE; } -static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaExpectedValue, jobject javaNewValue) { +static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jobject javaExpectedValue, jobject javaNewValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue); mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue); - byte* raw_addr = reinterpret_cast<byte*>(obj) + offset; - int32_t* address = reinterpret_cast<int32_t*>(raw_addr); - // Note: android_atomic_cmpxchg() returns 0 on success, not failure. - int result = android_atomic_release_cas(reinterpret_cast<int32_t>(expectedValue), - reinterpret_cast<int32_t>(newValue), address); - if (result == 0) { - Runtime::Current()->GetHeap()->WriteBarrierField(obj, MemberOffset(offset), newValue); - } - return (result == 0) ? JNI_TRUE : JNI_FALSE; + bool success = obj->CasFieldObject(MemberOffset(offset), expectedValue, newValue); + return success ? JNI_TRUE : JNI_FALSE; } static jint Unsafe_getInt(JNIEnv* env, jobject, jobject javaObj, jlong offset) { @@ -77,13 +66,15 @@ static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, j obj->SetField32(MemberOffset(offset), newValue, false); } -static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) { +static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jint newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); obj->SetField32(MemberOffset(offset), newValue, true); } -static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) { +static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jint newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); QuasiAtomic::MembarStoreStore(); @@ -108,13 +99,15 @@ static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, obj->SetField64(MemberOffset(offset), newValue, false); } -static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) { +static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jlong newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); obj->SetField64(MemberOffset(offset), newValue, true); } -static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) { +static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jlong newValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); QuasiAtomic::MembarStoreStore(); @@ -124,32 +117,35 @@ static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong o static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); - mirror::Object* value = obj->GetFieldObject<mirror::Object*>(MemberOffset(offset), true); + mirror::Object* value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset), true); return soa.AddLocalReference<jobject>(value); } static jobject Unsafe_getObject(JNIEnv* env, jobject, jobject javaObj, jlong offset) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); - mirror::Object* value = obj->GetFieldObject<mirror::Object*>(MemberOffset(offset), false); + mirror::Object* value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset), false); return soa.AddLocalReference<jobject>(value); } -static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) { +static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jobject javaNewValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue); obj->SetFieldObject(MemberOffset(offset), newValue, false); } -static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) { +static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jobject javaNewValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue); obj->SetFieldObject(MemberOffset(offset), newValue, true); } -static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) { +static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, + jobject javaNewValue) { ScopedFastNativeObjectAccess soa(env); mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index be88204818..0f380ad695 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -66,16 +66,16 @@ OatFile* OatFile::Open(const std::string& filename, std::string* error_msg) { CHECK(!filename.empty()) << location; CheckLocation(filename); -#ifdef ART_USE_PORTABLE_COMPILER - // If we are using PORTABLE, use dlopen to deal with relocations. - // - // We use our own ELF loader for Quick to deal with legacy apps that - // open a generated dex file by name, remove the file, then open - // another generated dex file with the same name. http://b/10614658 - if (executable) { - return OpenDlopen(filename, location, requested_base, error_msg); + if (kUsePortableCompiler) { + // If we are using PORTABLE, use dlopen to deal with relocations. + // + // We use our own ELF loader for Quick to deal with legacy apps that + // open a generated dex file by name, remove the file, then open + // another generated dex file with the same name. http://b/10614658 + if (executable) { + return OpenDlopen(filename, location, requested_base, error_msg); + } } -#endif // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons: // // On target, dlopen may fail when compiling due to selinux restrictions on installd. @@ -503,51 +503,40 @@ OatFile::OatMethod::OatMethod(const byte* base, mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset), native_gc_map_offset_(gc_map_offset) { -#ifndef NDEBUG - if (mapping_table_offset_ != 0) { // implies non-native, non-stub code - if (vmap_table_offset_ == 0) { - DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + - __builtin_popcount(fp_spill_mask_))); + if (kIsDebugBuild) { + if (mapping_table_offset_ != 0) { // implies non-native, non-stub code + if (vmap_table_offset_ == 0) { + CHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + + __builtin_popcount(fp_spill_mask_))); + } else { + VmapTable vmap_table(reinterpret_cast<const uint8_t*>(begin_ + vmap_table_offset_)); + + CHECK_EQ(vmap_table.Size(), static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + + __builtin_popcount(fp_spill_mask_))); + } } else { - VmapTable vmap_table(reinterpret_cast<const uint8_t*>(begin_ + vmap_table_offset_)); - - DCHECK_EQ(vmap_table.Size(), static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + - __builtin_popcount(fp_spill_mask_))); + CHECK_EQ(vmap_table_offset_, 0U); } - } else { - DCHECK_EQ(vmap_table_offset_, 0U); } -#endif } OatFile::OatMethod::~OatMethod() {} -const void* OatFile::OatMethod::GetCode() const { - return GetOatPointer<const void*>(code_offset_); -} - -uint32_t OatFile::OatMethod::GetCodeSize() const { -#if defined(ART_USE_PORTABLE_COMPILER) - // TODO: With Quick, we store the size before the code. With - // Portable, the code is in a .o file we don't manage ourselves. ELF - // symbols do have a concept of size, so we could capture that and - // store it somewhere, such as the OatMethod. - return 0; -#else - uintptr_t code = reinterpret_cast<uint32_t>(GetCode()); +uint32_t OatFile::OatMethod::GetQuickCodeSize() const { + uintptr_t code = reinterpret_cast<uintptr_t>(GetQuickCode()); if (code == 0) { return 0; } // TODO: make this Thumb2 specific code &= ~0x1; return reinterpret_cast<uint32_t*>(code)[-1]; -#endif } void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const { CHECK(method != NULL); - method->SetEntryPointFromCompiledCode(GetCode()); + method->SetEntryPointFromPortableCompiledCode(GetPortableCode()); + method->SetEntryPointFromQuickCompiledCode(GetQuickCode()); method->SetFrameSizeInBytes(frame_size_in_bytes_); method->SetCoreSpillMask(core_spill_mask_); method->SetFpSpillMask(fp_spill_mask_); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 887a9d1b63..d6e8dc07f2 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -97,8 +97,30 @@ class OatFile { return native_gc_map_offset_; } - const void* GetCode() const; - uint32_t GetCodeSize() const; + const void* GetPortableCode() const { + // TODO: encode whether code is portable/quick in flags within OatMethod. + if (kUsePortableCompiler) { + return GetOatPointer<const void*>(code_offset_); + } else { + return nullptr; + } + } + + const void* GetQuickCode() const { + if (kUsePortableCompiler) { + return nullptr; + } else { + return GetOatPointer<const void*>(code_offset_); + } + } + + uint32_t GetPortableCodeSize() const { + // TODO: With Quick, we store the size before the code. With Portable, the code is in a .o + // file we don't manage ourselves. ELF symbols do have a concept of size, so we could capture + // that and store it somewhere, such as the OatMethod. + return 0; + } + uint32_t GetQuickCodeSize() const; const uint8_t* GetMappingTable() const { return GetOatPointer<const uint8_t*>(mapping_table_offset_); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 407aa650cc..0451f5d5ed 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -69,30 +69,29 @@ class ObjectLock { class ClassHelper { public: - explicit ClassHelper(const mirror::Class* c ) + explicit ClassHelper(mirror::Class* c ) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : interface_type_list_(NULL), - klass_(NULL) { - if (c != NULL) { + : interface_type_list_(nullptr), klass_(nullptr) { + if (c != nullptr) { ChangeClass(c); } } - void ChangeClass(const mirror::Class* new_c) + void ChangeClass(mirror::Class* new_c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(new_c != NULL) << "klass_=" << klass_; // Log what we were changing from if any + CHECK(new_c != nullptr) << "klass_=" << klass_; // Log what we were changing from if any if (!new_c->IsClass()) { LOG(FATAL) << "new_c=" << new_c << " cc " << new_c->GetClass() << " ccc " - << ((new_c->GetClass() != nullptr) ? new_c->GetClass()->GetClass() : NULL); + << ((new_c->GetClass() != nullptr) ? new_c->GetClass()->GetClass() : nullptr); } klass_ = new_c; - interface_type_list_ = NULL; + interface_type_list_ = nullptr; } // The returned const char* is only guaranteed to be valid for the lifetime of the ClassHelper. // If you need it longer, copy it into a std::string. const char* GetDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(klass_ != NULL); + CHECK(klass_ != nullptr); if (UNLIKELY(klass_->IsArrayClass())) { return GetArrayDescriptor(); } else if (UNLIKELY(klass_->IsPrimitive())) { @@ -109,8 +108,8 @@ class ClassHelper { const char* GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string result("["); - const mirror::Class* saved_klass = klass_; - CHECK(saved_klass != NULL); + mirror::Class* saved_klass = klass_; + CHECK(saved_klass != nullptr); ChangeClass(klass_->GetComponentType()); result += GetDescriptor(); ChangeClass(saved_klass); @@ -128,7 +127,7 @@ class ClassHelper { } uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(klass_ != NULL); + DCHECK(klass_ != nullptr); if (klass_->IsPrimitive()) { return 0; } else if (klass_->IsArrayClass()) { @@ -137,7 +136,7 @@ class ClassHelper { return klass_->GetIfTable()->GetLength(); } else { const DexFile::TypeList* interfaces = GetInterfaceTypeList(); - if (interfaces == NULL) { + if (interfaces == nullptr) { return 0; } else { return interfaces->Size(); @@ -147,7 +146,7 @@ class ClassHelper { uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(klass_ != NULL); + DCHECK(klass_ != nullptr); DCHECK(!klass_->IsPrimitive()); DCHECK(!klass_->IsArrayClass()); return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_; @@ -155,7 +154,7 @@ class ClassHelper { mirror::Class* GetDirectInterface(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(klass_ != NULL); + DCHECK(klass_ != nullptr); DCHECK(!klass_->IsPrimitive()); if (klass_->IsArrayClass()) { if (idx == 0) { @@ -169,9 +168,9 @@ class ClassHelper { } else { uint16_t type_idx = GetDirectInterfaceTypeIdx(idx); mirror::Class* interface = GetDexCache()->GetResolvedType(type_idx); - if (interface == NULL) { + if (interface == nullptr) { interface = GetClassLinker()->ResolveType(GetDexFile(), type_idx, klass_); - CHECK(interface != NULL || Thread::Current()->IsExceptionPending()); + CHECK(interface != nullptr || Thread::Current()->IsExceptionPending()); } return interface; } @@ -181,13 +180,13 @@ class ClassHelper { std::string descriptor(GetDescriptor()); const DexFile& dex_file = GetDexFile(); const DexFile::ClassDef* dex_class_def = GetClassDef(); - CHECK(dex_class_def != NULL); + CHECK(dex_class_def != nullptr); return dex_file.GetSourceFile(*dex_class_def); } std::string GetLocation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::DexCache* dex_cache = GetDexCache(); - if (dex_cache != NULL && !klass_->IsProxyClass()) { + if (dex_cache != nullptr && !klass_->IsProxyClass()) { return dex_cache->GetLocation()->ToModifiedUtf8(); } else { // Arrays and proxies are generated and have no corresponding dex file location. @@ -207,9 +206,9 @@ class ClassHelper { const DexFile::TypeList* GetInterfaceTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::TypeList* result = interface_type_list_; - if (result == NULL) { + if (result == nullptr) { const DexFile::ClassDef* class_def = GetClassDef(); - if (class_def != NULL) { + if (class_def != nullptr) { result = GetDexFile().GetInterfacesList(*class_def); interface_type_list_ = result; } @@ -222,7 +221,7 @@ class ClassHelper { } const DexFile::TypeList* interface_type_list_; - const mirror::Class* klass_; + mirror::Class* klass_; std::string descriptor_; DISALLOW_COPY_AND_ASSIGN(ClassHelper); @@ -230,11 +229,11 @@ class ClassHelper { class FieldHelper { public: - FieldHelper() : field_(NULL) {} - explicit FieldHelper(const mirror::ArtField* f) : field_(f) {} + FieldHelper() : field_(nullptr) {} + explicit FieldHelper(mirror::ArtField* f) : field_(f) {} - void ChangeField(const mirror::ArtField* new_f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(new_f != NULL); + void ChangeField(mirror::ArtField* new_f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(new_f != nullptr); field_ = new_f; } @@ -257,9 +256,9 @@ class FieldHelper { const DexFile& dex_file = GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_); - if (resolve && (type == NULL)) { + if (resolve && (type == nullptr)) { type = GetClassLinker()->ResolveType(field_id.type_idx_, field_); - CHECK(type != NULL || Thread::Current()->IsExceptionPending()); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); } return type; } @@ -320,7 +319,7 @@ class FieldHelper { const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return *GetDexCache()->GetDexFile(); } - const mirror::ArtField* field_; + mirror::ArtField* field_; std::string declaring_class_descriptor_; DISALLOW_COPY_AND_ASSIGN(FieldHelper); @@ -328,20 +327,18 @@ class FieldHelper { class MethodHelper { public: - MethodHelper() - : method_(NULL), shorty_(NULL), - shorty_len_(0) {} + MethodHelper() : method_(nullptr), shorty_(nullptr), shorty_len_(0) {} - explicit MethodHelper(const mirror::ArtMethod* m) + explicit MethodHelper(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : method_(NULL), shorty_(NULL), shorty_len_(0) { + : method_(nullptr), shorty_(nullptr), shorty_len_(0) { SetMethod(m); } void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(new_m != NULL); + DCHECK(new_m != nullptr); SetMethod(new_m); - shorty_ = NULL; + shorty_ = nullptr; } const mirror::ArtMethod* GetMethod() const { @@ -381,7 +378,7 @@ class MethodHelper { const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const char* result = shorty_; - if (result == NULL) { + if (result == nullptr) { const DexFile& dex_file = GetDexFile(); result = dex_file.GetMethodShorty(dex_file.GetMethodId(method_->GetDexMethodIndex()), &shorty_len_); @@ -391,7 +388,7 @@ class MethodHelper { } uint32_t GetShortyLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (shorty_ == NULL) { + if (shorty_ == nullptr) { GetShorty(); } return shorty_len_; @@ -529,15 +526,15 @@ class MethodHelper { bool IsResolvedTypeIdx(uint16_t type_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return method_->GetDexCacheResolvedTypes()->Get(type_idx) != NULL; + return method_->GetDexCacheResolvedTypes()->Get(type_idx) != nullptr; } mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::Class* type = method_->GetDexCacheResolvedTypes()->Get(type_idx); - if (type == NULL && resolve) { + if (type == nullptr && resolve) { type = GetClassLinker()->ResolveType(type_idx, method_); - CHECK(type != NULL || Thread::Current()->IsExceptionPending()); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); } return type; } @@ -563,7 +560,7 @@ class MethodHelper { mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::String* s = method_->GetDexCacheStrings()->Get(string_idx); - if (UNLIKELY(s == NULL)) { + if (UNLIKELY(s == nullptr)) { SirtRef<mirror::DexCache> dex_cache(Thread::Current(), GetDexCache()); s = GetClassLinker()->ResolveString(GetDexFile(), string_idx, dex_cache); } @@ -613,13 +610,13 @@ class MethodHelper { private: // Set the method_ field, for proxy methods looking up the interface method via the resolved // methods table. - void SetMethod(const mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (method != NULL) { + void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (method != nullptr) { mirror::Class* klass = method->GetDeclaringClass(); if (UNLIKELY(klass->IsProxyClass())) { mirror::ArtMethod* interface_method = method->GetDexCacheResolvedMethods()->Get(method->GetDexMethodIndex()); - DCHECK(interface_method != NULL); + DCHECK(interface_method != nullptr); DCHECK(interface_method == GetClassLinker()->FindMethodForProxy(klass, method)); method = interface_method; } @@ -631,7 +628,7 @@ class MethodHelper { return Runtime::Current()->GetClassLinker(); } - const mirror::ArtMethod* method_; + mirror::ArtMethod* method_; const char* shorty_; uint32_t shorty_len_; diff --git a/runtime/offsets.h b/runtime/offsets.h index 94ae805e4a..e2dba9d97d 100644 --- a/runtime/offsets.h +++ b/runtime/offsets.h @@ -22,7 +22,7 @@ namespace art { -// Allow the meaning of offsets to be strongly typed +// Allow the meaning of offsets to be strongly typed. class Offset { public: explicit Offset(size_t val) : val_(val) {} @@ -37,7 +37,7 @@ class Offset { }; std::ostream& operator<<(std::ostream& os, const Offset& offs); -// Offsets relative to the current frame +// Offsets relative to the current frame. class FrameOffset : public Offset { public: explicit FrameOffset(size_t val) : Offset(val) {} @@ -45,13 +45,13 @@ class FrameOffset : public Offset { bool operator<(FrameOffset other) const { return val_ < other.val_; } }; -// Offsets relative to the current running thread +// Offsets relative to the current running thread. class ThreadOffset : public Offset { public: explicit ThreadOffset(size_t val) : Offset(val) {} }; -// Offsets relative to an object +// Offsets relative to an object. class MemberOffset : public Offset { public: explicit MemberOffset(size_t val) : Offset(val) {} diff --git a/runtime/primitive.h b/runtime/primitive.h index 5e07311073..b436bd2165 100644 --- a/runtime/primitive.h +++ b/runtime/primitive.h @@ -21,6 +21,7 @@ #include "base/logging.h" #include "base/macros.h" +#include "mirror/object_reference.h" namespace art { namespace mirror { @@ -78,7 +79,7 @@ class Primitive { case kPrimFloat: return 4; case kPrimLong: case kPrimDouble: return 8; - case kPrimNot: return sizeof(mirror::Object*); + case kPrimNot: return sizeof(mirror::HeapReference<mirror::Object>); default: LOG(FATAL) << "Invalid type " << static_cast<int>(type); return 0; diff --git a/runtime/profiler.cc b/runtime/profiler.cc index 365c9c34d7..20e08b82b3 100644 --- a/runtime/profiler.cc +++ b/runtime/profiler.cc @@ -455,9 +455,7 @@ void ProfileSampleResults::Clear() { } uint32_t ProfileSampleResults::Hash(mirror::ArtMethod* method) { - uint32_t value = reinterpret_cast<uint32_t>(method); - value >>= 2; - return value % kHashSize; + return (PointerToLowMemUInt32(method) >> 3) % kHashSize; } } // namespace art diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc index 6f65bff899..b5ef735059 100644 --- a/runtime/reference_table.cc +++ b/runtime/reference_table.cc @@ -59,7 +59,7 @@ void ReferenceTable::Remove(mirror::Object* obj) { // If "obj" is an array, return the number of elements in the array. // Otherwise, return zero. -static size_t GetElementCount(const mirror::Object* obj) { +static size_t GetElementCount(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArrayInstance()) { return 0; } @@ -67,7 +67,7 @@ static size_t GetElementCount(const mirror::Object* obj) { } struct ObjectComparator { - bool operator()(const mirror::Object* obj1, const mirror::Object* obj2) + bool operator()(mirror::Object* obj1, mirror::Object* obj2) // TODO: enable analysis when analysis can work with the STL. NO_THREAD_SAFETY_ANALYSIS { Locks::mutator_lock_->AssertSharedHeld(Thread::Current()); @@ -105,7 +105,7 @@ struct ObjectComparator { // Pass in the number of elements in the array (or 0 if this is not an // array object), and the number of additional objects that are identical // or equivalent to the original. -static void DumpSummaryLine(std::ostream& os, const mirror::Object* obj, size_t element_count, +static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count, int identical, int equiv) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (obj == NULL) { @@ -159,7 +159,7 @@ void ReferenceTable::Dump(std::ostream& os, const Table& entries) { } os << " Last " << (count - first) << " entries (of " << count << "):\n"; for (int idx = count - 1; idx >= first; --idx) { - const mirror::Object* ref = entries[idx]; + mirror::Object* ref = entries[idx]; if (ref == NULL) { continue; } @@ -212,8 +212,8 @@ void ReferenceTable::Dump(std::ostream& os, const Table& entries) { size_t equiv = 0; size_t identical = 0; for (size_t idx = 1; idx < count; idx++) { - const mirror::Object* prev = sorted_entries[idx-1]; - const mirror::Object* current = sorted_entries[idx]; + mirror::Object* prev = sorted_entries[idx-1]; + mirror::Object* current = sorted_entries[idx]; size_t element_count = GetElementCount(prev); if (current == prev) { // Same reference, added more than once. diff --git a/runtime/runtime.cc b/runtime/runtime.cc index bcd3d31474..4e90478728 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -31,6 +31,7 @@ #include "arch/arm/registers_arm.h" #include "arch/mips/registers_mips.h" #include "arch/x86/registers_x86.h" +#include "arch/x86_64/registers_x86_64.h" #include "atomic.h" #include "class_linker.h" #include "debugger.h" @@ -75,19 +76,27 @@ Runtime::Runtime() is_zygote_(false), is_concurrent_gc_enabled_(true), is_explicit_gc_disabled_(false), + compiler_filter_(kSpeed), + huge_method_threshold_(0), + large_method_threshold_(0), + small_method_threshold_(0), + tiny_method_threshold_(0), + num_dex_methods_threshold_(0), + sea_ir_mode_(false), default_stack_size_(0), - heap_(NULL), + heap_(nullptr), max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation), - monitor_list_(NULL), - thread_list_(NULL), - intern_table_(NULL), - class_linker_(NULL), - signal_catcher_(NULL), - java_vm_(NULL), - pre_allocated_OutOfMemoryError_(NULL), - resolution_method_(NULL), - imt_conflict_method_(NULL), - default_imt_(NULL), + monitor_list_(nullptr), + monitor_pool_(nullptr), + thread_list_(nullptr), + intern_table_(nullptr), + class_linker_(nullptr), + signal_catcher_(nullptr), + java_vm_(nullptr), + pre_allocated_OutOfMemoryError_(nullptr), + resolution_method_(nullptr), + imt_conflict_method_(nullptr), + default_imt_(nullptr), method_verifiers_lock_("Method verifiers lock"), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), @@ -95,19 +104,25 @@ Runtime::Runtime() shutting_down_started_(false), started_(false), finished_starting_(false), - vfprintf_(NULL), - exit_(NULL), - abort_(NULL), + vfprintf_(nullptr), + exit_(nullptr), + abort_(nullptr), stats_enabled_(false), - method_trace_(0), + profile_(false), + profile_period_s_(0), + profile_duration_s_(0), + profile_interval_us_(0), + profile_backoff_coefficient_(0), + method_trace_(false), method_trace_file_size_(0), instrumentation_(), use_compile_time_class_path_(false), - main_thread_group_(NULL), - system_thread_group_(NULL), - system_class_loader_(NULL) { + main_thread_group_(nullptr), + system_thread_group_(nullptr), + system_class_loader_(nullptr), + dump_gc_performance_on_shutdown_(false) { for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { - callee_save_methods_[i] = NULL; + callee_save_methods_[i] = nullptr; } } @@ -141,6 +156,7 @@ Runtime::~Runtime() { // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended. delete thread_list_; delete monitor_list_; + delete monitor_pool_; delete class_linker_; delete heap_; delete intern_table_; @@ -149,8 +165,8 @@ Runtime::~Runtime() { QuasiAtomic::Shutdown(); verifier::MethodVerifier::Shutdown(); // TODO: acquire a static mutex on Runtime to avoid racing. - CHECK(instance_ == NULL || instance_ == this); - instance_ = NULL; + CHECK(instance_ == nullptr || instance_ == this); + instance_ = nullptr; } struct AbortState { @@ -976,6 +992,7 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { max_spins_before_thin_lock_inflation_ = options->max_spins_before_thin_lock_inflation_; monitor_list_ = new MonitorList; + monitor_pool_ = MonitorPool::Create(); thread_list_ = new ThreadList; intern_table_ = new InternTable; @@ -1345,40 +1362,53 @@ mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* c mirror::ArtMethod* Runtime::CreateImtConflictMethod() { Thread* self = Thread::Current(); - Runtime* r = Runtime::Current(); - ClassLinker* cl = r->GetClassLinker(); - SirtRef<mirror::ArtMethod> method(self, cl->AllocArtMethod(self)); + Runtime* runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self)); method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod()); - // TODO: use a special method for imt conflict method saves + // TODO: use a special method for imt conflict method saves. method->SetDexMethodIndex(DexFile::kDexNoIndex); // When compiling, the code pointer will get set later when the image is loaded. - method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetImtConflictTrampoline(cl)); + if (runtime->IsCompiler()) { + method->SetEntryPointFromPortableCompiledCode(nullptr); + method->SetEntryPointFromQuickCompiledCode(nullptr); + } else { + method->SetEntryPointFromPortableCompiledCode(GetPortableImtConflictTrampoline(class_linker)); + method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictTrampoline(class_linker)); + } return method.get(); } mirror::ArtMethod* Runtime::CreateResolutionMethod() { Thread* self = Thread::Current(); - Runtime* r = Runtime::Current(); - ClassLinker* cl = r->GetClassLinker(); - SirtRef<mirror::ArtMethod> method(self, cl->AllocArtMethod(self)); + Runtime* runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self)); method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod()); // TODO: use a special method for resolution method saves method->SetDexMethodIndex(DexFile::kDexNoIndex); // When compiling, the code pointer will get set later when the image is loaded. - method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetResolutionTrampoline(cl)); + if (runtime->IsCompiler()) { + method->SetEntryPointFromPortableCompiledCode(nullptr); + method->SetEntryPointFromQuickCompiledCode(nullptr); + } else { + method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline(class_linker)); + method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline(class_linker)); + } return method.get(); } mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type) { Thread* self = Thread::Current(); - Runtime* r = Runtime::Current(); - ClassLinker* cl = r->GetClassLinker(); - SirtRef<mirror::ArtMethod> method(self, cl->AllocArtMethod(self)); + Runtime* runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + SirtRef<mirror::ArtMethod> method(self, class_linker->AllocArtMethod(self)); method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod()); // TODO: use a special method for callee saves method->SetDexMethodIndex(DexFile::kDexNoIndex); - method->SetEntryPointFromCompiledCode(NULL); + method->SetEntryPointFromPortableCompiledCode(nullptr); + method->SetEntryPointFromQuickCompiledCode(nullptr); if ((instruction_set == kThumb2) || (instruction_set == kArm)) { uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) | (1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11); @@ -1428,8 +1458,23 @@ mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_se method->SetFrameSizeInBytes(frame_size); method->SetCoreSpillMask(core_spills); method->SetFpSpillMask(0); + } else if (instruction_set == kX86_64) { + uint32_t ref_spills = + (1 << art::x86_64::RBP) | (1 << art::x86_64::RSI) | (1 << art::x86_64::RDI) | + (1 << art::x86_64::R8) | (1 << art::x86_64::R9) | (1 << art::x86_64::R10) | + (1 << art::x86_64::R11) | (1 << art::x86_64::R12) | (1 << art::x86_64::R13) | + (1 << art::x86_64::R14) | (1 << art::x86_64::R15); + uint32_t arg_spills = + (1 << art::x86_64::RCX) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RBX); + uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) | + (1 << art::x86::kNumberOfCpuRegisters); // fake return address callee save + size_t frame_size = RoundUp((__builtin_popcount(core_spills) /* gprs */ + + 1 /* Method* */) * kPointerSize, kStackAlignment); + method->SetFrameSizeInBytes(frame_size); + method->SetCoreSpillMask(core_spills); + method->SetFpSpillMask(0); } else { - UNIMPLEMENTED(FATAL); + UNIMPLEMENTED(FATAL) << instruction_set; } return method.get(); } diff --git a/runtime/runtime.h b/runtime/runtime.h index 9d4863151f..557ba2cdde 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -61,6 +61,7 @@ class DexFile; class InternTable; struct JavaVMExt; class MonitorList; +class MonitorPool; class SignalCatcher; class ThreadList; class Trace; @@ -314,6 +315,10 @@ class Runtime { return monitor_list_; } + MonitorPool* GetMonitorPool() const { + return monitor_pool_; + } + mirror::Throwable* GetPreAllocatedOutOfMemoryError() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -524,6 +529,7 @@ class Runtime { // The number of spins that are done before thread suspension is used to forcibly inflate. size_t max_spins_before_thin_lock_inflation_; MonitorList* monitor_list_; + MonitorPool* monitor_pool_; ThreadList* thread_list_; diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc index 47b72e9b17..d8f408ab6c 100644 --- a/runtime/runtime_linux.cc +++ b/runtime/runtime_linux.cc @@ -133,7 +133,7 @@ struct UContext { void Dump(std::ostream& os) { // TODO: support non-x86 hosts (not urgent because this code doesn't run on targets). -#if defined(__APPLE__) +#if defined(__APPLE__) && defined(__i386__) DumpRegister32(os, "eax", context->__ss.__eax); DumpRegister32(os, "ebx", context->__ss.__ebx); DumpRegister32(os, "ecx", context->__ss.__ecx); @@ -159,7 +159,7 @@ struct UContext { os << '\n'; DumpRegister32(os, "gs", context->__ss.__gs); DumpRegister32(os, "ss", context->__ss.__ss); -#else +#elif defined(__linux__) && defined(__i386__) DumpRegister32(os, "eax", context.gregs[REG_EAX]); DumpRegister32(os, "ebx", context.gregs[REG_EBX]); DumpRegister32(os, "ecx", context.gregs[REG_ECX]); @@ -185,6 +185,8 @@ struct UContext { os << '\n'; DumpRegister32(os, "gs", context.gregs[REG_GS]); DumpRegister32(os, "ss", context.gregs[REG_SS]); +#else + os << "Unknown architecture/word size/OS in ucontext dump"; #endif } diff --git a/runtime/sirt_ref.h b/runtime/sirt_ref.h index 56d81ecacc..3c5e4f88a1 100644 --- a/runtime/sirt_ref.h +++ b/runtime/sirt_ref.h @@ -35,13 +35,17 @@ class SirtRef { DCHECK_EQ(top_sirt, &sirt_); } - T& operator*() const { return *get(); } - T* operator->() const { return get(); } - T* get() const { + T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return *get(); + } + T* operator->() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return get(); + } + T* get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return down_cast<T*>(sirt_.GetReference(0)); } - void reset(T* object = NULL) { + void reset(T* object = nullptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { sirt_.SetReference(0, object); } diff --git a/runtime/stack.cc b/runtime/stack.cc index e583cedb24..fd7d98158a 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -75,7 +75,7 @@ size_t ManagedStack::NumJniShadowFrameReferences() const { return count; } -bool ManagedStack::ShadowFramesContain(mirror::Object** shadow_frame_entry) const { +bool ManagedStack::ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const { for (const ManagedStack* current_fragment = this; current_fragment != NULL; current_fragment = current_fragment->GetLink()) { for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL; @@ -251,7 +251,7 @@ std::string StackVisitor::DescribeLocation() const { return "upcall"; } result += PrettyMethod(m); - result += StringPrintf("' at dex PC 0x%04zx", GetDexPc()); + result += StringPrintf("' at dex PC 0x%04x", GetDexPc()); if (!IsShadowFrame()) { result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc())); } @@ -264,23 +264,23 @@ instrumentation::InstrumentationStackFrame& StackVisitor::GetInstrumentationStac } void StackVisitor::SanityCheckFrame() const { -#ifndef NDEBUG - mirror::ArtMethod* method = GetMethod(); - CHECK(method->GetClass() == mirror::ArtMethod::GetJavaLangReflectArtMethod()); - if (cur_quick_frame_ != NULL) { - method->AssertPcIsWithinCode(cur_quick_frame_pc_); - // Frame sanity. - size_t frame_size = method->GetFrameSizeInBytes(); - CHECK_NE(frame_size, 0u); - // A rough guess at an upper size we expect to see for a frame. The 256 is - // a dex register limit. The 16 incorporates callee save spills and - // outgoing argument set up. - const size_t kMaxExpectedFrameSize = 256 * sizeof(word) + 16; - CHECK_LE(frame_size, kMaxExpectedFrameSize); - size_t return_pc_offset = method->GetReturnPcOffsetInBytes(); - CHECK_LT(return_pc_offset, frame_size); + if (kIsDebugBuild) { + mirror::ArtMethod* method = GetMethod(); + CHECK(method->GetClass() == mirror::ArtMethod::GetJavaLangReflectArtMethod()); + if (cur_quick_frame_ != nullptr) { + method->AssertPcIsWithinQuickCode(cur_quick_frame_pc_); + // Frame sanity. + size_t frame_size = method->GetFrameSizeInBytes(); + CHECK_NE(frame_size, 0u); + // A rough guess at an upper size we expect to see for a frame. The 256 is + // a dex register limit. The 16 incorporates callee save spills and + // outgoing argument set up. + const size_t kMaxExpectedFrameSize = 256 * sizeof(word) + 16; + CHECK_LE(frame_size, kMaxExpectedFrameSize); + size_t return_pc_offset = method->GetReturnPcOffsetInBytes(); + CHECK_LT(return_pc_offset, frame_size); + } } -#endif } void StackVisitor::WalkStack(bool include_transitions) { diff --git a/runtime/stack.h b/runtime/stack.h index 0692390814..8466069108 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -19,8 +19,10 @@ #include "dex_file.h" #include "instrumentation.h" +#include "base/casts.h" #include "base/macros.h" #include "arch/context.h" +#include "mirror/object_reference.h" #include <stdint.h> #include <string> @@ -96,16 +98,33 @@ enum VRegBaseRegNum : int { kVRegNonSpecialTempBaseReg = -3, }; +// A reference from the shadow stack to a MirrorType object within the Java heap. +template<class MirrorType> +class MANAGED StackReference : public mirror::ObjectReference<false, MirrorType> { + public: + StackReference<MirrorType>() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : mirror::ObjectReference<false, MirrorType>(nullptr) {} + + static StackReference<MirrorType> FromMirrorPtr(MirrorType* p) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return StackReference<MirrorType>(p); + } + + private: + StackReference<MirrorType>(MirrorType* p) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : mirror::ObjectReference<false, MirrorType>(p) {} +}; + // ShadowFrame has 3 possible layouts: // - portable - a unified array of VRegs and references. Precise references need GC maps. // - interpreter - separate VRegs and reference arrays. References are in the reference array. // - JNI - just VRegs, but where every VReg holds a reference. class ShadowFrame { public: - // Compute size of ShadowFrame in bytes. + // Compute size of ShadowFrame in bytes assuming it has a reference array. static size_t ComputeSize(uint32_t num_vregs) { return sizeof(ShadowFrame) + (sizeof(uint32_t) * num_vregs) + - (sizeof(mirror::Object*) * num_vregs); + (sizeof(StackReference<mirror::Object>) * num_vregs); } // Create ShadowFrame in heap for deoptimization. @@ -195,22 +214,19 @@ class ShadowFrame { } template <bool kChecked = false> - mirror::Object* GetVRegReference(size_t i) const { + mirror::Object* GetVRegReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_LT(i, NumberOfVRegs()); if (HasReferenceArray()) { - mirror::Object* ref = References()[i]; + mirror::Object* ref = References()[i].AsMirrorPtr(); if (kChecked) { CHECK(VerifyReference(ref)) << "VReg " << i << "(" << ref << ") is in protected space, reference array " << true; } - // If the vreg reference is not equal to the vreg then the vreg reference is stale. - if (UNLIKELY(reinterpret_cast<uint32_t>(ref) != vregs_[i])) { - return nullptr; - } return ref; } else { - const uint32_t* vreg = &vregs_[i]; - mirror::Object* ref = *reinterpret_cast<mirror::Object* const*>(vreg); + const uint32_t* vreg_ptr = &vregs_[i]; + mirror::Object* ref = + reinterpret_cast<const StackReference<mirror::Object>*>(vreg_ptr)->AsMirrorPtr(); if (kChecked) { CHECK(VerifyReference(ref)) << "VReg " << i << "(" << ref << ") is in protected space, reference array " << false; @@ -231,7 +247,7 @@ class ShadowFrame { // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array. if (kMovingCollector && HasReferenceArray()) { - References()[i] = nullptr; + References()[i].Clear(); } } @@ -242,7 +258,7 @@ class ShadowFrame { // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array. if (kMovingCollector && HasReferenceArray()) { - References()[i] = nullptr; + References()[i].Clear(); } } @@ -255,8 +271,8 @@ class ShadowFrame { // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array. if (kMovingCollector && HasReferenceArray()) { - References()[i] = nullptr; - References()[i + 1] = nullptr; + References()[i].Clear(); + References()[i + 1].Clear(); } } @@ -269,24 +285,24 @@ class ShadowFrame { // This is needed for moving collectors since these can update the vreg references if they // happen to agree with references in the reference array. if (kMovingCollector && HasReferenceArray()) { - References()[i] = nullptr; - References()[i + 1] = nullptr; + References()[i].Clear(); + References()[i + 1].Clear(); } } - void SetVRegReference(size_t i, mirror::Object* val) { + void SetVRegReference(size_t i, mirror::Object* val) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_LT(i, NumberOfVRegs()); DCHECK(!kMovingCollector || VerifyReference(val)) << "VReg " << i << "(" << val << ") is in protected space"; uint32_t* vreg = &vregs_[i]; - *reinterpret_cast<mirror::Object**>(vreg) = val; + reinterpret_cast<StackReference<mirror::Object>*>(vreg)->Assign(val); if (HasReferenceArray()) { - References()[i] = val; + References()[i].Assign(val); } } - mirror::ArtMethod* GetMethod() const { - DCHECK_NE(method_, static_cast<void*>(NULL)); + mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(method_ != nullptr); return method_; } @@ -298,7 +314,7 @@ class ShadowFrame { void SetMethod(mirror::ArtMethod* method) { #if defined(ART_USE_PORTABLE_COMPILER) - DCHECK_NE(method, static_cast<void*>(NULL)); + DCHECK(method != nullptr); method_ = method; #else UNUSED(method); @@ -306,7 +322,7 @@ class ShadowFrame { #endif } - bool Contains(mirror::Object** shadow_frame_entry_obj) const { + bool Contains(StackReference<mirror::Object>* shadow_frame_entry_obj) const { if (HasReferenceArray()) { return ((&References()[0] <= shadow_frame_entry_obj) && (shadow_frame_entry_obj <= (&References()[NumberOfVRegs() - 1]))); @@ -346,22 +362,22 @@ class ShadowFrame { CHECK_LT(num_vregs, static_cast<uint32_t>(kHasReferenceArray)); number_of_vregs_ |= kHasReferenceArray; #endif - memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(mirror::Object*))); + memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(StackReference<mirror::Object>))); } else { memset(vregs_, 0, num_vregs * sizeof(uint32_t)); } } - mirror::Object* const* References() const { + const StackReference<mirror::Object>* References() const { DCHECK(HasReferenceArray()); const uint32_t* vreg_end = &vregs_[NumberOfVRegs()]; - return reinterpret_cast<mirror::Object* const*>(vreg_end); + return reinterpret_cast<const StackReference<mirror::Object>*>(vreg_end); } bool VerifyReference(const mirror::Object* val) const; - mirror::Object** References() { - return const_cast<mirror::Object**>(const_cast<const ShadowFrame*>(this)->References()); + StackReference<mirror::Object>* References() { + return const_cast<StackReference<mirror::Object>*>(const_cast<const ShadowFrame*>(this)->References()); } #if defined(ART_USE_PORTABLE_COMPILER) @@ -470,9 +486,9 @@ class PACKED(4) ManagedStack { return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_); } - size_t NumJniShadowFrameReferences() const; + size_t NumJniShadowFrameReferences() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool ShadowFramesContain(mirror::Object** shadow_frame_entry) const; + bool ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const; private: ManagedStack* link_; @@ -494,18 +510,18 @@ class StackVisitor { void WalkStack(bool include_transitions = false) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::ArtMethod* GetMethod() const { - if (cur_shadow_frame_ != NULL) { + mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (cur_shadow_frame_ != nullptr) { return cur_shadow_frame_->GetMethod(); - } else if (cur_quick_frame_ != NULL) { + } else if (cur_quick_frame_ != nullptr) { return *cur_quick_frame_; } else { - return NULL; + return nullptr; } } bool IsShadowFrame() const { - return cur_shadow_frame_ != NULL; + return cur_shadow_frame_ != nullptr; } uint32_t GetDexPc() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -514,9 +530,10 @@ class StackVisitor { size_t GetNativePcOffset() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - uintptr_t* CalleeSaveAddress(int num, size_t frame_size) const { + uintptr_t* CalleeSaveAddress(int num, size_t frame_size) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Callee saves are held at the top of the frame - DCHECK(GetMethod() != NULL); + DCHECK(GetMethod() != nullptr); byte* save_addr = reinterpret_cast<byte*>(cur_quick_frame_) + frame_size - ((num + 1) * kPointerSize); #if defined(__i386__) @@ -553,17 +570,17 @@ class StackVisitor { // This is a fast-path for getting/setting values in a quick frame. uint32_t* GetVRegAddr(mirror::ArtMethod** cur_quick_frame, const DexFile::CodeItem* code_item, - uint32_t core_spills, uint32_t fp_spills, size_t frame_size, - uint16_t vreg) const { + uint32_t core_spills, uint32_t fp_spills, size_t frame_size, + uint16_t vreg) const { int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); DCHECK_EQ(cur_quick_frame, GetCurrentQuickFrame()); byte* vreg_addr = reinterpret_cast<byte*>(cur_quick_frame) + offset; return reinterpret_cast<uint32_t*>(vreg_addr); } - uintptr_t GetReturnPc() const; + uintptr_t GetReturnPc() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SetReturnPc(uintptr_t new_ret_pc); + void SetReturnPc(uintptr_t new_ret_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * Return sp-relative offset for a Dalvik virtual register, compiler diff --git a/runtime/stack_indirect_reference_table.h b/runtime/stack_indirect_reference_table.h index 4c9b038423..d22650b6f2 100644 --- a/runtime/stack_indirect_reference_table.h +++ b/runtime/stack_indirect_reference_table.h @@ -19,6 +19,7 @@ #include "base/logging.h" #include "base/macros.h" +#include "stack.h" namespace art { namespace mirror { @@ -33,7 +34,7 @@ class StackIndirectReferenceTable { public: explicit StackIndirectReferenceTable(mirror::Object* object) : number_of_references_(1), link_(NULL) { - references_[0] = object; + references_[0].Assign(object); } ~StackIndirectReferenceTable() {} @@ -53,17 +54,17 @@ class StackIndirectReferenceTable { link_ = sirt; } - mirror::Object* GetReference(size_t i) const { + mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_LT(i, number_of_references_); - return references_[i]; + return references_[i].AsMirrorPtr(); } - void SetReference(size_t i, mirror::Object* object) { + void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_LT(i, number_of_references_); - references_[i] = object; + references_[i].Assign(object); } - bool Contains(mirror::Object** sirt_entry) const { + bool Contains(StackReference<mirror::Object>* sirt_entry) const { // A SIRT should always contain something. One created by the // jni_compiler should have a jobject/jclass as a native method is // passed in a this pointer or a class @@ -89,7 +90,7 @@ class StackIndirectReferenceTable { StackIndirectReferenceTable* link_; // number_of_references_ are available if this is allocated and filled in by jni_compiler. - mirror::Object* references_[1]; + StackReference<mirror::Object> references_[1]; DISALLOW_COPY_AND_ASSIGN(StackIndirectReferenceTable); }; diff --git a/runtime/thread.cc b/runtime/thread.cc index c3ef228487..c649765e55 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -178,7 +178,7 @@ void* Thread::CreateCallback(void* arg) { receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(soa.DecodeMethod(mid)); JValue result; ArgArray arg_array(nullptr, 0); - arg_array.Append(reinterpret_cast<uint32_t>(receiver)); + arg_array.Append(receiver); m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V'); } // Detach and delete self. @@ -190,7 +190,7 @@ void* Thread::CreateCallback(void* arg) { Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa, mirror::Object* thread_peer) { mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer); - Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetInt(thread_peer))); + Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetLong(thread_peer))); // Sanity check that if we have a result it is either suspended or we hold the thread_list_lock_ // to stop it from going away. if (kIsDebugBuild) { @@ -260,8 +260,8 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing to // assign it. - env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, - reinterpret_cast<jint>(child_thread)); + env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, + reinterpret_cast<jlong>(child_thread)); pthread_t new_pthread; pthread_attr_t attr; @@ -283,7 +283,7 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz delete child_thread; child_thread = nullptr; // TODO: remove from thread group? - env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0); + env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0); { std::string msg(StringPrintf("pthread_create (%s stack) failed: %s", PrettySize(stack_size).c_str(), strerror(pthread_create_result))); @@ -388,8 +388,8 @@ void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) Thread* self = this; DCHECK_EQ(self, Thread::Current()); - jni_env_->SetIntField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer, - reinterpret_cast<jint>(self)); + jni_env_->SetLongField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer, + reinterpret_cast<jlong>(self)); ScopedObjectAccess soa(self); SirtRef<mirror::String> peer_thread_name(soa.Self(), GetThreadName(soa)); @@ -767,7 +767,7 @@ struct StackDumpVisitor : public StackVisitor { } const int kMaxRepetition = 3; mirror::Class* c = m->GetDeclaringClass(); - const mirror::DexCache* dex_cache = c->GetDexCache(); + mirror::DexCache* dex_cache = c->GetDexCache(); int line_number = -1; if (dex_cache != nullptr) { // be tolerant of bad input const DexFile& dex_file = *dex_cache->GetDexFile(); @@ -1017,7 +1017,7 @@ void Thread::Destroy() { RemoveFromThreadGroup(soa); // this.nativePeer = 0; - soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetInt(opeer_, 0); + soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong(opeer_, 0); Dbg::PostThreadDeath(self); // Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone @@ -1133,7 +1133,8 @@ size_t Thread::NumSirtReferences() { } bool Thread::SirtContains(jobject obj) const { - mirror::Object** sirt_entry = reinterpret_cast<mirror::Object**>(obj); + StackReference<mirror::Object>* sirt_entry = + reinterpret_cast<StackReference<mirror::Object>*>(obj); for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->GetLink()) { if (cur->Contains(sirt_entry)) { return true; @@ -1172,10 +1173,11 @@ mirror::Object* Thread::DecodeJObject(jobject obj) const { IndirectReferenceTable& locals = jni_env_->locals; result = const_cast<mirror::Object*>(locals.Get(ref)); } else if (kind == kSirtOrInvalid) { - // TODO: make stack indirect reference table lookup more efficient - // Check if this is a local reference in the SIRT + // TODO: make stack indirect reference table lookup more efficient. + // Check if this is a local reference in the SIRT. if (LIKELY(SirtContains(obj))) { - result = *reinterpret_cast<mirror::Object**>(obj); // Read from SIRT + // Read from SIRT. + result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr(); } else if (Runtime::Current()->GetJavaVM()->work_around_app_jni_bugs) { // Assume an invalid local reference is actually a direct pointer. result = reinterpret_cast<mirror::Object*>(obj); @@ -1569,12 +1571,12 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location, SetException(gc_safe_throw_location, exception.get()); } else { ArgArray args("VLL", 3); - args.Append(reinterpret_cast<uint32_t>(exception.get())); + args.Append(exception.get()); if (msg != nullptr) { - args.Append(reinterpret_cast<uint32_t>(msg_string.get())); + args.Append(msg_string.get()); } if (cause.get() != nullptr) { - args.Append(reinterpret_cast<uint32_t>(cause.get())); + args.Append(cause.get()); } JValue result; exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, 'V'); @@ -1920,13 +1922,13 @@ class ReferenceMapVisitor : public StackVisitor { } } } else { - uint32_t* reg_addr = - GetVRegAddr(cur_quick_frame, code_item, core_spills, fp_spills, frame_size, reg); + uintptr_t* reg_addr = reinterpret_cast<uintptr_t*>( + GetVRegAddr(cur_quick_frame, code_item, core_spills, fp_spills, frame_size, reg)); mirror::Object* ref = reinterpret_cast<mirror::Object*>(*reg_addr); if (ref != nullptr) { mirror::Object* new_ref = visitor_(ref, reg, this); if (ref != new_ref) { - *reg_addr = reinterpret_cast<uint32_t>(new_ref); + *reg_addr = reinterpret_cast<uintptr_t>(new_ref); } } } diff --git a/runtime/thread.h b/runtime/thread.h index 4a37ca0de1..b7f8bb0e4e 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -487,23 +487,23 @@ class PACKED(4) Thread { ManagedStack::TopShadowFrameOffset()); } - // Number of references allocated in JNI ShadowFrames on this thread - size_t NumJniShadowFrameReferences() const { + // Number of references allocated in JNI ShadowFrames on this thread. + size_t NumJniShadowFrameReferences() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return managed_stack_.NumJniShadowFrameReferences(); } - // Number of references in SIRTs on this thread + // Number of references in SIRTs on this thread. size_t NumSirtReferences(); - // Number of references allocated in SIRTs & JNI shadow frames on this thread - size_t NumStackReferences() { + // Number of references allocated in SIRTs & JNI shadow frames on this thread. + size_t NumStackReferences() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return NumSirtReferences() + NumJniShadowFrameReferences(); }; // Is the given obj in this thread's stack indirect reference table? bool SirtContains(jobject obj) const; - void SirtVisitRoots(RootVisitor* visitor, void* arg); + void SirtVisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void PushSirt(StackIndirectReferenceTable* sirt) { sirt->SetLink(top_sirt_); @@ -788,7 +788,7 @@ class PACKED(4) Thread { // A positive value implies we're in a region where thread suspension isn't expected. uint32_t no_thread_suspension_; - // Cause for last suspension. + // If no_thread_suspension_ is > 0, what is causing that assertion. const char* last_no_thread_suspension_cause_; // Maximum number of checkpoint functions. diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index aca0561a77..e8c9ff85db 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -31,7 +31,7 @@ ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& n name_(name) { std::string error_msg; stack_.reset(MemMap::MapAnonymous(name.c_str(), nullptr, stack_size, PROT_READ | PROT_WRITE, - &error_msg)); + false, &error_msg)); CHECK(stack_.get() != nullptr) << error_msg; const char* reason = "new thread pool worker thread"; pthread_attr_t attr; diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index 2029d4b2d7..c6f0e92d19 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -17,7 +17,7 @@ #include <string> -#include "atomic_integer.h" +#include "atomic.h" #include "common_test.h" #include "thread_pool.h" diff --git a/runtime/trace.cc b/runtime/trace.cc index b0f6e37622..18185d4ba6 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -89,7 +89,7 @@ class BuildStackTraceVisitor : public StackVisitor { explicit BuildStackTraceVisitor(Thread* thread) : StackVisitor(thread, NULL), method_trace_(Trace::AllocStackTrace()) {} - bool VisitFrame() { + bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* m = GetMethod(); // Ignore runtime frames (in particular callee save). if (!m->IsRuntimeMethod()) { @@ -133,9 +133,9 @@ static TraceAction DecodeTraceAction(uint32_t tmid) { return static_cast<TraceAction>(tmid & kTraceMethodActionMask); } -static uint32_t EncodeTraceMethodAndAction(const mirror::ArtMethod* method, +static uint32_t EncodeTraceMethodAndAction(mirror::ArtMethod* method, TraceAction action) { - uint32_t tmid = reinterpret_cast<uint32_t>(method) | action; + uint32_t tmid = PointerToLowMemUInt32(method) | action; DCHECK_EQ(method, DecodeTraceMethodId(tmid)); return tmid; } @@ -298,7 +298,7 @@ void Trace::CompareAndUpdateStackTrace(Thread* thread, void* Trace::RunSamplingThread(void* arg) { Runtime* runtime = Runtime::Current(); - int interval_us = reinterpret_cast<int>(arg); + intptr_t interval_us = reinterpret_cast<intptr_t>(arg); CHECK_GE(interval_us, 0); CHECK(runtime->AttachCurrentThread("Sampling Profiler", true, runtime->GetSystemThreadGroup(), !runtime->IsCompiler())); @@ -508,7 +508,7 @@ void Trace::FinishTracing() { } else { os << StringPrintf("clock=wall\n"); } - os << StringPrintf("elapsed-time-usec=%llu\n", elapsed); + os << StringPrintf("elapsed-time-usec=%" PRIu64 "\n", elapsed); size_t num_records = (final_offset - kTraceHeaderLength) / GetRecordSize(clock_source_); os << StringPrintf("num-method-calls=%zd\n", num_records); os << StringPrintf("clock-call-overhead-nsec=%d\n", clock_overhead_ns); @@ -548,13 +548,13 @@ void Trace::FinishTracing() { } void Trace::DexPcMoved(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t new_dex_pc) { + mirror::ArtMethod* method, uint32_t new_dex_pc) { // We're not recorded to listen to this kind of event, so complain. LOG(ERROR) << "Unexpected dex PC event in tracing " << PrettyMethod(method) << " " << new_dex_pc; }; void Trace::MethodEntered(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) { + mirror::ArtMethod* method, uint32_t dex_pc) { uint32_t thread_clock_diff = 0; uint32_t wall_clock_diff = 0; ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); @@ -563,7 +563,7 @@ void Trace::MethodEntered(Thread* thread, mirror::Object* this_object, } void Trace::MethodExited(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) { UNUSED(return_value); uint32_t thread_clock_diff = 0; @@ -574,7 +574,7 @@ void Trace::MethodExited(Thread* thread, mirror::Object* this_object, } void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) { + mirror::ArtMethod* method, uint32_t dex_pc) { uint32_t thread_clock_diff = 0; uint32_t wall_clock_diff = 0; ReadClocks(thread, &thread_clock_diff, &wall_clock_diff); @@ -605,7 +605,7 @@ void Trace::ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wa } } -void Trace::LogMethodTraceEvent(Thread* thread, const mirror::ArtMethod* method, +void Trace::LogMethodTraceEvent(Thread* thread, mirror::ArtMethod* method, instrumentation::Instrumentation::InstrumentationEvent event, uint32_t thread_clock_diff, uint32_t wall_clock_diff) { // Advance cur_offset_ atomically. diff --git a/runtime/trace.h b/runtime/trace.h index 9be015a13d..d810df05fe 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -73,17 +73,17 @@ class Trace : public instrumentation::InstrumentationListener { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void MethodEntered(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void MethodExited(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc, + mirror::ArtMethod* method, uint32_t dex_pc, const JValue& return_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void MethodUnwind(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t dex_pc) + mirror::ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void DexPcMoved(Thread* thread, mirror::Object* this_object, - const mirror::ArtMethod* method, uint32_t new_dex_pc) + mirror::ArtMethod* method, uint32_t new_dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); virtual void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location, mirror::ArtMethod* catch_method, uint32_t catch_dex_pc, @@ -105,7 +105,7 @@ class Trace : public instrumentation::InstrumentationListener { void ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff); - void LogMethodTraceEvent(Thread* thread, const mirror::ArtMethod* method, + void LogMethodTraceEvent(Thread* thread, mirror::ArtMethod* method, instrumentation::Instrumentation::InstrumentationEvent event, uint32_t thread_clock_diff, uint32_t wall_clock_diff); diff --git a/runtime/utf.cc b/runtime/utf.cc index 5ec2ea1c36..e48d6d2093 100644 --- a/runtime/utf.cc +++ b/runtime/utf.cc @@ -68,7 +68,7 @@ void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, size_t } } -int32_t ComputeUtf16Hash(const mirror::CharArray* chars, int32_t offset, +int32_t ComputeUtf16Hash(mirror::CharArray* chars, int32_t offset, size_t char_count) { int32_t hash = 0; for (size_t i = 0; i < char_count; i++) { diff --git a/runtime/utf.h b/runtime/utf.h index cc5e6d48c2..5b2289ef19 100644 --- a/runtime/utf.h +++ b/runtime/utf.h @@ -73,7 +73,7 @@ void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, size_t /* * The java.lang.String hashCode() algorithm. */ -int32_t ComputeUtf16Hash(const mirror::CharArray* chars, int32_t offset, size_t char_count) +int32_t ComputeUtf16Hash(mirror::CharArray* chars, int32_t offset, size_t char_count) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count); diff --git a/runtime/utils.cc b/runtime/utils.cc index a2930430d3..aad21bca85 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -215,14 +215,14 @@ void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts } } -std::string PrettyDescriptor(const mirror::String* java_descriptor) { +std::string PrettyDescriptor(mirror::String* java_descriptor) { if (java_descriptor == NULL) { return "null"; } return PrettyDescriptor(java_descriptor->ToModifiedUtf8()); } -std::string PrettyDescriptor(const mirror::Class* klass) { +std::string PrettyDescriptor(mirror::Class* klass) { if (klass == NULL) { return "null"; } @@ -283,7 +283,7 @@ std::string PrettyDescriptor(Primitive::Type type) { return PrettyDescriptor(descriptor_string); } -std::string PrettyField(const mirror::ArtField* f, bool with_type) { +std::string PrettyField(mirror::ArtField* f, bool with_type) { if (f == NULL) { return "null"; } @@ -358,7 +358,7 @@ std::string PrettyReturnType(const char* signature) { return PrettyDescriptor(return_type); } -std::string PrettyMethod(const mirror::ArtMethod* m, bool with_signature) { +std::string PrettyMethod(mirror::ArtMethod* m, bool with_signature) { if (m == nullptr) { return "null"; } @@ -401,7 +401,7 @@ std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with return result; } -std::string PrettyTypeOf(const mirror::Object* obj) { +std::string PrettyTypeOf(mirror::Object* obj) { if (obj == NULL) { return "null"; } @@ -417,7 +417,7 @@ std::string PrettyTypeOf(const mirror::Object* obj) { return result; } -std::string PrettyClass(const mirror::Class* c) { +std::string PrettyClass(mirror::Class* c) { if (c == NULL) { return "null"; } @@ -428,7 +428,7 @@ std::string PrettyClass(const mirror::Class* c) { return result; } -std::string PrettyClassAndClassLoader(const mirror::Class* c) { +std::string PrettyClassAndClassLoader(mirror::Class* c) { if (c == NULL) { return "null"; } @@ -445,7 +445,7 @@ std::string PrettyClassAndClassLoader(const mirror::Class* c) { std::string PrettySize(int64_t byte_count) { // The byte thresholds at which we display amounts. A byte count is displayed // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. - static const size_t kUnitThresholds[] = { + static const int64_t kUnitThresholds[] = { 0, // B up to... 3*1024, // KB up to... 2*1024*1024, // MB up to... @@ -464,7 +464,7 @@ std::string PrettySize(int64_t byte_count) { break; } } - return StringPrintf("%s%lld%s", negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); + return StringPrintf("%s%" PRId64 "%s", negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); } std::string PrettyDuration(uint64_t nano_duration) { @@ -534,18 +534,18 @@ std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit) { uint64_t whole_part = nano_duration / divisor; uint64_t fractional_part = nano_duration % divisor; if (fractional_part == 0) { - return StringPrintf("%llu%s", whole_part, unit); + return StringPrintf("%" PRIu64 "%s", whole_part, unit); } else { while ((fractional_part % 1000) == 0) { zero_fill -= 3; fractional_part /= 1000; } if (zero_fill == 3) { - return StringPrintf("%llu.%03llu%s", whole_part, fractional_part, unit); + return StringPrintf("%" PRIu64 ".%03" PRIu64 "%s", whole_part, fractional_part, unit); } else if (zero_fill == 6) { - return StringPrintf("%llu.%06llu%s", whole_part, fractional_part, unit); + return StringPrintf("%" PRIu64 ".%06" PRIu64 "%s", whole_part, fractional_part, unit); } else { - return StringPrintf("%llu.%09llu%s", whole_part, fractional_part, unit); + return StringPrintf("%" PRIu64 ".%09" PRIu64 "%s", whole_part, fractional_part, unit); } } } @@ -627,7 +627,7 @@ std::string DescriptorToName(const char* descriptor) { return descriptor; } -std::string JniShortName(const mirror::ArtMethod* m) { +std::string JniShortName(mirror::ArtMethod* m) { MethodHelper mh(m); std::string class_name(mh.GetDeclaringClassDescriptor()); // Remove the leading 'L' and trailing ';'... @@ -646,7 +646,7 @@ std::string JniShortName(const mirror::ArtMethod* m) { return short_name; } -std::string JniLongName(const mirror::ArtMethod* m) { +std::string JniLongName(mirror::ArtMethod* m) { std::string long_name; long_name += JniShortName(m); long_name += "__"; diff --git a/runtime/utils.h b/runtime/utils.h index f063c0af0d..e2d89667c7 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -166,8 +166,29 @@ static inline int CountOneBits(uint32_t x) { return static_cast<int>(x & 0x0000003F); } -#define CLZ(x) __builtin_clz(x) -#define CTZ(x) __builtin_ctz(x) +template<typename T> +static inline int CLZ(T x) { + if (sizeof(T) == sizeof(uint32_t)) { + return __builtin_clz(x); + } else { + return __builtin_clzll(x); + } +} + +template<typename T> +static inline int CTZ(T x) { + if (sizeof(T) == sizeof(uint32_t)) { + return __builtin_ctz(x); + } else { + return __builtin_ctzll(x); + } +} + +static inline uint32_t PointerToLowMemUInt32(const void* p) { + uintptr_t intp = reinterpret_cast<uintptr_t>(p); + DCHECK_LE(intp, 0xFFFFFFFFU); + return intp & 0xFFFFFFFFU; +} static inline bool NeedsEscaping(uint16_t ch) { return (ch < ' ' || ch > '~'); @@ -200,21 +221,22 @@ bool EndsWith(const std::string& s, const char* suffix); // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", // "[[I" would be "int[][]", "[Ljava/lang/String;" would be // "java.lang.String[]", and so forth. -std::string PrettyDescriptor(const mirror::String* descriptor); +std::string PrettyDescriptor(mirror::String* descriptor) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::string PrettyDescriptor(const std::string& descriptor); std::string PrettyDescriptor(Primitive::Type type); -std::string PrettyDescriptor(const mirror::Class* klass) +std::string PrettyDescriptor(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns a human-readable signature for 'f'. Something like "a.b.C.f" or // "int a.b.C.f" (depending on the value of 'with_type'). -std::string PrettyField(const mirror::ArtField* f, bool with_type = true) +std::string PrettyField(mirror::ArtField* f, bool with_type = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::string PrettyField(uint32_t field_idx, const DexFile& dex_file, bool with_type = true); // Returns a human-readable signature for 'm'. Something like "a.b.C.m" or // "a.b.C.m(II)V" (depending on the value of 'with_signature'). -std::string PrettyMethod(const mirror::ArtMethod* m, bool with_signature = true) +std::string PrettyMethod(mirror::ArtMethod* m, bool with_signature = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with_signature = true); @@ -222,7 +244,7 @@ std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with // So given an instance of java.lang.String, the output would // be "java.lang.String". Given an array of int, the output would be "int[]". // Given String.class, the output would be "java.lang.Class<java.lang.String>". -std::string PrettyTypeOf(const mirror::Object* obj) +std::string PrettyTypeOf(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns a human-readable form of the type at an index in the specified dex file. @@ -231,11 +253,11 @@ std::string PrettyType(uint32_t type_idx, const DexFile& dex_file); // Returns a human-readable form of the name of the given class. // Given String.class, the output would be "java.lang.Class<java.lang.String>". -std::string PrettyClass(const mirror::Class* c) +std::string PrettyClass(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns a human-readable form of the name of the given class with its class loader. -std::string PrettyClassAndClassLoader(const mirror::Class* c) +std::string PrettyClassAndClassLoader(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns a human-readable size string such as "1MB". @@ -278,10 +300,10 @@ bool IsValidDescriptor(const char* s); // "Ljava/lang/String;" bool IsValidMemberName(const char* s); // Returns the JNI native function name for the non-overloaded method 'm'. -std::string JniShortName(const mirror::ArtMethod* m) +std::string JniShortName(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the JNI native function name for the overloaded method 'm'. -std::string JniLongName(const mirror::ArtMethod* m) +std::string JniLongName(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool ReadFileToString(const std::string& file_name, std::string* result); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index d2681dff47..30be36c978 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -85,7 +85,7 @@ PcToRegisterLineTable::~PcToRegisterLineTable() { } } -MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* klass, +MethodVerifier::FailureKind MethodVerifier::VerifyClass(mirror::Class* klass, bool allow_soft_failures, std::string* error) { if (klass->IsVerified()) { @@ -837,7 +837,7 @@ bool MethodVerifier::CheckArrayData(uint32_t cur_offset) { /* offset to array data table is a relative branch-style offset */ array_data = insns + array_data_offset; /* make sure the table is 32-bit aligned */ - if ((((uint32_t) array_data) & 0x03) != 0) { + if ((reinterpret_cast<uintptr_t>(array_data) & 0x03) != 0) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned array data table: at " << cur_offset << ", data offset " << array_data_offset; return false; @@ -941,7 +941,7 @@ bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) { /* offset to switch table is a relative branch-style offset */ const uint16_t* switch_insns = insns + switch_offset; /* make sure the table is 32-bit aligned */ - if ((((uint32_t) switch_insns) & 0x03) != 0) { + if ((reinterpret_cast<uintptr_t>(switch_insns) & 0x03) != 0) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned switch table: at " << cur_offset << ", switch offset " << switch_offset; return false; @@ -3616,10 +3616,9 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty // Look for an instance field with this offset. // TODO: we may speed up the search if offsets are sorted by doing a quick search. -static mirror::ArtField* FindInstanceFieldWithOffset(const mirror::Class* klass, - uint32_t field_offset) +static mirror::ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const mirror::ObjectArray<mirror::ArtField>* instance_fields = klass->GetIFields(); + mirror::ObjectArray<mirror::ArtField>* instance_fields = klass->GetIFields(); if (instance_fields != NULL) { for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) { mirror::ArtField* field = instance_fields->Get(i); diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 053cee55ca..7c75c9c240 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -140,8 +140,7 @@ class MethodVerifier { }; /* Verify a class. Returns "kNoFailure" on success. */ - static FailureKind VerifyClass(const mirror::Class* klass, bool allow_soft_failures, - std::string* error) + static FailureKind VerifyClass(mirror::Class* klass, bool allow_soft_failures, std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static FailureKind VerifyClass(const DexFile* dex_file, SirtRef<mirror::DexCache>& dex_cache, SirtRef<mirror::ClassLoader>& class_loader, diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index 4be1d02e46..3818375f4e 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -203,7 +203,7 @@ class RegType { bool IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Primitive::Type GetPrimitiveType() const; bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsInstantiableTypes() const; + bool IsInstantiableTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::string& GetDescriptor() const { DCHECK(HasClass() || (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass())); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index e3946f7209..546eb405ff 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -179,7 +179,7 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;"); java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I"); java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;"); - java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "I"); + java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J"); java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;"); java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;"); diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index 8cb199375b..ba0b91ede0 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -55,7 +55,7 @@ MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error name += entry_filename; UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(), NULL, GetUncompressedLength(), - PROT_READ | PROT_WRITE, error_msg)); + PROT_READ | PROT_WRITE, false, error_msg)); if (map.get() == nullptr) { DCHECK(!error_msg->empty()); return nullptr; |