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
diff --git a/build/Android.common.mk b/build/Android.common.mk
index a8d313a..c5e45e3 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -260,7 +260,7 @@
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 32e6c39..f9fbc58 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1987,30 +1987,6 @@
}
}
-#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 @@
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 f249c6a..a0b4f1c 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -468,7 +468,7 @@
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 b0285fd..4de2a3f 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -78,9 +78,11 @@
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 @@
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 @@
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 @@
: CompiledCode(instruction_set, code) {
}
-CompiledInvokeStub::~CompiledInvokeStub() {}
-
} // namespace art
diff --git a/src/compiled_method.h b/src/compiled_method.h
index ca3a597..901ec64 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -87,10 +87,8 @@
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 @@
fp_spill_mask_(0) {
}
- ~CompiledMethod();
+ ~CompiledMethod() {}
- 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;
-
-#if defined(ART_USE_LLVM_COMPILER)
- void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
- frame_size_in_bytes_ = new_frame_size_in_bytes;
+ size_t GetFrameSizeInBytes() const {
+ return frame_size_in_bytes_;
}
-#endif
+
+ uint32_t GetCoreSpillMask() const {
+ return core_spill_mask_;
+ }
+
+ uint32_t GetFpSpillMask() const {
+ return fp_spill_mask_;
+ }
+
+ const std::vector<uint32_t>& GetMappingTable() const {
+ return mapping_table_;
+ }
+
+ const std::vector<uint16_t>& GetVmapTable() const {
+ return vmap_table_;
+ }
+
+ const std::vector<uint8_t>& GetNativeGcMap() const {
+ return native_gc_map_;
+ }
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 @@
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 b80b6a6..abbb939 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -554,8 +554,7 @@
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 @@
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 3376bc2..759fcd3 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -271,13 +271,6 @@
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 f7b1bc6..c5bbae6 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -472,6 +472,7 @@
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 ca6ccca..1a09427 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -1217,7 +1217,8 @@
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 dff30be..ca0a933 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 @@
}
}
+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 @@
// 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 bd792f7..6a58210 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -136,7 +136,7 @@
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 @@
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 0000000..50e63d6
--- /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 d91fc59..4eec311 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -534,9 +534,9 @@
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 49365b5..2c6f766 100644
--- a/src/oat/runtime/support_jni.cc
+++ b/src/oat/runtime/support_jni.cc
@@ -179,7 +179,7 @@
}
}
// 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 138f722..5df7da3 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -97,7 +97,7 @@
#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 264405d..2a21baa 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -297,7 +297,7 @@
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 @@
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 @@
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 24b6b40..91df927 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -88,8 +88,8 @@
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 @@
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 @@
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 a7951f3..2eb80ec 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -297,7 +297,7 @@
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 @@
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 @@
}
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 54183bb..ee85782 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 @@
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 @@
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 @@
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 @@
} 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 @@
}
} 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 @@
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 bac3ec1..f2043b1 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -450,8 +450,7 @@
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 @@
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 @@
#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 @@
#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 03aadda..5d19ffc 100644
--- a/src/object.h
+++ b/src/object.h
@@ -761,39 +761,22 @@
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);
+ }
+ void SetNativeGcMap(const uint8_t* data) {
+ SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, native_gc_map_), data, 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));
- }
-
- 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 @@
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 @@
// 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 2b2530b..c13aaf4 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -68,12 +68,18 @@
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 91b0cf1..21b05c4 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -243,6 +243,10 @@
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 @@
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 @@
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 935b05c..eaa6683 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 @@
// 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 @@
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 @@
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));
}
- 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_);
+ if (ref != NULL) {
+ root_visitor_(ref, arg_);
+ }
}
}
}
@@ -1768,10 +1769,12 @@
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
similarity index 97%
rename from src/verifier/gc_map.cc
rename to src/verifier/dex_gc_map.cc
index 66cb6c7..c1c9a29 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
similarity index 88%
rename from src/verifier/gc_map.h
rename to src/verifier/dex_gc_map.h
index d6a1c46..d588cfd 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 @@
// 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 @@
// 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 @@
// 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 @@
}
// 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 @@
// 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 @@
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 a01aa8d..73aee9c 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::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 @@
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 @@
#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::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 @@
#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::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 92621ef..c1c2562 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -188,8 +188,8 @@
// 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 @@
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 8cb1ed2..649e6ea 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 @@
}
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 @@
// 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 @@
// 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 5fdb92f..3c37a98 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 @@
}
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());