Fix 065 and 066 tests (NULL Method bug). Don't use Method in LLVM method compiler.
Change-Id: I98e4e9b329448b1b72c3b5c9d712ea68dab624bd
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 8932b47..49717fc 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -19,6 +19,7 @@
#include "backend_types.h"
#include "compilation_unit.h"
#include "compiler.h"
+#include "dex_verifier.h"
#include "inferred_reg_category_map.h"
#include "ir_builder.h"
#include "logging.h"
@@ -55,8 +56,6 @@
dex_cache_(oat_compilation_unit->dex_cache_),
code_item_(oat_compilation_unit->code_item_),
oat_compilation_unit_(oat_compilation_unit),
- method_(dex_cache_->GetResolvedMethod(oat_compilation_unit->method_idx_)),
- method_helper_(method_),
method_idx_(oat_compilation_unit->method_idx_),
access_flags_(oat_compilation_unit->access_flags_),
module_(cunit->GetModule()),
@@ -82,7 +81,7 @@
// Get function type
llvm::FunctionType* func_type =
- GetFunctionType(method_idx_, method_->IsStatic());
+ GetFunctionType(method_idx_, oat_compilation_unit_->IsStatic());
// Create function
func_ = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
@@ -96,7 +95,7 @@
arg_iter->setName("method");
++arg_iter;
- if (!method_->IsStatic()) {
+ if (!oat_compilation_unit_->IsStatic()) {
DCHECK_NE(arg_iter, arg_end);
arg_iter->setName("this");
++arg_iter;
@@ -216,7 +215,7 @@
irb_.CreateCall(irb_.GetRuntime(ThrowStackOverflowException));
// Unwind.
- char ret_shorty = method_helper_.GetShorty()[0];
+ char ret_shorty = oat_compilation_unit_->GetShorty()[0];
if (ret_shorty == 'V') {
irb_.CreateRetVoid();
} else {
@@ -294,19 +293,19 @@
llvm::Function::arg_iterator arg_iter(func_->arg_begin());
llvm::Function::arg_iterator arg_end(func_->arg_end());
- char const* shorty = method_helper_.GetShorty();
- int32_t shorty_size = method_helper_.GetShortyLength();
- CHECK_LE(1, shorty_size);
+ uint32_t shorty_size = 0;
+ char const* shorty = oat_compilation_unit_->GetShorty(&shorty_size);
+ CHECK_GE(shorty_size, 1u);
++arg_iter; // skip method object
- if (!method_->IsStatic()) {
+ if (!oat_compilation_unit_->IsStatic()) {
EmitStoreDalvikReg(arg_reg, kObject, kAccurate, arg_iter);
++arg_iter;
++arg_reg;
}
- for (int32_t i = 1; i < shorty_size; ++i, ++arg_iter) {
+ for (uint32_t i = 1; i < shorty_size; ++i, ++arg_iter) {
EmitStoreDalvikReg(arg_reg, shorty[i], kAccurate, arg_iter);
++arg_reg;
@@ -1319,7 +1318,7 @@
// the return value might be collected since the shadow stack is popped.
// Return!
- char ret_shorty = method_helper_.GetShorty()[0];
+ char ret_shorty = oat_compilation_unit_->GetShorty()[0];
llvm::Value* retval = EmitLoadDalvikReg(dec_insn.vA, ret_shorty, kAccurate);
irb_.CreateRet(retval);
@@ -1812,40 +1811,41 @@
EmitAllocNewArray(dex_pc, dec_insn.vA, dec_insn.vB, true);
if (dec_insn.vA > 0) {
- llvm::Value* object_addr_int =
- irb_.CreatePtrToInt(object_addr, irb_.getPtrEquivIntTy());
-
- // TODO: currently FilledNewArray doesn't support I, J, D and L, [ so computing the component
- // size using int alignment is safe. This code should determine the width of the FilledNewArray
- // component.
- llvm::Value* data_field_offset =
- irb_.getPtrEquivInt(Array::DataOffset(sizeof(int32_t)).Int32Value());
-
- llvm::Value* data_field_addr_int =
- irb_.CreateAdd(object_addr_int, data_field_offset);
-
- Class* klass = method_->GetDexCacheResolvedTypes()->Get(dec_insn.vB);
+ // Resolve the element type
+ Class* klass = dex_cache_->GetResolvedType(dec_insn.vB);
+ // TODO: Avoid the usage of the dex_cache_. Try to figure out a better
+ // way to distinguish [I and [L.
CHECK_NE(klass, static_cast<Class*>(NULL));
- // Moved this below already: CHECK(!klass->IsPrimitive() || klass->IsPrimitiveInt());
- llvm::Constant* word_size = irb_.getSizeOfPtrEquivIntValue();
+ uint32_t alignment;
+ llvm::Constant* elem_size;
+ llvm::PointerType* field_type;
- llvm::Type* field_type;
+ // NOTE: Currently filled-new-array only supports 'L', '[', and 'I'
+ // as the element, thus we are only checking 2 cases: primitive int and
+ // non-primitive type.
if (klass->IsPrimitiveInt()) {
+ alignment = sizeof(int32_t);
+ elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
field_type = irb_.getJIntTy()->getPointerTo();
} else {
CHECK(!klass->IsPrimitive());
+ alignment = irb_.getSizeOfPtrEquivInt();
+ elem_size = irb_.getSizeOfPtrEquivIntValue();
field_type = irb_.getJObjectTy()->getPointerTo();
}
+ llvm::Value* data_field_offset =
+ irb_.getPtrEquivInt(Array::DataOffset(alignment).Int32Value());
+
+ llvm::Value* data_field_addr =
+ irb_.CreatePtrDisp(object_addr, data_field_offset, field_type);
+
// TODO: Tune this code. Currently we are generating one instruction for
// one element which may be very space consuming. Maybe changing to use
// memcpy may help; however, since we can't guarantee that the alloca of
// dalvik register are continuous, we can't perform such optimization yet.
for (uint32_t i = 0; i < dec_insn.vA; ++i) {
- llvm::Value* data_field_addr =
- irb_.CreateIntToPtr(data_field_addr_int, field_type);
-
int reg_index;
if (is_range) {
reg_index = dec_insn.vC + i;
@@ -1862,7 +1862,8 @@
irb_.CreateStore(reg_value, data_field_addr);
- data_field_addr_int = irb_.CreateAdd(data_field_addr_int, word_size);
+ data_field_addr =
+ irb_.CreatePtrDisp(data_field_addr, elem_size, field_type);
}
}
@@ -2209,7 +2210,12 @@
RegCategory MethodCompiler::GetInferredRegCategory(uint32_t dex_pc,
uint16_t reg_idx) {
- InferredRegCategoryMap const* map = method_->GetInferredRegCategoryMap();
+
+ Compiler::MethodReference mref(dex_file_, method_idx_);
+
+ InferredRegCategoryMap const* map =
+ verifier::DexVerifier::GetInferredRegCategoryMap(mref);
+
CHECK_NE(map, static_cast<InferredRegCategoryMap*>(NULL));
return map->GetRegCategory(dex_pc, reg_idx);
@@ -2361,12 +2367,11 @@
void MethodCompiler::PrintUnresolvedFieldWarning(int32_t field_idx) {
- DexFile const& dex_file = method_helper_.GetDexFile();
- DexFile::FieldId const& field_id = dex_file.GetFieldId(field_idx);
+ DexFile::FieldId const& field_id = dex_file_->GetFieldId(field_idx);
LOG(WARNING) << "unable to resolve static field " << field_idx << " ("
- << dex_file.GetFieldName(field_id) << ") in "
- << dex_file.GetFieldDeclaringClassDescriptor(field_id);
+ << dex_file_->GetFieldName(field_id) << ") in "
+ << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
}
@@ -3622,9 +3627,6 @@
// Verify the generated bitcode
llvm::verifyFunction(*func_, llvm::PrintMessageAction);
- // Delete the inferred register category map (won't be used anymore)
- method_->ResetInferredRegCategoryMap();
-
// Add the memory usage approximation of the compilation unit
cunit_->AddMemUsageApproximation(code_item_->insns_size_in_code_units_ * 900);
// NOTE: From statistic, the bitcode size is 4.5 times bigger than the
@@ -3823,7 +3825,7 @@
EmitPopShadowFrame();
// Emit the code to return default value (zero) for the given return type.
- char ret_shorty = method_helper_.GetShorty()[0];
+ char ret_shorty = oat_compilation_unit_->GetShorty()[0];
if (ret_shorty == 'V') {
irb_.CreateRetVoid();
} else {
@@ -3947,7 +3949,9 @@
void MethodCompiler::EmitUpdateLineNumFromDexPC(uint32_t dex_pc) {
- EmitUpdateLineNum(dex_file_->GetLineNumFromPC(method_, dex_pc));
+ EmitUpdateLineNum(
+ dex_file_->GetLineNumFromPC(oat_compilation_unit_->IsStatic(),
+ method_idx_, code_item_, dex_pc));
}
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 74c55f0..7b374af 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -447,8 +447,6 @@
DexFile::CodeItem const* code_item_;
OatCompilationUnit* oat_compilation_unit_;
- Method* method_;
- MethodHelper method_helper_;
uint32_t method_idx_;
uint32_t access_flags_;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index c3e7c84..6168f9e 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -580,7 +580,6 @@
return descriptor;
}
-
int32_t DexFile::GetLineNumFromPC(const Method* method, uint32_t rel_pc) const {
// For native method, lineno should be -2 to indicate it is native. Note that
// "line number == -2" is how libcore tells from StackTraceElement.
@@ -588,12 +587,18 @@
return -2;
}
- const CodeItem* code_item = GetCodeItem(method->GetCodeItemOffset());
+ return GetLineNumFromPC(method->IsStatic(), method->GetDexMethodIndex(),
+ GetCodeItem(method->GetCodeItemOffset()), rel_pc);
+}
+
+int32_t DexFile::GetLineNumFromPC(bool is_static, uint32_t method_idx,
+ const CodeItem* code_item,
+ uint32_t rel_pc) const {
DCHECK(code_item != NULL) << GetLocation();
// A method with no line number info should return -1
LineNumFromPcContext context(rel_pc, -1);
- DecodeDebugInfo(code_item, method->IsStatic(), method->GetDexMethodIndex(), LineNumForPcCb,
+ DecodeDebugInfo(code_item, is_static, method_idx, LineNumForPcCb,
NULL, &context);
return context.line_num_;
}
diff --git a/src/dex_file.h b/src/dex_file.h
index e6c8a94..02d0b27 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -755,6 +755,9 @@
// This is used by runtime; therefore use art::Method not art::DexFile::Method.
int32_t GetLineNumFromPC(const Method* method, uint32_t rel_pc) const;
+ int32_t GetLineNumFromPC(bool is_static, uint32_t method_idx,
+ const CodeItem* code_item, uint32_t rel_pc) const;
+
void DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
void* context) const;
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index f02379c..91d6ccd 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -1691,12 +1691,12 @@
Compiler::MethodReference ref(dex_file_, method_->GetDexMethodIndex());
verifier::DexVerifier::SetGcMap(ref, *gc_map);
-#if !defined(ART_USE_LLVM_COMPILER)
method_->SetGcMap(&gc_map->at(0));
-#else
+
+#if defined(ART_USE_LLVM_COMPILER)
/* Generate Inferred Register Category for LLVM-based Code Generator */
const InferredRegCategoryMap* table = GenerateInferredRegCategoryMap();
- method_->SetInferredRegCategoryMap(table);
+ verifier::DexVerifier::SetInferredRegCategoryMap(ref, *table);
#endif
return true;
@@ -4077,7 +4077,7 @@
}
#if defined(ART_USE_LLVM_COMPILER)
-InferredRegCategoryMap const* DexVerifier::GenerateInferredRegCategoryMap() {
+const InferredRegCategoryMap* DexVerifier::GenerateInferredRegCategoryMap() {
uint32_t insns_size = code_item_->insns_size_in_code_units_;
uint16_t regs_size = code_item_->registers_size_;
@@ -4087,7 +4087,7 @@
for (size_t i = 0; i < insns_size; ++i) {
if (RegisterLine* line = reg_table_.GetLine(i)) {
for (size_t r = 0; r < regs_size; ++r) {
- RegType const &rt = line->GetRegisterType(r);
+ const RegType &rt = line->GetRegisterType(r);
if (rt.IsZero()) {
table->SetRegCategory(i, r, kRegZero);
@@ -4106,6 +4106,56 @@
return table.release();
}
+
+Mutex* DexVerifier::inferred_reg_category_maps_lock_ = NULL;
+DexVerifier::InferredRegCategoryMapTable* DexVerifier::inferred_reg_category_maps_ = NULL;
+
+void DexVerifier::InitInferredRegCategoryMaps() {
+ inferred_reg_category_maps_lock_ = new Mutex("verifier GC maps lock");
+ MutexLock mu(*inferred_reg_category_maps_lock_);
+ inferred_reg_category_maps_ = new DexVerifier::InferredRegCategoryMapTable;
+}
+
+void DexVerifier::DeleteInferredRegCategoryMaps() {
+ {
+ MutexLock mu(*inferred_reg_category_maps_lock_);
+ STLDeleteValues(inferred_reg_category_maps_);
+ delete inferred_reg_category_maps_;
+ inferred_reg_category_maps_ = NULL;
+ }
+ delete inferred_reg_category_maps_lock_;
+ inferred_reg_category_maps_lock_ = NULL;
+}
+
+
+void DexVerifier::SetInferredRegCategoryMap(Compiler::MethodReference ref,
+ const InferredRegCategoryMap& inferred_reg_category_map) {
+ MutexLock mu(*inferred_reg_category_maps_lock_);
+ const InferredRegCategoryMap* existing_inferred_reg_category_map =
+ GetInferredRegCategoryMap(ref);
+
+ if (existing_inferred_reg_category_map != NULL) {
+ CHECK(*existing_inferred_reg_category_map == inferred_reg_category_map);
+ delete existing_inferred_reg_category_map;
+ }
+
+ (*inferred_reg_category_maps_)[ref] = &inferred_reg_category_map;
+ CHECK(GetInferredRegCategoryMap(ref) != NULL);
+}
+
+const InferredRegCategoryMap*
+DexVerifier::GetInferredRegCategoryMap(Compiler::MethodReference ref) {
+ MutexLock mu(*inferred_reg_category_maps_lock_);
+
+ InferredRegCategoryMapTable::const_iterator it =
+ inferred_reg_category_maps_->find(ref);
+
+ if (it == inferred_reg_category_maps_->end()) {
+ return NULL;
+ }
+ CHECK(it->second != NULL);
+ return it->second;
+}
#endif
} // namespace verifier
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 46f9ef2..043e4f9 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -922,6 +922,12 @@
static void InitGcMaps();
static void DeleteGcMaps();
+#if defined(ART_USE_LLVM_COMPILER)
+ static const compiler_llvm::InferredRegCategoryMap* GetInferredRegCategoryMap(Compiler::MethodReference ref);
+ static void InitInferredRegCategoryMaps();
+ static void DeleteInferredRegCategoryMaps();
+#endif
+
static bool IsClassRejected(Compiler::ClassReference ref);
private:
@@ -1305,6 +1311,16 @@
static GcMapTable* gc_maps_;
static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map);
+#if defined(ART_USE_LLVM_COMPILER)
+ // All the inferred register category maps that the verifier has created
+ typedef std::map<const Compiler::MethodReference,
+ const compiler_llvm::InferredRegCategoryMap*> InferredRegCategoryMapTable;
+ static Mutex* inferred_reg_category_maps_lock_;
+ static InferredRegCategoryMapTable* inferred_reg_category_maps_;
+ static void SetInferredRegCategoryMap(Compiler::MethodReference ref,
+ const compiler_llvm::InferredRegCategoryMap& m);
+#endif
+
static void AddRejectedClass(Compiler::ClassReference ref);
RegTypeCache reg_types_;
diff --git a/src/oat_compilation_unit.h b/src/oat_compilation_unit.h
index b21a5b0..0000f21 100644
--- a/src/oat_compilation_unit.h
+++ b/src/oat_compilation_unit.h
@@ -46,6 +46,30 @@
callee_access_flags);
}
+ const ClassLoader* GetClassLoader() const {
+ return class_loader_;
+ }
+
+ ClassLinker* GetClassLinker() const {
+ return class_linker_;
+ }
+
+ const DexFile* GetDexFile() const {
+ return dex_file_;
+ }
+
+ DexCache* GetDexCache() const {
+ return dex_cache_;
+ }
+
+ uint32_t GetDexMethodIndex() const {
+ return method_idx_;
+ }
+
+ const DexFile::CodeItem* GetCodeItem() const {
+ return code_item_;
+ }
+
const char* GetShorty() const {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
return dex_file_->GetMethodShorty(method_id);
@@ -56,6 +80,10 @@
return dex_file_->GetMethodShorty(method_id, shorty_len);
}
+ bool IsStatic() const {
+ return ((access_flags_ & kAccStatic) != 0);
+ }
+
public:
const ClassLoader* class_loader_;
ClassLinker* class_linker_;
diff --git a/src/object.cc b/src/object.cc
index 0bcf5c7..cd6b51f 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -384,35 +384,6 @@
new_value, false);
}
-#if defined(ART_USE_LLVM_COMPILER)
-
-const InferredRegCategoryMap* Method::GetInferredRegCategoryMap() const {
- const InferredRegCategoryMap* map = GetFieldPtr<const InferredRegCategoryMap*>(
- OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
- DCHECK(map != NULL) << PrettyMethod(this);
- return map;
-}
-
-void Method::SetInferredRegCategoryMap(const InferredRegCategoryMap* map) {
- const InferredRegCategoryMap* existing_map = GetFieldPtr<const InferredRegCategoryMap*>(
- OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
-
- DCHECK(existing_map == NULL) << PrettyMethod(this);
- DCHECK(map != NULL) << PrettyMethod(this);
-
- // TODO: Remove if we won't find any use of InferredRegCategoryMap at runtime.
- SetFieldPtr<const InferredRegCategoryMap*>(
- OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), map, false);
-}
-
-void Method::ResetInferredRegCategoryMap() {
- delete GetInferredRegCategoryMap();
- SetFieldPtr<const InferredRegCategoryMap*>(
- OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), NULL, false);
-}
-
-#endif
-
size_t Method::NumArgRegisters(const StringPiece& shorty) {
CHECK_LE(1, shorty.length());
uint32_t num_registers = 0;
diff --git a/src/object.h b/src/object.h
index 4d054b9..3ece535 100644
--- a/src/object.h
+++ b/src/object.h
@@ -760,16 +760,6 @@
SetGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
}
-#if defined(ART_USE_LLVM_COMPILER)
- // NOTE: In order not to change the Oat file format, we are reusing the
- // gc_map_ field, so be careful while altering the GC map related code.
-
- const compiler_llvm::InferredRegCategoryMap* GetInferredRegCategoryMap() const;
-
- void SetInferredRegCategoryMap(const compiler_llvm::InferredRegCategoryMap* map);
- void ResetInferredRegCategoryMap();
-#endif
-
size_t GetFrameSizeInBytes() const {
DCHECK_EQ(sizeof(size_t), sizeof(uint32_t));
size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false);
diff --git a/src/runtime.cc b/src/runtime.cc
index 014ce6b..d16ee78 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -99,6 +99,9 @@
delete class_linker_;
delete heap_;
+#if defined(ART_USE_LLVM_COMPILER)
+ verifier::DexVerifier::DeleteInferredRegCategoryMaps();
+#endif
verifier::DexVerifier::DeleteGcMaps();
delete intern_table_;
delete java_vm_;
@@ -643,6 +646,10 @@
verifier::DexVerifier::InitGcMaps();
+#if defined(ART_USE_LLVM_COMPILER)
+ verifier::DexVerifier::InitInferredRegCategoryMaps();
+#endif
+
heap_ = new Heap(options->heap_initial_size_,
options->heap_growth_limit_,
options->heap_maximum_size_,