diff options
author | 2012-09-19 13:33:42 -0700 | |
---|---|---|
committer | 2012-09-20 15:26:35 -0700 | |
commit | 0c7abda482f53db3d153c073d1c7a145f84e0626 (patch) | |
tree | 837b89c75f0047cbcd16c9121739069a36b4f22a | |
parent | ba0b9c55adce3f533845ab1b25c552589e5b4118 (diff) |
NativePcOffsetToReferenceMap
Rather than translate a native PC to a Dex PC and then to the reference
bitmap, just go straight from the native PC to the reference bitmap.
Encode the native PC offsets using a hash rather than linearly
searching.
Change-Id: Iee1073d93c941c0a31f639e5f23cea9e9f747bee
30 files changed, 430 insertions, 366 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index a8d313ae6f..c5e45e3c2d 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -260,7 +260,7 @@ LIBART_COMMON_SRC_FILES := \ src/utils.cc \ src/well_known_classes.cc \ src/zip_archive.cc \ - src/verifier/gc_map.cc \ + src/verifier/dex_gc_map.cc \ src/verifier/method_verifier.cc \ src/verifier/reg_type.cc \ src/verifier/reg_type_cache.cc \ diff --git a/src/class_linker.cc b/src/class_linker.cc index 32e6c3925f..f9fbc5824c 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -1987,30 +1987,6 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vector<Class*>& cla } } -#if !defined(NDEBUG) && !defined(ART_USE_LLVM_COMPILER) -static void CheckMethodsHaveGcMaps(Class* klass) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (!Runtime::Current()->IsStarted()) { - return; - } - for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - Method* method = klass->GetDirectMethod(i); - if (!method->IsNative() && !method->IsAbstract()) { - CHECK(method->GetGcMap() != NULL) << PrettyMethod(method); - } - } - for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { - Method* method = klass->GetVirtualMethod(i); - if (!method->IsNative() && !method->IsAbstract()) { - CHECK(method->GetGcMap() != NULL) << PrettyMethod(method); - } - } -} -#else -static void CheckMethodsHaveGcMaps(Class*) { -} -#endif - void ClassLinker::VerifyClass(Class* klass) { // TODO: assert that the monitor on the Class is held ObjectLock lock(klass); @@ -2106,8 +2082,6 @@ void ClassLinker::VerifyClass(Class* klass) { klass->SetStatus(Class::kStatusVerified); } } - // Sanity check that a verified class has GC maps on all methods. - CheckMethodsHaveGcMaps(klass); } else { LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index f249c6a1c2..a0b4f1ca29 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -468,7 +468,7 @@ struct MethodOffsets : public CheckOffsets<Method> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_), "coreSpillMask")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_), "fpSpillMask")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_), "frameSizeInBytes")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_), "gcMap")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_gc_map_), "gcMap")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_), "invokeStub")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_), "mappingTable")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_dex_index_), "methodDexIndex")); diff --git a/src/compiled_method.cc b/src/compiled_method.cc index b0285fdd04..4de2a3f5fd 100644 --- a/src/compiled_method.cc +++ b/src/compiled_method.cc @@ -78,9 +78,11 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const std::vector<uint32_t>& mapping_table, - const std::vector<uint16_t>& vmap_table) + const std::vector<uint16_t>& vmap_table, + const std::vector<uint8_t>& native_gc_map) : CompiledCode(instruction_set), frame_size_in_bytes_(frame_size_in_bytes), - core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) + core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), + native_gc_map_(native_gc_map) { CHECK_NE(code.size(), 0U); DCHECK_EQ(vmap_table.size(), @@ -113,17 +115,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask))); } -void CompiledMethod::SetGcMap(const std::vector<uint8_t>& gc_map) { - CHECK_NE(gc_map.size(), 0U); - -#if !defined(ART_USE_LLVM_COMPILER) && !defined(ART_USE_GREENLAND_COMPILER) - // Should only be used with CompiledMethods created with the non-LLVM compilers. - CHECK_NE(mapping_table_.size(), 0U); -#endif - - gc_map_ = gc_map; -} - CompiledMethod::CompiledMethod(InstructionSet instruction_set, const std::vector<uint8_t>& code, const size_t frame_size_in_bytes, @@ -134,32 +125,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) { } -CompiledMethod::~CompiledMethod() {} - -size_t CompiledMethod::GetFrameSizeInBytes() const { - return frame_size_in_bytes_; -} - -uint32_t CompiledMethod::GetCoreSpillMask() const { - return core_spill_mask_; -} - -uint32_t CompiledMethod::GetFpSpillMask() const { - return fp_spill_mask_; -} - -const std::vector<uint32_t>& CompiledMethod::GetMappingTable() const { - return mapping_table_; -} - -const std::vector<uint16_t>& CompiledMethod::GetVmapTable() const { - return vmap_table_; -} - -const std::vector<uint8_t>& CompiledMethod::GetGcMap() const { - return gc_map_; -} - CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set) : CompiledCode(instruction_set) { } @@ -169,6 +134,4 @@ CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set, : CompiledCode(instruction_set, code) { } -CompiledInvokeStub::~CompiledInvokeStub() {} - } // namespace art diff --git a/src/compiled_method.h b/src/compiled_method.h index ca3a597149..901ec64d79 100644 --- a/src/compiled_method.h +++ b/src/compiled_method.h @@ -87,10 +87,8 @@ class CompiledMethod : public CompiledCode { const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const std::vector<uint32_t>& mapping_table, - const std::vector<uint16_t>& vmap_table); - - // Sets the GC map for a CompiledMethod. - void SetGcMap(const std::vector<uint8_t>& gc_map); + const std::vector<uint16_t>& vmap_table, + const std::vector<uint8_t>& native_gc_map); // Constructs a CompiledMethod for the JniCompiler. CompiledMethod(InstructionSet instruction_set, @@ -107,28 +105,39 @@ class CompiledMethod : public CompiledCode { fp_spill_mask_(0) { } - ~CompiledMethod(); + ~CompiledMethod() {} + + size_t GetFrameSizeInBytes() const { + return frame_size_in_bytes_; + } + + uint32_t GetCoreSpillMask() const { + return core_spill_mask_; + } + + uint32_t GetFpSpillMask() const { + return fp_spill_mask_; + } - size_t GetFrameSizeInBytes() const; - uint32_t GetCoreSpillMask() const; - uint32_t GetFpSpillMask() const; - const std::vector<uint32_t>& GetMappingTable() const; - const std::vector<uint16_t>& GetVmapTable() const; - const std::vector<uint8_t>& GetGcMap() const; + const std::vector<uint32_t>& GetMappingTable() const { + return mapping_table_; + } + + const std::vector<uint16_t>& GetVmapTable() const { + return vmap_table_; + } -#if defined(ART_USE_LLVM_COMPILER) - void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) { - frame_size_in_bytes_ = new_frame_size_in_bytes; + const std::vector<uint8_t>& GetNativeGcMap() const { + return native_gc_map_; } -#endif private: - size_t frame_size_in_bytes_; + const size_t frame_size_in_bytes_; const uint32_t core_spill_mask_; const uint32_t fp_spill_mask_; std::vector<uint32_t> mapping_table_; std::vector<uint16_t> vmap_table_; - std::vector<uint8_t> gc_map_; + std::vector<uint8_t> native_gc_map_; }; class CompiledInvokeStub : public CompiledCode { @@ -138,7 +147,7 @@ class CompiledInvokeStub : public CompiledCode { explicit CompiledInvokeStub(InstructionSet instruction_set, const std::vector<uint8_t>& code); - ~CompiledInvokeStub(); + ~CompiledInvokeStub() {} }; } // namespace art diff --git a/src/compiler.cc b/src/compiler.cc index b80b6a6600..abbb939a44 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -554,8 +554,7 @@ void Compiler::PreCompile(jobject class_loader, const std::vector<const DexFile* timings.AddSplit("PreCompile.InitializeClassesWithoutClinit"); } -void Compiler::PostCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files) { - SetGcMaps(class_loader, dex_files); +void Compiler::PostCompile(jobject, const std::vector<const DexFile*>&) { } bool Compiler::IsImageClass(const std::string& descriptor) const { @@ -1703,72 +1702,6 @@ CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const { return it->second; } -void Compiler::SetGcMaps(jobject class_loader, const std::vector<const DexFile*>& dex_files) { - for (size_t i = 0; i != dex_files.size(); ++i) { - const DexFile* dex_file = dex_files[i]; - CHECK(dex_file != NULL); - SetGcMapsDexFile(class_loader, *dex_file); - } -} - -void Compiler::SetGcMapsDexFile(jobject jni_class_loader, const DexFile& dex_file) { - ScopedObjectAccess soa(Thread::Current()); - ClassLoader* class_loader = soa.Decode<ClassLoader*>(jni_class_loader); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - DexCache* dex_cache = class_linker->FindDexCache(dex_file); - 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); - const char* descriptor = dex_file.GetClassDescriptor(class_def); - Class* klass = class_linker->FindClass(descriptor, class_loader); - if (klass == NULL || !klass->IsVerified()) { - Thread::Current()->ClearException(); - continue; - } - const byte* class_data = dex_file.GetClassData(class_def); - if (class_data == NULL) { - // empty class such as a marker interface - continue; - } - ClassDataItemIterator it(dex_file, class_data); - while (it.HasNextStaticField()) { - it.Next(); - } - while (it.HasNextInstanceField()) { - it.Next(); - } - while (it.HasNextDirectMethod()) { - Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, - class_loader, NULL, it.GetMethodInvokeType(class_def)); - SetGcMapsMethod(dex_file, method); - it.Next(); - } - while (it.HasNextVirtualMethod()) { - Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, - class_loader, NULL, it.GetMethodInvokeType(class_def)); - SetGcMapsMethod(dex_file, method); - it.Next(); - } - } -} - -void Compiler::SetGcMapsMethod(const DexFile& dex_file, Method* method) { - if (method == NULL) { - Thread::Current()->ClearException(); - return; - } - uint16_t method_idx = method->GetDexMethodIndex(); - MethodReference ref(&dex_file, method_idx); - CompiledMethod* compiled_method = GetCompiledMethod(ref); - if (compiled_method == NULL) { - return; - } - const std::vector<uint8_t>* gc_map = verifier::MethodVerifier::GetGcMap(ref); - if (gc_map == NULL) { - return; - } - compiled_method->SetGcMap(*gc_map); -} - #if defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_QUICK_COMPILER) void Compiler::SetBitcodeFileName(std::string const& filename) { typedef void (*SetBitcodeFileNameFn)(Compiler&, std::string const&); diff --git a/src/compiler.h b/src/compiler.h index 3376bc2b78..759fcd3853 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -271,13 +271,6 @@ class Compiler { static void CompileClass(const CompilationContext* context, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_); - void SetGcMaps(jobject class_loader, const std::vector<const DexFile*>& dex_files) - LOCKS_EXCLUDED(Locks::mutator_lock_); - void SetGcMapsDexFile(jobject class_loader, const DexFile& dex_file) - LOCKS_EXCLUDED(Locks::mutator_lock_); - void SetGcMapsMethod(const DexFile& dex_file, Method* method) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void InsertInvokeStub(const std::string& key, const CompiledInvokeStub* compiled_invoke_stub) LOCKS_EXCLUDED(compiled_invoke_stubs_lock_); diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h index f7b1bc6ac1..c5bbae6283 100644 --- a/src/compiler/CompilerIR.h +++ b/src/compiler/CompilerIR.h @@ -472,6 +472,7 @@ struct CompilationUnit { std::vector<uint32_t> mappingTable; std::vector<uint32_t> coreVmapTable; std::vector<uint32_t> fpVmapTable; + std::vector<uint8_t> nativeGcMap; bool genDebugger; // Generate code for debugger bool printMe; bool hasClassLiterals; // Contains class ptrs used as literals diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc index ca6ccca190..1a0942795a 100644 --- a/src/compiler/Frontend.cc +++ b/src/compiler/Frontend.cc @@ -1217,7 +1217,8 @@ CompiledMethod* compileMethod(Compiler& compiler, CompiledMethod* result = new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer, cUnit->frameSize, cUnit->coreSpillMask, - cUnit->fpSpillMask, cUnit->mappingTable, vmapTable); + cUnit->fpSpillMask, cUnit->mappingTable, vmapTable, + cUnit->nativeGcMap); VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file) << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc index dff30bee5e..ca0a933789 100644 --- a/src/compiler/codegen/CodegenUtil.cc +++ b/src/compiler/codegen/CodegenUtil.cc @@ -14,6 +14,10 @@ * limitations under the License. */ +#include "gc_map.h" +#include "verifier/dex_gc_map.h" +#include "verifier/method_verifier.h" + namespace art { void setMemRefType(LIR* lir, bool isLoad, int memType) @@ -768,6 +772,114 @@ void createMappingTable(CompilationUnit* cUnit) } } +class NativePcToReferenceMapBuilder { + public: + NativePcToReferenceMapBuilder(std::vector<uint8_t>* table, + size_t entries, uint32_t max_native_offset, + size_t references_width) : entries_(entries), + references_width_(references_width), in_use_(entries), + table_(table) { + // Compute width in bytes needed to hold max_native_offset. + native_offset_width_ = 0; + while (max_native_offset != 0) { + native_offset_width_++; + max_native_offset >>= 8; + } + // Resize table and set up header. + table->resize((EntryWidth() * entries) + sizeof(uint32_t)); + CHECK_LT(native_offset_width_, 1U << 8); + (*table)[0] = native_offset_width_; + CHECK_LT(references_width_, 1U << 8); + (*table)[1] = references_width_; + CHECK_LT(entries, 1U << 16); + (*table)[2] = entries & 0xFF; + (*table)[3] = (entries >> 8) & 0xFF; + } + + void AddEntry(uint32_t native_offset, const uint8_t* references) { + size_t table_index = TableIndex(native_offset); + while (in_use_[table_index]) { + table_index = (table_index + 1) % entries_; + } + in_use_[table_index] = true; + SetNativeOffset(table_index, native_offset); + DCHECK_EQ(native_offset, GetNativeOffset(table_index)); + SetReferences(table_index, references); + } + + private: + size_t TableIndex(uint32_t native_offset) { + return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_; + } + + uint32_t GetNativeOffset(size_t table_index) { + uint32_t native_offset = 0; + size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); + for (size_t i = 0; i < native_offset_width_; i++) { + native_offset |= (*table_)[table_offset + i] << (i * 8); + } + return native_offset; + } + + void SetNativeOffset(size_t table_index, uint32_t native_offset) { + size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); + for (size_t i = 0; i < native_offset_width_; i++) { + (*table_)[table_offset + i] = (native_offset >> (i * 8)) & 0xFF; + } + } + + void SetReferences(size_t table_index, const uint8_t* references) { + size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); + memcpy(&(*table_)[table_offset + native_offset_width_], references, references_width_); + } + + size_t EntryWidth() const { + return native_offset_width_ + references_width_; + } + + // Number of entries in the table. + const size_t entries_; + // Number of bytes used to encode the reference bitmap. + const size_t references_width_; + // Number of bytes used to encode a native offset. + size_t native_offset_width_; + // Entries that are in use. + std::vector<bool> in_use_; + // The table we're building. + std::vector<uint8_t>* const table_; +}; + +static void createNativeGcMap(CompilationUnit* cUnit) { + const std::vector<uint32_t>& mapping_table = cUnit->mappingTable; + uint32_t max_native_offset = 0; + for (size_t i = 0; i < mapping_table.size(); i += 2) { + uint32_t native_offset = mapping_table[i + 0]; + if (native_offset > max_native_offset) { + max_native_offset = native_offset; + } + } + Compiler::MethodReference method_ref(cUnit->dex_file, cUnit->method_idx); + const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref); + verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4); + // Compute native offset to references size. + NativePcToReferenceMapBuilder native_gc_map_builder(&cUnit->nativeGcMap, + mapping_table.size() / 2, max_native_offset, + dex_gc_map.RegWidth()); + + for (size_t i = 0; i < mapping_table.size(); i += 2) { + uint32_t native_offset = mapping_table[i + 0]; + uint32_t dex_pc = mapping_table[i + 1]; + const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); + if (references != NULL) { + native_gc_map_builder.AddEntry(native_offset, references); + } else { + // TODO: there is a mapping table entry but no reference bitmap. This happens because of + // catch block entries. We should check that the dex_pc corresponds with a catch block + // here. + } + } +} + /* Determine the offset of each literal field */ int assignLiteralOffset(CompilationUnit* cUnit, int offset) { @@ -874,10 +986,10 @@ void oatAssembleLIR(CompilationUnit* cUnit) // Install fill array data installFillArrayData(cUnit); - /* - * Create the mapping table - */ + // Create the mapping table and native offset to reference map. createMappingTable(cUnit); + + createNativeGcMap(cUnit); } /* diff --git a/src/exception_test.cc b/src/exception_test.cc index bd792f7b86..6a58210284 100644 --- a/src/exception_test.cc +++ b/src/exception_test.cc @@ -136,7 +136,7 @@ TEST_F(ExceptionTest, StackTraceElement) { 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 + 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_)); @@ -153,7 +153,7 @@ TEST_F(ExceptionTest, StackTraceElement) { 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 + 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); diff --git a/src/gc_map.h b/src/gc_map.h new file mode 100644 index 0000000000..50e63d6d00 --- /dev/null +++ b/src/gc_map.h @@ -0,0 +1,97 @@ +/* + * 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_SRC_GC_MAP_H_ +#define ART_SRC_GC_MAP_H_ + +#include "logging.h" +#include "macros.h" +#include <stdint.h> + +namespace art { + +// Lightweight wrapper for native PC offset to reference bit maps. +class NativePcOffsetToReferenceMap { + public: + NativePcOffsetToReferenceMap(const uint8_t* data) : data_(data) { + CHECK(data_ != NULL); + } + + // The number of entries in the table. + size_t NumEntries() const { + return data_[2] | (data_[3] << 8); + } + + // Return address of bitmap encoding what are live references. + const uint8_t* GetBitMap(size_t index) const { + size_t entry_offset = index * EntryWidth(); + return &Table()[entry_offset + NativeOffsetWidth()]; + } + + // Get the native PC encoded in the table at the given index. + uintptr_t GetNativePcOffset(size_t index) const { + size_t entry_offset = index * EntryWidth(); + uintptr_t result = 0; + for (size_t i = 0; i < NativeOffsetWidth(); ++i) { + result |= Table()[entry_offset + i] << (i * 8); + } + return result; + } + + // Finds the bitmap associated with the native pc offset. + const uint8_t* FindBitMap(uintptr_t native_pc_offset) { + size_t num_entries = NumEntries(); + size_t index = Hash(native_pc_offset) % num_entries; + while (GetNativePcOffset(index) != native_pc_offset) { + index = (index + 1) % num_entries; + } + return GetBitMap(index); + } + + static uint32_t Hash(uint32_t native_offset) { + uint32_t hash = native_offset; + hash ^= (hash >> 20) ^ (hash >> 12); + hash ^= (hash >> 7) ^ (hash >> 4); + return hash; + } + + // The number of bytes used to encode registers. + size_t RegWidth() const { + return data_[1]; + } + + private: + // Skip the size information at the beginning of data. + const uint8_t* Table() const { + return data_ + 4; + } + + // Number of bytes used to encode a native offset. + size_t NativeOffsetWidth() const { + return data_[0]; + } + + // The width of an entry in the table. + size_t EntryWidth() const { + return NativeOffsetWidth() + RegWidth(); + } + + const uint8_t* const data_; // The header and table data +}; + +} // namespace art + +#endif // ART_SRC_GC_MAP_H_ diff --git a/src/image_writer.cc b/src/image_writer.cc index d91fc59905..4eec31157c 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -534,9 +534,9 @@ void ImageWriter::FixupMethod(const Method* orig, Method* copy) { const byte* vmap_table = GetOatAddress(vmap_table_offset); copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table); - uint32_t gc_map_offset = orig->GetOatGcMapOffset(); - const byte* gc_map = GetOatAddress(gc_map_offset); - copy->gc_map_ = reinterpret_cast<const uint8_t*>(gc_map); + uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset(); + const byte* native_gc_map = GetOatAddress(native_gc_map_offset); + copy->native_gc_map_ = reinterpret_cast<const uint8_t*>(native_gc_map); } } diff --git a/src/oat/runtime/support_jni.cc b/src/oat/runtime/support_jni.cc index 49365b55bd..2c6f766342 100644 --- a/src/oat/runtime/support_jni.cc +++ b/src/oat/runtime/support_jni.cc @@ -179,7 +179,7 @@ extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) } } // Load expected destination, see Method::RegisterNative - const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw()); + const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap()); if (UNLIKELY(code == NULL)) { code = Runtime::Current()->GetJniDlsymLookupStub()->GetData(); jni_method->RegisterNative(self, code); diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc index 138f7221d4..5df7da30bb 100644 --- a/src/oat/runtime/support_stubs.cc +++ b/src/oat/runtime/support_stubs.cc @@ -97,7 +97,7 @@ const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp #endif if (type == Runtime::kUnknownMethod) { DCHECK(called->IsRuntimeMethod()); - uint32_t dex_pc = caller->ToDexPC(caller_pc); + uint32_t dex_pc = caller->ToDexPc(caller_pc); const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem(); CHECK_LT(dex_pc, code->insns_size_in_code_units_); const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); diff --git a/src/oat_file.cc b/src/oat_file.cc index 264405d6c8..2a21baac3f 100644 --- a/src/oat_file.cc +++ b/src/oat_file.cc @@ -297,7 +297,7 @@ OatFile::OatMethod::OatMethod(const byte* base, fp_spill_mask_(fp_spill_mask), mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset), - gc_map_offset_(gc_map_offset), + native_gc_map_offset_(gc_map_offset), invoke_stub_offset_(invoke_stub_offset) #if defined(ART_USE_LLVM_COMPILER) , proxy_stub_offset_(proxy_stub_offset) @@ -363,7 +363,7 @@ void OatFile::OatMethod::LinkMethodPointers(Method* method) const { method->SetFpSpillMask(fp_spill_mask_); method->SetMappingTable(GetMappingTable()); method->SetVmapTable(GetVmapTable()); - method->SetGcMap(GetGcMap()); // Note, used by native methods in work around JNI mode. + method->SetNativeGcMap(GetNativeGcMap()); // Note, used by native methods in work around JNI mode. method->SetInvokeStub(GetInvokeStub()); } @@ -375,7 +375,7 @@ void OatFile::OatMethod::LinkMethodOffsets(Method* method) const { method->SetFpSpillMask(GetFpSpillMask()); method->SetOatMappingTableOffset(GetMappingTableOffset()); method->SetOatVmapTableOffset(GetVmapTableOffset()); - method->SetOatGcMapOffset(GetGcMapOffset()); + method->SetOatNativeGcMapOffset(GetNativeGcMapOffset()); method->SetOatInvokeStubOffset(GetInvokeStubOffset()); } diff --git a/src/oat_file.h b/src/oat_file.h index 24b6b40538..91df927fd4 100644 --- a/src/oat_file.h +++ b/src/oat_file.h @@ -88,8 +88,8 @@ class OatFile { uint32_t GetVmapTableOffset() const { return vmap_table_offset_; } - uint32_t GetGcMapOffset() const { - return gc_map_offset_; + uint32_t GetNativeGcMapOffset() const { + return native_gc_map_offset_; } uint32_t GetInvokeStubOffset() const { return invoke_stub_offset_; @@ -104,8 +104,8 @@ class OatFile { const uint16_t* GetVmapTable() const { return GetOatPointer<const uint16_t*>(vmap_table_offset_); } - const uint8_t* GetGcMap() const { - return GetOatPointer<const uint8_t*>(gc_map_offset_); + const uint8_t* GetNativeGcMap() const { + return GetOatPointer<const uint8_t*>(native_gc_map_offset_); } Method::InvokeStub* GetInvokeStub() const; @@ -149,7 +149,7 @@ class OatFile { uint32_t fp_spill_mask_; uint32_t mapping_table_offset_; uint32_t vmap_table_offset_; - uint32_t gc_map_offset_; + uint32_t native_gc_map_offset_; uint32_t invoke_stub_offset_; #if defined(ART_USE_LLVM_COMPILER) diff --git a/src/oat_writer.cc b/src/oat_writer.cc index a7951f31de..2eb80ec294 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -297,7 +297,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size); } - const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); + const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap(); size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); gc_map_offset = (gc_map_size == 0) ? 0 : offset; @@ -412,7 +412,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, method->SetCode(Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()); } method->SetOatVmapTableOffset(vmap_table_offset); - method->SetOatGcMapOffset(gc_map_offset); + method->SetOatNativeGcMapOffset(gc_map_offset); method->SetOatInvokeStubOffset(invoke_stub_offset); } @@ -665,7 +665,7 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_cla } DCHECK_CODE_OFFSET(); - const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); + const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap(); size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); // Deduplicate GC maps diff --git a/src/oatdump.cc b/src/oatdump.cc index 54183bbfb2..ee85782529 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -35,7 +35,7 @@ #include "scoped_thread_state_change.h" #include "space.h" #include "stringpiece.h" -#include "verifier/gc_map.h" +#include "gc_map.h" namespace art { @@ -224,7 +224,7 @@ class OatDumper { offsets_.insert(code_offset); offsets_.insert(oat_method.GetMappingTableOffset()); offsets_.insert(oat_method.GetVmapTableOffset()); - offsets_.insert(oat_method.GetGcMapOffset()); + offsets_.insert(oat_method.GetNativeGcMapOffset()); offsets_.insert(oat_method.GetInvokeStubOffset()); } @@ -309,8 +309,8 @@ class OatDumper { DumpVmap(os, oat_method.GetVmapTable(), oat_method.GetCoreSpillMask(), oat_method.GetFpSpillMask()); os << StringPrintf("\t\tgc_map: %p (offset=0x%08x)\n", - oat_method.GetGcMap(), oat_method.GetGcMapOffset()); - DumpGcMap(os, oat_method.GetGcMap()); + oat_method.GetNativeGcMap(), oat_method.GetNativeGcMapOffset()); + DumpGcMap(os, oat_method.GetNativeGcMap()); os << StringPrintf("\t\tCODE: %p (offset=0x%08x size=%d)%s\n", oat_method.GetCode(), oat_method.GetCodeOffset(), @@ -392,11 +392,9 @@ class OatDumper { if (gc_map_raw == NULL) { return; } - uint32_t gc_map_length = (gc_map_raw[0] << 24) | (gc_map_raw[1] << 16) | - (gc_map_raw[2] << 8) | (gc_map_raw[3] << 0); - verifier::DexPcToReferenceMap map(gc_map_raw + sizeof(uint32_t), gc_map_length); + NativePcOffsetToReferenceMap map(gc_map_raw); for (size_t entry = 0; entry < map.NumEntries(); entry++) { - os << StringPrintf("\t\t\t0x%04x", map.GetDexPc(entry)); + os << StringPrintf("\t\t\t0x%04x", map.GetNativePcOffset(entry)); size_t num_regs = map.RegWidth() * 8; const uint8_t* reg_bitmap = map.GetBitMap(entry); bool first = true; @@ -770,8 +768,7 @@ class ImageDumper { } else if (obj->IsMethod()) { Method* method = obj->AsMethod(); if (method->IsNative()) { - DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method); - DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method); + DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); bool first_occurrence; size_t invoke_stub_size = state->ComputeOatSize( @@ -790,13 +787,11 @@ class ImageDumper { } } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || method->IsResolutionMethod()) { - DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method); - DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method); + DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); } else { #if !defined(ART_USE_LLVM_COMPILER) - DCHECK(method->GetGcMap() != NULL) << PrettyMethod(method); - DCHECK_NE(0U, method->GetGcMapLength()) << PrettyMethod(method); + DCHECK(method->GetNativeGcMap() != NULL) << PrettyMethod(method); #endif const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem(); @@ -804,7 +799,7 @@ class ImageDumper { state->stats_.dex_instruction_bytes += dex_instruction_bytes; bool first_occurrence; - size_t gc_map_bytes = state->ComputeOatSize(method->GetGcMapRaw(), &first_occurrence); + size_t gc_map_bytes = state->ComputeOatSize(method->GetNativeGcMap(), &first_occurrence); if (first_occurrence) { state->stats_.gc_map_bytes += gc_map_bytes; } diff --git a/src/object.cc b/src/object.cc index bac3ec1310..f2043b1332 100644 --- a/src/object.cc +++ b/src/object.cc @@ -450,8 +450,7 @@ Method* Method::FindOverriddenMethod() const { return result; } -static const void* GetOatCode(const Method* m) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +static const void* GetOatCode(const Method* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Runtime* runtime = Runtime::Current(); const void* code = m->GetCode(); // Peel off any method tracing trampoline. @@ -465,7 +464,11 @@ static const void* GetOatCode(const Method* m) return code; } -uint32_t Method::ToDexPC(const uintptr_t pc) const { +uintptr_t Method::NativePcOffset(const uintptr_t pc) const { + return pc - reinterpret_cast<uintptr_t>(GetOatCode(this)); +} + +uint32_t Method::ToDexPc(const uintptr_t pc) const { #if !defined(ART_USE_LLVM_COMPILER) const uint32_t* mapping_table = GetMappingTable(); if (mapping_table == NULL) { @@ -488,7 +491,7 @@ uint32_t Method::ToDexPC(const uintptr_t pc) const { #endif } -uintptr_t Method::ToNativePC(const uint32_t dex_pc) const { +uintptr_t Method::ToNativePc(const uint32_t dex_pc) const { const uint32_t* mapping_table = GetMappingTable(); if (mapping_table == NULL) { DCHECK_EQ(dex_pc, 0U); @@ -600,7 +603,7 @@ void Method::RegisterNative(Thread* self, const void* native_method) { #else UNIMPLEMENTED(FATAL); #endif - SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, native_gc_map_), reinterpret_cast<const uint8_t*>(native_method), false); } #endif diff --git a/src/object.h b/src/object.h index 03aadda8a6..5d19ffc19e 100644 --- a/src/object.h +++ b/src/object.h @@ -761,39 +761,22 @@ class MANAGED Method : public Object { SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset)); } - const uint8_t* GetGcMap() const { - const uint8_t* gc_map_raw = GetGcMapRaw(); - if (gc_map_raw == NULL) { - return gc_map_raw; - } - return gc_map_raw + sizeof(uint32_t); + const uint8_t* GetNativeGcMap() const { + return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, native_gc_map_), false); } - - uint32_t GetGcMapLength() const { - const uint8_t* gc_map_raw = GetGcMapRaw(); - if (gc_map_raw == NULL) { - return 0; - } - return static_cast<uint32_t>((gc_map_raw[0] << 24) | - (gc_map_raw[1] << 16) | - (gc_map_raw[2] << 8) | - (gc_map_raw[3] << 0)); + void SetNativeGcMap(const uint8_t* data) { + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, native_gc_map_), data, false); } - const uint8_t* GetGcMapRaw() const { - return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false); - } - void SetGcMap(const uint8_t* data) { - SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), data, false); - } - - uint32_t GetOatGcMapOffset() const { + // When building the oat need a convenient place to stuff the offset of the native GC map. + void SetOatNativeGcMapOffset(uint32_t gc_map_offset) { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetGcMapRaw()); + SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset)); } - void SetOatGcMapOffset(uint32_t gc_map_offset) { + + uint32_t GetOatNativeGcMapOffset() const { DCHECK(!Runtime::Current()->IsStarted()); - SetGcMap(reinterpret_cast<uint8_t*>(gc_map_offset)); + return reinterpret_cast<uint32_t>(GetNativeGcMap()); } size_t GetFrameSizeInBytes() const { @@ -916,15 +899,13 @@ class MANAGED Method : public Object { return result; } - // Converts a native PC to a dex PC. TODO: this is a no-op - // until we associate a PC mapping table with each method. - uint32_t ToDexPC(const uintptr_t pc) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Converts a dex PC to a native PC. TODO: this is a no-op - // until we associate a PC mapping table with each method. - uintptr_t ToNativePC(const uint32_t dex_pc) const - 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_); + + // Converts a dex PC to a native PC. + uintptr_t ToNativePc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find the catch block for the given exception type and dex_pc uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const @@ -978,8 +959,8 @@ class MANAGED Method : public Object { // Total size in bytes of the frame size_t frame_size_in_bytes_; - // Garbage collection map - const uint8_t* gc_map_; + // Garbage collection map of native PC offsets to reference bitmaps. + const uint8_t* native_gc_map_; // Native invocation stub entry point for calling from native to managed code. InvokeStub* invoke_stub_; diff --git a/src/stack.cc b/src/stack.cc index 2b2530bb99..c13aaf4d5e 100644 --- a/src/stack.cc +++ b/src/stack.cc @@ -68,12 +68,18 @@ uint32_t StackVisitor::GetDexPc() const { if (cur_shadow_frame_ != NULL) { return cur_shadow_frame_->GetDexPC(); } else if (cur_quick_frame_ != NULL) { - return GetMethod()->ToDexPC(cur_quick_frame_pc_); + return GetMethod()->ToDexPc(cur_quick_frame_pc_); } else { return 0; } } +size_t StackVisitor::GetNativePcOffset() const { + DCHECK(!IsShadowFrame()); + return GetMethod()->NativePcOffset(cur_quick_frame_pc_); +} + + uint32_t StackVisitor::GetVReg(Method* m, int vreg) const { if (cur_quick_frame_ != NULL) { DCHECK(context_ != NULL); // You can't reliably read registers without a context. diff --git a/src/stack.h b/src/stack.h index 91b0cf16ba..21b05c4b27 100644 --- a/src/stack.h +++ b/src/stack.h @@ -243,6 +243,10 @@ class StackVisitor { return cur_shadow_frame_ != NULL; } + uint32_t GetDexPc() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + size_t GetNativePcOffset() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uintptr_t LoadCalleeSave(int num, size_t frame_size) const { // Callee saves are held at the top of the frame Method* method = GetMethod(); @@ -255,8 +259,6 @@ class StackVisitor { return *reinterpret_cast<uintptr_t*>(save_addr); } - uint32_t GetDexPc() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Returns the height of the stack in the managed stack frames, including transitions. size_t GetFrameHeight() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetNumFrames() - cur_depth_; @@ -274,8 +276,7 @@ class StackVisitor { return num_frames_; } - uint32_t GetVReg(Method* m, int vreg) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + uint32_t GetVReg(Method* m, int vreg) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetVReg(Method* m, int vreg, uint32_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/src/thread.cc b/src/thread.cc index 935b05cbf9..eaa6683344 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -31,6 +31,7 @@ #include "class_linker.h" #include "class_loader.h" #include "debugger.h" +#include "gc_map.h" #include "heap.h" #include "jni_internal.h" #include "monitor.h" @@ -47,7 +48,6 @@ #include "stack_indirect_reference_table.h" #include "thread_list.h" #include "utils.h" -#include "verifier/gc_map.h" #include "well_known_classes.h" namespace art { @@ -1558,7 +1558,7 @@ class CatchBlockStackVisitor : public StackVisitor { // Unwind stack when an exception occurs during method tracing if (UNLIKELY(method_tracing_active_ && IsTraceExitPc(GetCurrentQuickFramePc()))) { uintptr_t pc = TraceMethodUnwindFromCode(Thread::Current()); - dex_pc = method->ToDexPC(pc); + dex_pc = method->ToDexPc(pc); } else { dex_pc = GetDexPc(); } @@ -1568,7 +1568,7 @@ class CatchBlockStackVisitor : public StackVisitor { uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc); if (found_dex_pc != DexFile::kDexNoIndex) { handler_dex_pc_ = found_dex_pc; - handler_quick_frame_pc_ = method->ToNativePC(found_dex_pc); + handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc); handler_quick_frame_ = GetCurrentQuickFrame(); return false; // End stack walk. } @@ -1712,49 +1712,50 @@ class ReferenceMapVisitor : public StackVisitor { Method* m = GetMethod(); // Process register map (which native and runtime methods don't have) if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) { - const uint8_t* gc_map = m->GetGcMap(); - CHECK(gc_map != NULL) << PrettyMethod(m); - uint32_t gc_map_length = m->GetGcMapLength(); - CHECK_NE(0U, gc_map_length) << PrettyMethod(m); - verifier::DexPcToReferenceMap map(gc_map, gc_map_length); - const uint8_t* reg_bitmap = map.FindBitMap(GetDexPc()); - CHECK(reg_bitmap != NULL); - const VmapTable vmap_table(m->GetVmapTableRaw()); - const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem(); + const uint8_t* native_gc_map = m->GetNativeGcMap(); + CHECK(native_gc_map != NULL) << PrettyMethod(m); + mh_.ChangeMethod(m); + const DexFile::CodeItem* code_item = mh_.GetCodeItem(); DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions? - uint32_t core_spills = m->GetCoreSpillMask(); - uint32_t fp_spills = m->GetFpSpillMask(); - size_t frame_size = m->GetFrameSizeInBytes(); - // For all dex registers in the bitmap + NativePcOffsetToReferenceMap map(native_gc_map); size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(code_item->registers_size_)); - Method** cur_quick_frame = GetCurrentQuickFrame(); - DCHECK(cur_quick_frame != NULL); - for (size_t reg = 0; reg < num_regs; ++reg) { - // Does this register hold a reference? - if (TestBitmap(reg, reg_bitmap)) { - uint32_t vmap_offset; - Object* ref; - if (vmap_table.IsInContext(reg, vmap_offset)) { - // Compute the register we need to load from the context - uint32_t spill_mask = core_spills; - CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask))); - uint32_t matches = 0; - uint32_t spill_shifts = 0; - while (matches != (vmap_offset + 1)) { - DCHECK_NE(spill_mask, 0u); - matches += spill_mask & 1; // Add 1 if the low bit is set - spill_mask >>= 1; - spill_shifts++; + if (num_regs > 0) { + const uint8_t* reg_bitmap = map.FindBitMap(GetNativePcOffset()); + DCHECK(reg_bitmap != NULL); + const VmapTable vmap_table(m->GetVmapTableRaw()); + uint32_t core_spills = m->GetCoreSpillMask(); + uint32_t fp_spills = m->GetFpSpillMask(); + size_t frame_size = m->GetFrameSizeInBytes(); + // For all dex registers in the bitmap + Method** cur_quick_frame = GetCurrentQuickFrame(); + DCHECK(cur_quick_frame != NULL); + for (size_t reg = 0; reg < num_regs; ++reg) { + // Does this register hold a reference? + if (TestBitmap(reg, reg_bitmap)) { + uint32_t vmap_offset; + Object* ref; + if (vmap_table.IsInContext(reg, vmap_offset)) { + // Compute the register we need to load from the context + uint32_t spill_mask = core_spills; + CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask))); + uint32_t matches = 0; + uint32_t spill_shifts = 0; + while (matches != (vmap_offset + 1)) { + DCHECK_NE(spill_mask, 0u); + matches += spill_mask & 1; // Add 1 if the low bit is set + spill_mask >>= 1; + spill_shifts++; + } + spill_shifts--; // wind back one as we want the last match + ref = reinterpret_cast<Object*>(GetGPR(spill_shifts)); + } else { + ref = reinterpret_cast<Object*>(GetVReg(cur_quick_frame, code_item, core_spills, + fp_spills, frame_size, reg)); + } + if (ref != NULL) { + root_visitor_(ref, arg_); } - spill_shifts--; // wind back one as we want the last match - ref = reinterpret_cast<Object*>(GetGPR(spill_shifts)); - } else { - ref = reinterpret_cast<Object*>(GetVReg(cur_quick_frame, code_item, core_spills, - fp_spills, frame_size, reg)); - } - if (ref != NULL) { - root_visitor_(ref, arg_); } } } @@ -1768,10 +1769,12 @@ class ReferenceMapVisitor : public StackVisitor { return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0; } - // Call-back when we visit a root + // Call-back when we visit a root. Heap::RootVisitor* root_visitor_; - // Argument to call-back + // Argument to call-back. void* arg_; + // A method helper we keep around to avoid dex file/cache re-computations. + MethodHelper mh_; }; void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) { diff --git a/src/verifier/gc_map.cc b/src/verifier/dex_gc_map.cc index 66cb6c77c1..c1c9a29fb0 100644 --- a/src/verifier/gc_map.cc +++ b/src/verifier/dex_gc_map.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "gc_map.h" +#include "verifier/dex_gc_map.h" #include "logging.h" diff --git a/src/verifier/gc_map.h b/src/verifier/dex_gc_map.h index d6a1c46c31..d588cfd388 100644 --- a/src/verifier/gc_map.h +++ b/src/verifier/dex_gc_map.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_SRC_VERIFIER_GC_MAP_H_ -#define ART_SRC_VERIFIER_GC_MAP_H_ +#ifndef ART_SRC_VERIFIER_DEX_GC_MAP_H_ +#define ART_SRC_VERIFIER_DEX_GC_MAP_H_ #include "logging.h" #include "macros.h" @@ -37,8 +37,7 @@ enum RegisterMapFormat { // Lightweight wrapper for Dex PC to reference bit maps. class DexPcToReferenceMap { public: - DexPcToReferenceMap(const uint8_t* data, size_t data_length) { - data_ = data; + DexPcToReferenceMap(const uint8_t* data, size_t data_length) : data_(data) { CHECK(data_ != NULL); // Check the size of the table agrees with the number of entries size_t data_size = data_length - 4; @@ -53,7 +52,7 @@ class DexPcToReferenceMap { // Get the Dex PC at the given index uint16_t GetDexPc(size_t index) const { size_t entry_offset = index * EntryWidth(); - if (PcWidth() == 1) { + if (DexPcWidth() == 1) { return Table()[entry_offset]; } else { return Table()[entry_offset] | (Table()[entry_offset + 1] << 8); @@ -63,7 +62,7 @@ class DexPcToReferenceMap { // Return address of bitmap encoding what are live references const uint8_t* GetBitMap(size_t index) const { size_t entry_offset = index * EntryWidth(); - return &Table()[entry_offset + PcWidth()]; + return &Table()[entry_offset + DexPcWidth()]; } // Find the bitmap associated with the given dex pc @@ -86,7 +85,7 @@ class DexPcToReferenceMap { } // Number of bytes used to encode a dex pc - size_t PcWidth() const { + size_t DexPcWidth() const { RegisterMapFormat format = Format(); switch (format) { case kRegMapFormatCompact8: @@ -101,7 +100,7 @@ class DexPcToReferenceMap { // The width of an entry in the table size_t EntryWidth() const { - return PcWidth() + RegWidth(); + return DexPcWidth() + RegWidth(); } const uint8_t* GetData() const { @@ -113,10 +112,10 @@ class DexPcToReferenceMap { static const int kRegMapFormatShift = 5; static const uint8_t kRegMapFormatMask = 0x7; - const uint8_t* data_; // The header and table data + const uint8_t* const data_; // The header and table data }; } // namespace verifier } // namespace art -#endif // ART_SRC_VERIFIER_GC_MAP_H_ +#endif // ART_SRC_VERIFIER_DEX_GC_MAP_H_ diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc index a01aa8db48..73aee9cf0c 100644 --- a/src/verifier/method_verifier.cc +++ b/src/verifier/method_verifier.cc @@ -24,7 +24,7 @@ #include "dex_file.h" #include "dex_instruction.h" #include "dex_instruction_visitor.h" -#include "gc_map.h" +#include "verifier/dex_gc_map.h" #include "intern_table.h" #include "leb128.h" #include "logging.h" @@ -549,8 +549,9 @@ bool MethodVerifier::ScanTryCatchBlocks() { bool MethodVerifier::VerifyInstructions() { const Instruction* inst = Instruction::At(code_item_->insns_); - /* Flag the start of the method as a branch target. */ + /* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */ insn_flags_[0].SetBranchTarget(); + insn_flags_[0].SetGcPoint(); uint32_t insns_size = code_item_->insns_size_in_code_units_; for (uint32_t dex_pc = 0; dex_pc < insns_size;) { @@ -945,7 +946,7 @@ bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) { return true; } -const std::vector<uint8_t>* CreateLengthPrefixedGcMap(const std::vector<uint8_t>& gc_map) { +static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(const std::vector<uint8_t>& gc_map) { std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>; length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24); length_prefixed_gc_map->push_back((gc_map.size() & 0x00ff0000) >> 16); @@ -1004,12 +1005,8 @@ bool MethodVerifier::VerifyCodeFlow() { #ifndef NDEBUG VerifyGcMap(*map); #endif - const std::vector<uint8_t>* gc_map = CreateLengthPrefixedGcMap(*(map.get())); - verifier::MethodVerifier::SetGcMap(ref, *gc_map); - - if (foo_method_ != NULL) { - foo_method_->SetGcMap(&gc_map->at(0)); - } + const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get())); + verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map); #else // defined(ART_USE_LLVM_COMPILER) || defined(ART_USE_GREENLAND_COMPILER) /* Generate Inferred Register Category for LLVM-based Code Generator */ @@ -3212,31 +3209,31 @@ void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) { } } -void MethodVerifier::SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) { +void MethodVerifier::SetDexGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) { { - MutexLock mu(*gc_maps_lock_); - GcMapTable::iterator it = gc_maps_->find(ref); - if (it != gc_maps_->end()) { + MutexLock mu(*dex_gc_maps_lock_); + DexGcMapTable::iterator it = dex_gc_maps_->find(ref); + if (it != dex_gc_maps_->end()) { delete it->second; - gc_maps_->erase(it); + dex_gc_maps_->erase(it); } - gc_maps_->Put(ref, &gc_map); + dex_gc_maps_->Put(ref, &gc_map); } - CHECK(GetGcMap(ref) != NULL); + CHECK(GetDexGcMap(ref) != NULL); } -const std::vector<uint8_t>* MethodVerifier::GetGcMap(Compiler::MethodReference ref) { - MutexLock mu(*gc_maps_lock_); - GcMapTable::const_iterator it = gc_maps_->find(ref); - if (it == gc_maps_->end()) { +const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(Compiler::MethodReference ref) { + MutexLock mu(*dex_gc_maps_lock_); + DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref); + if (it == dex_gc_maps_->end()) { return NULL; } CHECK(it->second != NULL); return it->second; } -Mutex* MethodVerifier::gc_maps_lock_ = NULL; -MethodVerifier::GcMapTable* MethodVerifier::gc_maps_ = NULL; +Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL; +MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL; Mutex* MethodVerifier::rejected_classes_lock_ = NULL; MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL; @@ -3247,10 +3244,10 @@ MethodVerifier::InferredRegCategoryMapTable* MethodVerifier::inferred_reg_catego #endif void MethodVerifier::Init() { - gc_maps_lock_ = new Mutex("verifier GC maps lock"); + dex_gc_maps_lock_ = new Mutex("verifier GC maps lock"); { - MutexLock mu(*gc_maps_lock_); - gc_maps_ = new MethodVerifier::GcMapTable; + MutexLock mu(*dex_gc_maps_lock_); + dex_gc_maps_ = new MethodVerifier::DexGcMapTable; } rejected_classes_lock_ = new Mutex("verifier rejected classes lock"); @@ -3270,13 +3267,13 @@ void MethodVerifier::Init() { void MethodVerifier::Shutdown() { { - MutexLock mu(*gc_maps_lock_); - STLDeleteValues(gc_maps_); - delete gc_maps_; - gc_maps_ = NULL; + MutexLock mu(*dex_gc_maps_lock_); + STLDeleteValues(dex_gc_maps_); + delete dex_gc_maps_; + dex_gc_maps_ = NULL; } - delete gc_maps_lock_; - gc_maps_lock_ = NULL; + delete dex_gc_maps_lock_; + dex_gc_maps_lock_ = NULL; { MutexLock mu(*rejected_classes_lock_); diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h index 92621efff6..c1c25628ff 100644 --- a/src/verifier/method_verifier.h +++ b/src/verifier/method_verifier.h @@ -188,8 +188,8 @@ class MethodVerifier { // information void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref) - LOCKS_EXCLUDED(gc_maps_lock_); + static const std::vector<uint8_t>* GetDexGcMap(Compiler::MethodReference ref) + LOCKS_EXCLUDED(dex_gc_maps_lock_); // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding // to the locks held at 'dex_pc' in 'm'. @@ -578,11 +578,11 @@ class MethodVerifier { InsnFlags* CurrentInsnFlags(); // All the GC maps that the verifier has created - typedef SafeMap<const Compiler::MethodReference, const std::vector<uint8_t>*> GcMapTable; - static Mutex* gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - static GcMapTable* gc_maps_ GUARDED_BY(gc_maps_lock_); - static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) - LOCKS_EXCLUDED(gc_maps_lock_); + typedef SafeMap<const Compiler::MethodReference, const std::vector<uint8_t>*> DexGcMapTable; + static Mutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + static DexGcMapTable* dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_); + static void SetDexGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& dex_gc_map) + LOCKS_EXCLUDED(dex_gc_maps_lock_); typedef std::set<Compiler::ClassReference> RejectedClassesTable; static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc index 8cb1ed2b49..649e6eaf77 100644 --- a/test/ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/ReferenceMap/stack_walk_refmap_jni.cc @@ -18,12 +18,12 @@ #include "UniquePtr.h" #include "class_linker.h" +#include "gc_map.h" #include "object.h" #include "object_utils.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "jni.h" -#include "verifier/gc_map.h" #include "verifier/method_verifier.h" namespace art { @@ -55,7 +55,7 @@ struct ReferenceMap2Visitor : public StackVisitor { } LOG(INFO) << "At " << PrettyMethod(m, false); - verifier::DexPcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength()); + NativePcOffsetToReferenceMap map(m->GetNativeGcMap()); if (m->IsCalleeSaveMethod()) { LOG(WARNING) << "no PC for " << PrettyMethod(m); @@ -75,31 +75,31 @@ struct ReferenceMap2Visitor : public StackVisitor { // we know the Dex registers with live reference values. Assert that what we // find is what is expected. if (m_name.compare("f") == 0) { - ref_bitmap = map.FindBitMap(0x03U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x03U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8); // v8: this - ref_bitmap = map.FindBitMap(0x06U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x06U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 1); // v8: this, v1: x - ref_bitmap = map.FindBitMap(0x08U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x08U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 1); // v8: this, v3: y, v1: x - ref_bitmap = map.FindBitMap(0x0cU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0cU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 1); // v8: this, v3: y, v1: x - ref_bitmap = map.FindBitMap(0x0eU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0eU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 1); // v8: this, v3: y, v1: x - ref_bitmap = map.FindBitMap(0x10U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x10U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 1); // v8: this, v3: y, v1: x - ref_bitmap = map.FindBitMap(0x13U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x13U))); CHECK(ref_bitmap); // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See: // 0024: move-object v3, v2 @@ -107,53 +107,49 @@ struct ReferenceMap2Visitor : public StackVisitor { // Detaled dex instructions for ReferenceMap.java are at the end of this function. CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1); // v8: this, v3: y, v2: y, v1: x - ref_bitmap = map.FindBitMap(0x15U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x18U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x18U); - CHECK(ref_bitmap); - CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex - - ref_bitmap = map.FindBitMap(0x1aU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1aU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x1dU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1dU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x1fU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1fU))); CHECK(ref_bitmap); // v5 is removed from the root set because there is a "merge" operation. // See 0015: if-nez v2, 001f. CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x21U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x21U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x25U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x25U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0); // v8: this, v3: y, v2: y, v1: x, v0: ex - ref_bitmap = map.FindBitMap(0x27U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x27U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x - ref_bitmap = map.FindBitMap(0x29U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x29U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x - ref_bitmap = map.FindBitMap(0x2cU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2cU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x - ref_bitmap = map.FindBitMap(0x2fU); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2fU))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 4, 3, 2, 1); // v8: this, v4: ex, v3: y, v2: y, v1: x - ref_bitmap = map.FindBitMap(0x32U); + ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x32U))); CHECK(ref_bitmap); CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0); // v8: this, v3: y, v2: y, v1: x, v0: ex } diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc index 5fdb92fb0d..3c37a98e87 100644 --- a/test/StackWalk/stack_walk_jni.cc +++ b/test/StackWalk/stack_walk_jni.cc @@ -18,11 +18,11 @@ #include "UniquePtr.h" #include "class_linker.h" +#include "gc_map.h" #include "object.h" #include "object_utils.h" #include "jni.h" #include "scoped_thread_state_change.h" -#include "verifier/gc_map.h" namespace art { @@ -58,8 +58,8 @@ struct TestReferenceMapVisitor : public StackVisitor { } const uint8_t* reg_bitmap = NULL; if (!IsShadowFrame()) { - verifier::DexPcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength()); - reg_bitmap = map.FindBitMap(GetDexPc()); + NativePcOffsetToReferenceMap map(m->GetNativeGcMap()); + reg_bitmap = map.FindBitMap(GetNativePcOffset()); } MethodHelper mh(m); StringPiece m_name(mh.GetName()); |