Add GC map to oat file
Change-Id: Ied0462c711a09e2542f231c3b2fa31239958bd28
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5ff2293..20e6514 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1799,26 +1799,105 @@
}
void ClassLinker::VerifyClass(Class* klass) {
+ // TODO: assert that the monitor on the Class is held
if (klass->IsVerified()) {
return;
}
- CHECK_EQ(klass->GetStatus(), Class::kStatusResolved);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass);
klass->SetStatus(Class::kStatusVerifying);
- if (verifier::DexVerifier::VerifyClass(klass)) {
+ // Try to use verification information from oat file, otherwise do runtime verification
+ const DexFile& dex_file = FindDexFile(klass->GetDexCache());
+ if (VerifyClassUsingOatFile(dex_file, klass) || verifier::DexVerifier::VerifyClass(klass)) {
+ // Make sure all classes referenced by catch blocks are resolved
+ ResolveClassExceptionHandlerTypes(dex_file, klass);
klass->SetStatus(Class::kStatusVerified);
} else {
LOG(ERROR) << "Verification failed on class " << PrettyClass(klass);
Thread* self = Thread::Current();
- CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+ CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException()) << PrettyClass(klass);
self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed",
PrettyDescriptor(klass).c_str());
- CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyClass(klass);
klass->SetStatus(Class::kStatusError);
}
}
+bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) {
+ if (!Runtime::Current()->IsStarted()) {
+ return false;
+ }
+ if (ClassLoader::UseCompileTimeClassPath()) {
+ return false;
+ }
+ const OatFile* oat_file = FindOatFileForDexFile(dex_file);
+ if (oat_file == NULL) {
+ return false;
+ }
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ CHECK(oat_dex_file != NULL) << PrettyClass(klass);
+ const char* descriptor = ClassHelper(klass).GetDescriptor();
+ uint32_t class_def_index;
+ bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+ CHECK(found) << descriptor;
+ UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
+ CHECK(oat_class.get() != NULL) << descriptor;
+ Class::Status status = oat_class->GetStatus();
+ if (status == Class::kStatusError) {
+ ThrowEarlierClassFailure(klass);
+ klass->SetVerifyErrorClass(Thread::Current()->GetException()->GetClass());
+ klass->SetStatus(Class::kStatusError);
+ return true;
+ }
+ if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
+ return true;
+ }
+ if (status == Class::kStatusNotReady) {
+ return false;
+ }
+ LOG(FATAL) << "Unexpected class status: " << status;
+ return false;
+}
+
+void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass) {
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+ ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
+ }
+ for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+ ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i));
+ }
+}
+
+void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* method) {
+ // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
+ const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
+ if (code_item == NULL) {
+ return; // native or abstract method
+ }
+ if (code_item->tries_size_ == 0) {
+ return; // nothing to process
+ }
+ const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ for (uint32_t idx = 0; idx < handlers_size; idx++) {
+ CatchHandlerIterator iterator(handlers_ptr);
+ for (; iterator.HasNext(); iterator.Next()) {
+ // Ensure exception types are resolved so that they don't need resolution to be delivered,
+ // unresolved exception types will be ignored by exception delivery
+ if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method);
+ if (exception_type == NULL) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ Thread::Current()->ClearException();
+ }
+ }
+ }
+ handlers_ptr = iterator.EndDataPointer();
+ }
+}
+
static void CheckProxyConstructor(Method* constructor);
static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype);
@@ -2025,7 +2104,7 @@
return false;
}
- DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified);
+ DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified) << PrettyClass(klass);
klass->SetClinitThreadId(self->GetTid());
klass->SetStatus(Class::kStatusInitializing);
@@ -2211,7 +2290,7 @@
if (!super_initialized) {
if (!can_run_clinit) {
// Don't set status to error when we can't run <clinit>.
- CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing) << PrettyClass(klass);
klass->SetStatus(Class::kStatusVerified);
return false;
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 45b1aa2..fde4d5f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -266,6 +266,9 @@
ObjectArray<StackTraceElement>* AllocStackTraceElementArray(size_t length);
void VerifyClass(Class* klass);
+ bool VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass);
+ void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass);
+ void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* klass);
Class* CreateProxyClass(String* name, ObjectArray<Class>* interfaces, ClassLoader* loader,
ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 8b0e1a1..f680d2b 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -439,7 +439,6 @@
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_), "dexCacheResolvedMethods"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_), "dexCacheResolvedTypes"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_), "dexCacheStrings"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_), "gcMap"));
// alphabetical 32-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_), "accessFlags"));
@@ -448,6 +447,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, 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/common_test.h b/src/common_test.h
index c89527c..402766f 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -105,6 +105,7 @@
const uint32_t fp_spill_mask,
const uint32_t* mapping_table,
const uint16_t* vmap_table,
+ const uint8_t* gc_map,
const Method::InvokeStub* invoke_stub) {
return OatFile::OatMethod(NULL,
reinterpret_cast<uint32_t>(code),
@@ -113,6 +114,7 @@
fp_spill_mask,
reinterpret_cast<uint32_t>(mapping_table),
reinterpret_cast<uint32_t>(vmap_table),
+ reinterpret_cast<uint32_t>(gc_map),
reinterpret_cast<uint32_t>(invoke_stub));
}
@@ -148,6 +150,7 @@
compiled_method->GetFpSpillMask(),
&compiled_method->GetMappingTable()[0],
&compiled_method->GetVmapTable()[0],
+ NULL,
method_invoke_stub);
oat_method.LinkMethodPointers(method);
} else {
@@ -160,6 +163,7 @@
0,
NULL,
NULL,
+ NULL,
method_invoke_stub);
oat_method.LinkMethodPointers(method);
}
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 67bdd9a..40230b4 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -5,16 +5,17 @@
namespace art {
CompiledMethod::CompiledMethod(InstructionSet instruction_set,
- std::vector<short>& short_code,
+ const std::vector<uint16_t>& short_code,
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)
+ const std::vector<uint32_t>& mapping_table,
+ const std::vector<uint16_t>& vmap_table)
: instruction_set_(instruction_set), frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
CHECK_NE(short_code.size(), 0U);
CHECK_GE(vmap_table.size(), 1U); // should always contain an entry for LR
+ CHECK_LE(vmap_table.size(), (1U << 16) - 1); // length must fit in 2^16-1
size_t code_byte_count = short_code.size() * sizeof(short_code[0]);
std::vector<uint8_t> byte_code(code_byte_count);
@@ -42,8 +43,33 @@
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);
+
+ // Should only be used with CompiledMethods created with oatCompileMethod
+ CHECK_NE(mapping_table_.size(), 0U);
+ CHECK_NE(vmap_table_.size(), 0U);
+
+ std::vector<uint8_t> length_prefixed_gc_map;
+ length_prefixed_gc_map.push_back((gc_map.size() & 0xff000000) >> 24);
+ length_prefixed_gc_map.push_back((gc_map.size() & 0x00ff0000) >> 16);
+ length_prefixed_gc_map.push_back((gc_map.size() & 0x0000ff00) >> 8);
+ length_prefixed_gc_map.push_back((gc_map.size() & 0x000000ff) >> 0);
+ length_prefixed_gc_map.insert(length_prefixed_gc_map.end(),
+ gc_map.begin(),
+ gc_map.end());
+ DCHECK_EQ(gc_map.size() + 4, length_prefixed_gc_map.size());
+ DCHECK_EQ(gc_map.size(),
+ static_cast<size_t>((length_prefixed_gc_map[0] << 24) |
+ (length_prefixed_gc_map[1] << 16) |
+ (length_prefixed_gc_map[2] << 8) |
+ (length_prefixed_gc_map[3] << 0)));
+
+ gc_map_ = length_prefixed_gc_map;
+}
+
CompiledMethod::CompiledMethod(InstructionSet instruction_set,
- std::vector<uint8_t>& code,
+ const std::vector<uint8_t>& code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask)
@@ -82,6 +108,10 @@
return vmap_table_;
}
+const std::vector<uint8_t>& CompiledMethod::GetGcMap() const {
+ return gc_map_;
+}
+
uint32_t CompiledMethod::AlignCode(uint32_t offset) const {
return AlignCode(offset, instruction_set_);
}
diff --git a/src/compiled_method.h b/src/compiled_method.h
index 4b5a78b..4528e52 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -14,16 +14,19 @@
public:
// Create a CompiledMethod from the oatCompileMethod
CompiledMethod(InstructionSet instruction_set,
- std::vector<short>& code,
+ const std::vector<uint16_t>& code,
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);
+ const std::vector<uint32_t>& mapping_table,
+ const std::vector<uint16_t>& vmap_table);
+
+ // Add a GC map to a CompiledMethod created by oatCompileMethod
+ void SetGcMap(const std::vector<uint8_t>& gc_map);
// Create a CompiledMethod from the JniCompiler
CompiledMethod(InstructionSet instruction_set,
- std::vector<uint8_t>& code,
+ const std::vector<uint8_t>& code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask);
@@ -37,6 +40,8 @@
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;
+
// Aligns an offset from a page aligned value to make it suitable
// for code storage. important to ensure that PC relative value
// computations work out as expected on ARM.
@@ -61,6 +66,7 @@
const uint32_t fp_spill_mask_;
std::vector<uint32_t> mapping_table_;
std::vector<uint16_t> vmap_table_;
+ std::vector<uint8_t> gc_map_;
};
class CompiledInvokeStub {
diff --git a/src/compiler.cc b/src/compiler.cc
index 88e156d..d700adb 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -8,6 +8,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "dex_cache.h"
+#include "dex_verifier.h"
#include "jni_compiler.h"
#include "jni_internal.h"
#include "oat_file.h"
@@ -136,6 +137,7 @@
void Compiler::PostCompile(const ClassLoader* class_loader,
const std::vector<const DexFile*>& dex_files) {
+ SetGcMaps(class_loader, dex_files);
SetCodeAndDirectMethods(dex_files);
}
@@ -481,6 +483,70 @@
return it->second;
}
+void Compiler::SetGcMaps(const ClassLoader* 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(const ClassLoader* class_loader, const DexFile& dex_file) {
+ 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, true);
+ SetGcMapsMethod(dex_file, method);
+ it.Next();
+ }
+ while (it.HasNextVirtualMethod()) {
+ Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
+ class_loader, false);
+ 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::DexVerifier::GetGcMap(ref);
+ if (gc_map == NULL) {
+ return;
+ }
+ compiled_method->SetGcMap(*gc_map);
+}
+
void Compiler::SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
diff --git a/src/compiler.h b/src/compiler.h
index f59587f..bf21ed6 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -58,10 +58,36 @@
// A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
typedef std::pair<const DexFile*, uint32_t> ClassReference;
+ struct ClassReferenceHash {
+ size_t operator()(const ClassReference& id) const {
+ size_t dex = reinterpret_cast<size_t>(id.first);
+ DCHECK_NE(dex, static_cast<size_t>(0));
+ dex += 33; // dex is an aligned pointer, get some non-zero low bits
+ size_t idx = id.second;
+ if (idx == 0) { // special case of a method index of 0
+ return dex * 5381;
+ } else {
+ return dex * idx;
+ }
+ }
+ };
CompiledClass* GetCompiledClass(ClassReference ref) const;
// A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
typedef std::pair<const DexFile*, uint32_t> MethodReference;
+ struct MethodReferenceHash {
+ size_t operator()(const MethodReference& id) const {
+ size_t dex = reinterpret_cast<size_t>(id.first);
+ DCHECK_NE(dex, static_cast<size_t>(0));
+ dex += 33; // dex is an aligned pointer, get some non-zero low bits
+ size_t idx = id.second;
+ if (idx == 0) { // special case of a method index of 0
+ return dex * 5381;
+ } else {
+ return dex * idx;
+ }
+ }
+ };
CompiledMethod* GetCompiledMethod(MethodReference ref) const;
const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
@@ -116,6 +142,10 @@
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx,
const ClassLoader* class_loader, const DexFile& dex_file);
+ void SetGcMaps(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+ void SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
+ void SetGcMapsMethod(const DexFile& dex_file, Method* method);
+
// After compiling, walk all the DexCaches and set the code and
// method pointers of CodeAndDirectMethods entries in the DexCaches.
void SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files);
@@ -127,36 +157,10 @@
InstructionSet instruction_set_;
JniCompiler jni_compiler_;
- struct ClassReferenceHash {
- size_t operator()(const ClassReference& id) const {
- size_t dex = reinterpret_cast<size_t>(id.first);
- DCHECK_NE(dex, static_cast<size_t>(0));
- dex += 33; // dex is an aligned pointer, get some non-zero low bits
- size_t idx = id.second;
- if (idx == 0) { // special case of a method index of 0
- return dex * 5381;
- } else {
- return dex * idx;
- }
- }
- };
typedef std::tr1::unordered_map<const ClassReference, CompiledClass*, ClassReferenceHash> ClassTable;
// All class references that this compiler has compiled
ClassTable compiled_classes_;
- struct MethodReferenceHash {
- size_t operator()(const MethodReference& id) const {
- size_t dex = reinterpret_cast<size_t>(id.first);
- DCHECK_NE(dex, static_cast<size_t>(0));
- dex += 33; // dex is an aligned pointer, get some non-zero low bits
- size_t idx = id.second;
- if (idx == 0) { // special case of a method index of 0
- return dex * 5381;
- } else {
- return dex * idx;
- }
- }
- };
typedef std::tr1::unordered_map<const MethodReference, CompiledMethod*, MethodReferenceHash> MethodTable;
// All method references that this compiler has compiled
MethodTable compiled_methods_;
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 49c84c1..2e89ab5 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -215,7 +215,7 @@
int totalSize; // header + code size
AssemblerStatus assemblerStatus; // Success or fix and retry
int assemblerRetries;
- std::vector<short> codeBuffer;
+ std::vector<uint16_t> codeBuffer;
std::vector<uint32_t> mappingTable;
std::vector<uint16_t> coreVmapTable;
std::vector<uint16_t> fpVmapTable;
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 9a1a30e..a73a27a 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -974,12 +974,12 @@
*/
#define PADDING_MOV_R5_R5 0x1C2D
-STATIC void pushWord(std::vector<short>&buf, int data) {
+STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
buf.push_back( data & 0xffff);
buf.push_back( (data >> 16) & 0xffff);
}
-void alignBuffer(std::vector<short>&buf, size_t offset) {
+void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
while (buf.size() < (offset/2))
buf.push_back(0);
}
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 1172186..00b226d 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -5,6 +5,7 @@
#include <iostream>
#include "class_linker.h"
+#include "compiler.h"
#include "dex_cache.h"
#include "dex_file.h"
#include "dex_instruction.h"
@@ -842,7 +843,7 @@
return changed;
}
-void RegisterLine::WriteReferenceBitMap(int8_t* data, size_t max_bytes) {
+void RegisterLine::WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes) {
for (size_t i = 0; i < num_regs_; i += 8) {
uint8_t val = 0;
for (size_t j = 0; j < 8 && (i + j) < num_regs_; j++) {
@@ -851,10 +852,12 @@
val |= 1 << j;
}
}
- if (val != 0) {
- DCHECK_LT(i / 8, max_bytes);
- data[i / 8] = val;
+ if ((i / 8) >= max_bytes) {
+ DCHECK_EQ(0, val);
+ continue;
}
+ DCHECK_LT(i / 8, max_bytes) << "val=" << static_cast<uint32_t>(val);
+ data.push_back(val);
}
}
@@ -966,12 +969,18 @@
<< verifier.info_messages_.str() << Dumpable<DexVerifier>(verifier);
}
-DexVerifier::DexVerifier(Method* method) : work_insn_idx_(-1), method_(method),
- failure_(VERIFY_ERROR_NONE),
-
- new_instance_count_(0), monitor_enter_count_(0) {
+DexVerifier::DexVerifier(Method* method)
+ : work_insn_idx_(-1),
+ method_(method),
+ failure_(VERIFY_ERROR_NONE),
+ new_instance_count_(0),
+ monitor_enter_count_(0) {
+ CHECK(method != NULL);
+ Runtime* runtime = Runtime::Current();
+ // We should only be running the verifier at compile time
+ CHECK(!runtime->IsStarted());
const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ClassLinker* class_linker = runtime->GetClassLinker();
dex_file_ = &class_linker->FindDexFile(dex_cache);
code_item_ = dex_file_->GetCodeItem(method->GetCodeItemOffset());
}
@@ -1063,7 +1072,7 @@
insn_flags_[dex_pc].SetInTry();
}
}
- /* Iterate over each of the handlers to verify target addresses. */
+ // Iterate over each of the handlers to verify target addresses.
const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -1517,13 +1526,14 @@
}
/* Generate a register map and add it to the method. */
- ByteArray* map = GenerateGcMap();
+ const std::vector<uint8_t>* map = GenerateGcMap();
if (map == NULL) {
return false; // Not a real failure, but a failure to encode
}
- method_->SetGcMap(map);
+ Compiler::MethodReference ref(dex_file_, method_->GetDexMethodIndex());
+ verifier::DexVerifier::SetGcMap(ref, *map);
#ifndef NDEBUG
- VerifyGcMap();
+ VerifyGcMap(*map);
#endif
return true;
}
@@ -3712,7 +3722,7 @@
*log2_max_gc_pc = i;
}
-ByteArray* DexVerifier::GenerateGcMap() {
+const std::vector<uint8_t>* DexVerifier::GenerateGcMap() {
size_t num_entries, ref_bitmap_bits, pc_bits;
ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
// There's a single byte to encode the size of each bitmap
@@ -3745,39 +3755,35 @@
return NULL;
}
size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries ) + 4;
- ByteArray* table = ByteArray::Alloc(table_size);
+ std::vector<uint8_t>* table = new std::vector<uint8_t>;
if (table == NULL) {
Fail(VERIFY_ERROR_GENERIC) << "Failed to encode GC map (size=" << table_size << ")";
return NULL;
}
// Write table header
- table->Set(0, format);
- table->Set(1, ref_bitmap_bytes);
- table->Set(2, num_entries & 0xFF);
- table->Set(3, (num_entries >> 8) & 0xFF);
+ table->push_back(format);
+ table->push_back(ref_bitmap_bytes);
+ table->push_back(num_entries & 0xFF);
+ table->push_back((num_entries >> 8) & 0xFF);
// Write table data
- size_t offset = 4;
for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
if (insn_flags_[i].IsGcPoint()) {
- table->Set(offset, i & 0xFF);
- offset++;
+ table->push_back(i & 0xFF);
if (pc_bytes == 2) {
- table->Set(offset, (i >> 8) & 0xFF);
- offset++;
+ table->push_back((i >> 8) & 0xFF);
}
RegisterLine* line = reg_table_.GetLine(i);
- line->WriteReferenceBitMap(table->GetData() + offset, ref_bitmap_bytes);
- offset += ref_bitmap_bytes;
+ line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
}
}
- DCHECK(offset == table_size);
+ DCHECK_EQ(table->size(), table_size);
return table;
}
-void DexVerifier::VerifyGcMap() {
+void DexVerifier::VerifyGcMap(const std::vector<uint8_t>& data) {
// Check that for every GC point there is a map entry, there aren't entries for non-GC points,
// that the table data is well formed and all references are marked (or not) in the bitmap
- PcToReferenceMap map(method_);
+ PcToReferenceMap map(&data[0], data.size());
size_t map_index = 0;
for(size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
const uint8_t* reg_bitmap = map.FindBitMap(i, false);
@@ -3834,5 +3840,26 @@
return NULL;
}
+DexVerifier::GcMapTable DexVerifier::gc_maps_;
+
+void DexVerifier::SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) {
+ CHECK(GetGcMap(ref) == NULL);
+ gc_maps_[ref] = &gc_map;
+ CHECK(GetGcMap(ref) != NULL);
+}
+
+const std::vector<uint8_t>* DexVerifier::GetGcMap(Compiler::MethodReference ref) {
+ GcMapTable::const_iterator it = gc_maps_.find(ref);
+ if (it == gc_maps_.end()) {
+ return NULL;
+ }
+ CHECK(it->second != NULL);
+ return it->second;
+}
+
+void DexVerifier::DeleteGcMaps() {
+ STLDeleteValues(&gc_maps_);
+}
+
} // namespace verifier
} // namespace art
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index a0819e6..263dcae 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -4,11 +4,13 @@
#define ART_SRC_DEX_VERIFY_H_
#include "casts.h"
+#include "compiler.h"
#include "dex_file.h"
#include "dex_instruction.h"
#include "macros.h"
#include "object.h"
#include "stl_util.h"
+#include "unordered_map.h"
#include "UniquePtr.h"
#include <deque>
@@ -17,6 +19,7 @@
#include <vector>
namespace art {
+
namespace verifier {
class DexVerifier;
@@ -702,7 +705,7 @@
}
// Write a bit at each register location that holds a reference
- void WriteReferenceBitMap(int8_t* data, size_t max_bytes);
+ void WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes);
private:
void CopyRegToLockDepth(size_t dst, size_t src) {
@@ -864,6 +867,9 @@
// information
void Dump(std::ostream& os);
+ static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref);
+ static void DeleteGcMaps();
+
private:
explicit DexVerifier(Method* method);
@@ -1173,10 +1179,10 @@
* encode it in some clever fashion.
* Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
*/
- ByteArray* GenerateGcMap();
+ const std::vector<uint8_t>* GenerateGcMap();
// Verify that the GC map associated with method_ is well formed
- void VerifyGcMap();
+ void VerifyGcMap(const std::vector<uint8_t>& data);
// Compute sizes for GC map data
void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
@@ -1185,6 +1191,13 @@
return insn_flags_[work_insn_idx_];
}
+ typedef std::tr1::unordered_map<const Compiler::MethodReference,
+ const std::vector<uint8_t>*,
+ Compiler::MethodReferenceHash> GcMapTable;
+ // All the GC maps that the verifier has created
+ static GcMapTable gc_maps_;
+ static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map);
+
RegTypeCache reg_types_;
PcToRegisterLineTable reg_table_;
@@ -1220,11 +1233,11 @@
// Lightweight wrapper for PC to reference bit maps.
class PcToReferenceMap {
public:
- PcToReferenceMap(Method* m) {
- data_ = down_cast<ByteArray*>(m->GetGcMap());
- CHECK(data_ != NULL) << PrettyMethod(m);
+ PcToReferenceMap(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_->GetLength() - 4;
+ size_t data_size = data_length - 4;
DCHECK_EQ(EntryWidth() * NumEntries(), data_size);
}
@@ -1288,9 +1301,9 @@
}
const uint8_t* GetData() const {
- return reinterpret_cast<uint8_t*>(data_->GetData());
+ return data_;
}
- ByteArray* data_; // The header and table data
+ const uint8_t* data_; // The header and table data
};
} // namespace verifier
diff --git a/src/image_writer.cc b/src/image_writer.cc
index f6d144e..861a878 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -398,6 +398,10 @@
uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
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);
}
}
diff --git a/src/oat.cc b/src/oat.cc
index 0089410..c458ea3 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -72,6 +72,7 @@
fp_spill_mask_(0),
mapping_table_offset_(0),
vmap_table_offset_(0),
+ gc_map_offset_(0),
invoke_stub_offset_(0) {}
OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
@@ -80,6 +81,7 @@
uint32_t fp_spill_mask,
uint32_t mapping_table_offset,
uint32_t vmap_table_offset,
+ uint32_t gc_map_offset,
uint32_t invoke_stub_offset)
: code_offset_(code_offset),
frame_size_in_bytes_(frame_size_in_bytes),
@@ -87,6 +89,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),
invoke_stub_offset_(invoke_stub_offset) {}
OatMethodOffsets::~OatMethodOffsets() {}
diff --git a/src/oat.h b/src/oat.h
index 0ffc80f..4023aed 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -45,6 +45,7 @@
uint32_t fp_spill_mask,
uint32_t mapping_table_offset,
uint32_t vmap_table_offset,
+ uint32_t gc_map_offset,
uint32_t invoke_stub_offset);
~OatMethodOffsets();
@@ -54,6 +55,7 @@
uint32_t fp_spill_mask_;
uint32_t mapping_table_offset_;
uint32_t vmap_table_offset_;
+ uint32_t gc_map_offset_;
uint32_t invoke_stub_offset_;
};
diff --git a/src/oat_file.cc b/src/oat_file.cc
index a4bbc5f..6ffcb52 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -216,6 +216,7 @@
oat_method_offsets.fp_spill_mask_,
oat_method_offsets.mapping_table_offset_,
oat_method_offsets.vmap_table_offset_,
+ oat_method_offsets.gc_map_offset_,
oat_method_offsets.invoke_stub_offset_);
}
@@ -226,6 +227,7 @@
const uint32_t fp_spill_mask,
const uint32_t mapping_table_offset,
const uint32_t vmap_table_offset,
+ const uint32_t gc_map_offset,
const uint32_t invoke_stub_offset)
: base_(base),
code_offset_(code_offset),
@@ -234,6 +236,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),
invoke_stub_offset_(invoke_stub_offset) {
#ifndef NDEBUG
@@ -260,6 +263,7 @@
method->SetFpSpillMask(fp_spill_mask_);
method->SetMappingTable(GetMappingTable());
method->SetVmapTable(GetVmapTable());
+ method->SetGcMap(GetGcMap());
method->SetInvokeStub(GetInvokeStub());
}
@@ -271,6 +275,7 @@
method->SetFpSpillMask(GetFpSpillMask());
method->SetOatMappingTableOffset(GetMappingTableOffset());
method->SetOatVmapTableOffset(GetVmapTableOffset());
+ method->SetOatGcMapOffset(GetGcMapOffset());
method->SetOatInvokeStubOffset(GetInvokeStubOffset());
}
diff --git a/src/oat_file.h b/src/oat_file.h
index 33a0e28..07e235b 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -61,6 +61,9 @@
uint32_t GetVmapTableOffset() const {
return vmap_table_offset_;
}
+ uint32_t GetGcMapOffset() const {
+ return gc_map_offset_;
+ }
uint32_t GetInvokeStubOffset() const {
return invoke_stub_offset_;
}
@@ -74,6 +77,9 @@
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 Method::InvokeStub* GetInvokeStub() const {
return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
}
@@ -88,6 +94,7 @@
const uint32_t fp_spill_mask,
const uint32_t mapping_table_offset,
const uint32_t vmap_table_offset,
+ const uint32_t gc_map_offset,
const uint32_t invoke_stub_offset);
private:
@@ -107,6 +114,7 @@
uint32_t fp_spill_mask_;
uint32_t mapping_table_offset_;
uint32_t vmap_table_offset_;
+ uint32_t gc_map_offset_;
uint32_t invoke_stub_offset_;
friend class OatClass;
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 806ac71..9690142 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -193,6 +193,7 @@
uint32_t fp_spill_mask = 0;
uint32_t mapping_table_offset = 0;
uint32_t vmap_table_offset = 0;
+ uint32_t gc_map_offset = 0;
// derived from CompiledInvokeStub if available
uint32_t invoke_stub_offset = 0;
@@ -258,6 +259,20 @@
offset += vmap_table_size;
oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
}
+
+ const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+ size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+ gc_map_offset = (gc_map_size == 0) ? 0 : offset;
+
+ // Deduplicate GC maps
+ std::map<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
+ if (gc_map_iter != gc_map_offsets_.end()) {
+ gc_map_offset = gc_map_iter->second;
+ } else {
+ gc_map_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&gc_map, gc_map_offset));
+ offset += gc_map_size;
+ oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
+ }
}
const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
@@ -287,6 +302,7 @@
fp_spill_mask,
mapping_table_offset,
vmap_table_offset,
+ gc_map_offset,
invoke_stub_offset);
if (compiler_->IsImage()) {
@@ -301,6 +317,7 @@
method->SetOatMappingTableOffset(mapping_table_offset);
method->SetOatCodeOffset(code_offset);
method->SetOatVmapTableOffset(vmap_table_offset);
+ method->SetOatGcMapOffset(gc_map_offset);
method->SetOatInvokeStubOffset(invoke_stub_offset);
}
return offset;
@@ -567,6 +584,29 @@
code_offset += vmap_table_size;
}
DCHECK_CODE_OFFSET();
+
+ const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+ size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+
+ // Deduplicate GC maps
+ std::map<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
+ gc_map_offsets_.find(&gc_map);
+ if (gc_map_iter != gc_map_offsets_.end() &&
+ code_offset != method_offsets.gc_map_offset_) {
+ DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+ || gc_map_iter->second == method_offsets.gc_map_offset_)
+ << PrettyMethod(method_idx, dex_file);
+ } else {
+ DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+ || code_offset == method_offsets.gc_map_offset_)
+ << PrettyMethod(method_idx, dex_file);
+ if (!file->WriteFully(&gc_map[0], gc_map_size)) {
+ ReportWriteFailure("GC map", method_idx, dex_file, file);
+ return false;
+ }
+ code_offset += gc_map_size;
+ }
+ DCHECK_CODE_OFFSET();
}
const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 6ae0f4e..d1983a5 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -147,6 +147,7 @@
std::map<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > code_offsets_;
std::map<const std::vector<uint16_t>*, uint32_t, MapCompare<std::vector<uint16_t> > > vmap_table_offsets_;
std::map<const std::vector<uint32_t>*, uint32_t, MapCompare<std::vector<uint32_t> > > mapping_table_offsets_;
+ std::map<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > gc_map_offsets_;
DISALLOW_COPY_AND_ASSIGN(OatWriter);
};
diff --git a/src/oatdump.cc b/src/oatdump.cc
index dd46896..91f4091 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -122,9 +122,10 @@
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);
- os << StringPrintf("%d: %s (type_idx=%d)\n", class_def_index, descriptor, class_def.class_idx_);
UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
CHECK(oat_class.get() != NULL);
+ os << StringPrintf("%d: %s (type_idx=%d) (", class_def_index, descriptor, class_def.class_idx_)
+ << oat_class->GetStatus() << ")\n";
DumpOatClass(os, oat_file, *oat_class.get(), *dex_file, class_def);
}
@@ -189,6 +190,8 @@
oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
+ os << StringPrintf("\t\tgc_map: %p (offset=%08x)\n",
+ oat_method.GetGcMap(), oat_method.GetGcMapOffset());
os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
}
@@ -342,29 +345,36 @@
StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
}
DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+ DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else if (method->IsAbstract()) {
StringAppendF(&summary, "\tABSTRACT\n");
DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+ DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else if (method->IsCalleeSaveMethod()) {
StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+ DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else {
- if (method->GetGcMap() != NULL) {
- size_t register_map_bytes = method->GetGcMap()->SizeOf();
- state->stats_.register_map_bytes += register_map_bytes;
- }
+ DCHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
+ DCHECK_NE(0U, method->GetGcMapLength()) << PrettyMethod(method);
- if (method->GetMappingTable() != NULL) {
- size_t pc_mapping_table_bytes = method->GetMappingTableLength();
- state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
- }
+ size_t register_map_bytes = method->GetGcMapLength();
+ state->stats_.register_map_bytes += register_map_bytes;
+ StringAppendF(&summary, "GC=%d ", register_map_bytes);
+
+ size_t pc_mapping_table_bytes = method->GetMappingTableLength();
+ state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
+ StringAppendF(&summary, "Mapping=%d ", pc_mapping_table_bytes);
const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
state->stats_.dex_instruction_bytes += dex_instruction_bytes;
+
+ StringAppendF(&summary, "\tSIZE Code=%d GC=%d Mapping=%d",
+ dex_instruction_bytes, register_map_bytes, pc_mapping_table_bytes);
}
}
state->os_ << summary << std::flush;
diff --git a/src/object.h b/src/object.h
index 5977977..7730974 100644
--- a/src/object.h
+++ b/src/object.h
@@ -701,12 +701,39 @@
SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
}
- Object* GetGcMap() const {
- return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
+ 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);
}
- void SetGcMap(Object* data) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, 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 {
+ DCHECK(!Runtime::Current()->IsStarted());
+ return reinterpret_cast<uint32_t>(GetGcMapRaw());
+ }
+ void SetOatGcMapOffset(uint32_t gc_map_offset) {
+ DCHECK(!Runtime::Current()->IsStarted());
+ SetGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
}
size_t GetFrameSizeInBytes() const {
@@ -859,9 +886,6 @@
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<String>* dex_cache_strings_;
- // Garbage collection map
- Object* gc_map_;
-
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
@@ -881,6 +905,9 @@
// Total size in bytes of the frame
size_t frame_size_in_bytes_;
+ // Garbage collection map
+ const uint8_t* gc_map_;
+
// Native invocation stub entry point for calling from native to managed code.
const InvokeStub* invoke_stub_;
diff --git a/src/thread.cc b/src/thread.cc
index a1df41b..6bee2c8 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1495,7 +1495,9 @@
}
// Process register map (which native and callee save methods don't have)
if (!m->IsNative() && !m->IsCalleeSaveMethod() && !m->IsProxyMethod()) {
- verifier::PcToReferenceMap map(m);
+ CHECK(m->GetGcMap() != NULL) << PrettyMethod(m);
+ CHECK_NE(0U, m->GetGcMapLength()) << PrettyMethod(m);
+ verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
CHECK(reg_bitmap != NULL);
const VmapTable vmap_table(m->GetVmapTableRaw());
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index 547f8c9..a85e4ee 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -36,7 +36,7 @@
}
LOG(INFO) << "At " << PrettyMethod(m, false);
- verifier::PcToReferenceMap map(m);
+ verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
if (!pc) {
// pc == NULL: m is either a native method or a phony method
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index 5b3921d..a967835 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -38,7 +38,7 @@
CHECK_EQ(pc, 0u);
return;
}
- verifier::PcToReferenceMap map(m);
+ verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
MethodHelper mh(m);
StringPiece m_name(mh.GetName());