Merge "Fix VM-less builds."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 9275c97..6346970 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -144,11 +144,8 @@
ART_TARGET_CLANG_CFLAGS_arm64 += \
-fno-vectorize
-# Colorize clang compiler warnings.
-art_clang_cflags := -fcolor-diagnostics
-
# Warn about thread safety violations with clang.
-art_clang_cflags += -Wthread-safety
+art_clang_cflags := -Wthread-safety
# Warn if switch fallthroughs aren't annotated.
art_clang_cflags += -Wimplicit-fallthrough
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index e8b363b..523d143 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -44,6 +44,9 @@
core_pic_infix :=
core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+ ifeq ($(1),default)
+ core_compile_options += --compiler-backend=Quick
+ endif
ifeq ($(1),optimizing)
core_compile_options += --compiler-backend=Optimizing
# With the optimizing compiler, we want to rerun dex2oat whenever there is
@@ -137,6 +140,9 @@
core_pic_infix :=
core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+ ifeq ($(1),default)
+ core_compile_options += --compiler-backend=Quick
+ endif
ifeq ($(1),optimizing)
ifeq ($($(3)TARGET_ARCH),arm64)
# TODO: Enable image generation on arm64 once the backend
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index 4c7f874..b9d9a11 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -488,6 +488,7 @@
kThumb2BicRRI8M, // bic rd, rn, #<const> [11110] i [000010] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
kThumb2AndRRI8M, // and rd, rn, #<const> [11110] i [000000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
kThumb2OrrRRI8M, // orr rd, rn, #<const> [11110] i [000100] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
+ kThumb2OrnRRI8M, // orn rd, rn, #<const> [11110] i [000110] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
kThumb2EorRRI8M, // eor rd, rn, #<const> [11110] i [001000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
kThumb2AddRRI8M, // add rd, rn, #<const> [11110] i [010001] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
kThumb2AdcRRI8M, // adc rd, rn, #<const> [11110] i [010101] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index 76ec9df..de93e26 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -788,6 +788,10 @@
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
"orr", "!0C, !1C, #!2m", 4, kFixupNone),
+ ENCODING_MAP(kThumb2OrnRRI8M, 0xf0600000,
+ kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "orn", "!0C, !1C, #!2m", 4, kFixupNone),
ENCODING_MAP(kThumb2EorRRI8M, 0xf0800000,
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index e8d0c32..0bc4c3b 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -250,10 +250,11 @@
int EncodeShift(int code, int amount);
int ModifiedImmediate(uint32_t value);
ArmConditionCode ArmConditionEncoding(ConditionCode code);
- bool InexpensiveConstantInt(int32_t value);
- bool InexpensiveConstantFloat(int32_t value);
- bool InexpensiveConstantLong(int64_t value);
- bool InexpensiveConstantDouble(int64_t value);
+ bool InexpensiveConstantInt(int32_t value) OVERRIDE;
+ bool InexpensiveConstantInt(int32_t value, Instruction::Code opcode) OVERRIDE;
+ bool InexpensiveConstantFloat(int32_t value) OVERRIDE;
+ bool InexpensiveConstantLong(int64_t value) OVERRIDE;
+ bool InexpensiveConstantDouble(int64_t value) OVERRIDE;
RegStorage AllocPreservedDouble(int s_reg);
RegStorage AllocPreservedSingle(int s_reg);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 4aedbaf..1a7b439 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -592,7 +592,6 @@
// Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms.
bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) {
- GetEasyMultiplyOp(lit, &ops[0]);
if (GetEasyMultiplyOp(lit, &ops[0])) {
ops[1].op = kOpInvalid;
ops[1].shift = 0;
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 7168b9f..117d8f0 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -97,31 +97,11 @@
return load_pc_rel;
}
-static int LeadingZeros(uint32_t val) {
- uint32_t alt;
- int32_t n;
- int32_t count;
-
- count = 16;
- n = 32;
- do {
- alt = val >> count;
- if (alt != 0) {
- n = n - count;
- val = alt;
- }
- count >>= 1;
- } while (count);
- return n - val;
-}
-
/*
* Determine whether value can be encoded as a Thumb2 modified
* immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
*/
int ArmMir2Lir::ModifiedImmediate(uint32_t value) {
- int32_t z_leading;
- int32_t z_trailing;
uint32_t b0 = value & 0xff;
/* Note: case of value==0 must use 0:000:0:0000000 encoding */
@@ -135,8 +115,8 @@
if (value == ((b0 << 24) | (b0 << 8)))
return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
/* Can we do it with rotation? */
- z_leading = LeadingZeros(value);
- z_trailing = 32 - LeadingZeros(~value & (value - 1));
+ int z_leading = CLZ(value);
+ int z_trailing = CTZ(value);
/* A run of eight or fewer active bits? */
if ((z_leading + z_trailing) < 24)
return -1; /* No - bail */
@@ -152,6 +132,64 @@
return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
}
+bool ArmMir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcode) {
+ switch (opcode) {
+ case Instruction::ADD_INT:
+ case Instruction::ADD_INT_2ADDR:
+ case Instruction::SUB_INT:
+ case Instruction::SUB_INT_2ADDR:
+ if ((value >> 12) == (value >> 31)) { // Signed 12-bit, RRI12 versions of ADD/SUB.
+ return true;
+ }
+ FALLTHROUGH_INTENDED;
+ case Instruction::IF_EQ:
+ case Instruction::IF_NE:
+ case Instruction::IF_LT:
+ case Instruction::IF_GE:
+ case Instruction::IF_GT:
+ case Instruction::IF_LE:
+ return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(-value) >= 0);
+ case Instruction::SHL_INT:
+ case Instruction::SHL_INT_2ADDR:
+ case Instruction::SHR_INT:
+ case Instruction::SHR_INT_2ADDR:
+ case Instruction::USHR_INT:
+ case Instruction::USHR_INT_2ADDR:
+ return true;
+ case Instruction::AND_INT:
+ case Instruction::AND_INT_2ADDR:
+ case Instruction::AND_INT_LIT16:
+ case Instruction::AND_INT_LIT8:
+ case Instruction::OR_INT:
+ case Instruction::OR_INT_2ADDR:
+ case Instruction::OR_INT_LIT16:
+ case Instruction::OR_INT_LIT8:
+ return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
+ case Instruction::XOR_INT:
+ case Instruction::XOR_INT_2ADDR:
+ case Instruction::XOR_INT_LIT16:
+ case Instruction::XOR_INT_LIT8:
+ return (ModifiedImmediate(value) >= 0);
+ case Instruction::MUL_INT:
+ case Instruction::MUL_INT_2ADDR:
+ case Instruction::MUL_INT_LIT8:
+ case Instruction::MUL_INT_LIT16:
+ case Instruction::DIV_INT:
+ case Instruction::DIV_INT_2ADDR:
+ case Instruction::DIV_INT_LIT8:
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::REM_INT:
+ case Instruction::REM_INT_2ADDR:
+ case Instruction::REM_INT_LIT8:
+ case Instruction::REM_INT_LIT16: {
+ EasyMultiplyOp ops[2];
+ return GetEasyMultiplyTwoOps(value, ops);
+ }
+ default:
+ return false;
+ }
+}
+
bool ArmMir2Lir::InexpensiveConstantFloat(int32_t value) {
return EncodeImmSingle(value) >= 0;
}
@@ -510,7 +548,7 @@
op = (op == kOpAdd) ? kOpSub : kOpAdd;
}
}
- if (mod_imm < 0 && (abs_value & 0x3ff) == abs_value) {
+ if (mod_imm < 0 && (abs_value >> 12) == 0) {
// This is deliberately used only if modified immediate encoding is inadequate since
// we sometimes actually use the flags for small values but not necessarily low regs.
if (op == kOpAdd)
@@ -542,6 +580,12 @@
case kOpOr:
opcode = kThumb2OrrRRI8M;
alt_opcode = kThumb2OrrRRR;
+ if (mod_imm < 0) {
+ mod_imm = ModifiedImmediate(~value);
+ if (mod_imm >= 0) {
+ opcode = kThumb2OrnRRI8M;
+ }
+ }
break;
case kOpAnd:
if (mod_imm < 0) {
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index ebf7874..3a91b08 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -21,7 +21,6 @@
#include "dex/compiler_ir.h"
#include "dex_compilation_unit.h"
-#include "field_helper.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class_loader.h"
@@ -134,10 +133,9 @@
} else {
// Search dex file for localized ssb index, may fail if field's class is a parent
// of the class mentioned in the dex file and there is no dex cache entry.
- StackHandleScope<1> hs(Thread::Current());
+ std::string temp;
const DexFile::StringId* string_id =
- dex_file->FindStringId(
- FieldHelper(hs.NewHandle(resolved_field)).GetDeclaringClassDescriptor());
+ dex_file->FindStringId(resolved_field->GetDeclaringClass()->GetDescriptor(&temp));
if (string_id != nullptr) {
const DexFile::TypeId* type_id =
dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 2e9f835..ab9f41a 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -19,6 +19,7 @@
#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <utils/Trace.h>
+#include <unordered_set>
#include <vector>
#include <unistd.h>
@@ -53,6 +54,7 @@
#include "ScopedLocalRef.h"
#include "handle_scope-inl.h"
#include "thread.h"
+#include "thread_list.h"
#include "thread_pool.h"
#include "trampolines/trampoline_compiler.h"
#include "transaction.h"
@@ -626,10 +628,10 @@
}
}
-static void ResolveExceptionsForMethod(MutableMethodHelper* mh,
+static void ResolveExceptionsForMethod(MutableHandle<mirror::ArtMethod> method_handle,
std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem();
+ const DexFile::CodeItem* code_item = method_handle->GetCodeItem();
if (code_item == nullptr) {
return; // native or abstract method
}
@@ -649,10 +651,10 @@
uint16_t encoded_catch_handler_handlers_type_idx =
DecodeUnsignedLeb128(&encoded_catch_handler_list);
// Add to set of types to resolve if not already in the dex cache resolved types
- if (!mh->GetMethod()->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+ if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
exceptions_to_resolve.insert(
std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
- mh->GetMethod()->GetDexFile()));
+ method_handle->GetDexFile()));
}
// ignore address associated with catch handler
DecodeUnsignedLeb128(&encoded_catch_handler_list);
@@ -669,14 +671,14 @@
std::set<std::pair<uint16_t, const DexFile*>>* exceptions_to_resolve =
reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*>>*>(arg);
StackHandleScope<1> hs(Thread::Current());
- MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+ MutableHandle<mirror::ArtMethod> method_handle(hs.NewHandle<mirror::ArtMethod>(nullptr));
for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
- mh.ChangeMethod(c->GetVirtualMethod(i));
- ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+ method_handle.Assign(c->GetVirtualMethod(i));
+ ResolveExceptionsForMethod(method_handle, *exceptions_to_resolve);
}
for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
- mh.ChangeMethod(c->GetDirectMethod(i));
- ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+ method_handle.Assign(c->GetDirectMethod(i));
+ ResolveExceptionsForMethod(method_handle, *exceptions_to_resolve);
}
return true;
}
@@ -782,23 +784,143 @@
}
}
-void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
- DCHECK(object != nullptr);
- DCHECK(arg != nullptr);
- CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
- StackHandleScope<1> hs(Thread::Current());
- MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get());
-}
+// Keeps all the data for the update together. Also doubles as the reference visitor.
+// Note: we can use object pointers because we suspend all threads.
+class ClinitImageUpdate {
+ public:
+ static ClinitImageUpdate* Create(std::set<std::string>* image_class_descriptors, Thread* self,
+ ClassLinker* linker, std::string* error_msg) {
+ std::unique_ptr<ClinitImageUpdate> res(new ClinitImageUpdate(image_class_descriptors, self,
+ linker));
+ if (res->art_method_class_ == nullptr) {
+ *error_msg = "Could not find ArtMethod class.";
+ return nullptr;
+ } else if (res->dex_cache_class_ == nullptr) {
+ *error_msg = "Could not find DexCache class.";
+ return nullptr;
+ }
+
+ return res.release();
+ }
+
+ ~ClinitImageUpdate() {
+ // Allow others to suspend again.
+ self_->EndAssertNoThreadSuspension(old_cause_);
+ }
+
+ // Visitor for VisitReferences.
+ void operator()(mirror::Object* object, MemberOffset field_offset, bool /* is_static */) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Object* ref = object->GetFieldObject<mirror::Object>(field_offset);
+ if (ref != nullptr) {
+ VisitClinitClassesObject(ref);
+ }
+ }
+
+ // java.lang.Reference visitor for VisitReferences.
+ void operator()(mirror::Class* /* klass */, mirror::Reference* /* ref */) const {
+ }
+
+ void Walk() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Use the initial classes as roots for a search.
+ for (mirror::Class* klass_root : image_classes_) {
+ VisitClinitClassesObject(klass_root);
+ }
+ }
+
+ private:
+ ClinitImageUpdate(std::set<std::string>* image_class_descriptors, Thread* self,
+ ClassLinker* linker)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+ image_class_descriptors_(image_class_descriptors), self_(self) {
+ CHECK(linker != nullptr);
+ CHECK(image_class_descriptors != nullptr);
+
+ // Make sure nobody interferes with us.
+ old_cause_ = self->StartAssertNoThreadSuspension("Boot image closure");
+
+ // Find the interesting classes.
+ art_method_class_ = linker->LookupClass(self, "Ljava/lang/reflect/ArtMethod;",
+ ComputeModifiedUtf8Hash("Ljava/lang/reflect/ArtMethod;"), nullptr);
+ dex_cache_class_ = linker->LookupClass(self, "Ljava/lang/DexCache;",
+ ComputeModifiedUtf8Hash("Ljava/lang/DexCache;"), nullptr);
+
+ // Find all the already-marked classes.
+ WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+ linker->VisitClasses(FindImageClasses, this);
+ }
+
+ static bool FindImageClasses(mirror::Class* klass, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClinitImageUpdate* data = reinterpret_cast<ClinitImageUpdate*>(arg);
+ std::string temp;
+ const char* name = klass->GetDescriptor(&temp);
+ if (data->image_class_descriptors_->find(name) != data->image_class_descriptors_->end()) {
+ data->image_classes_.push_back(klass);
+ }
+
+ return true;
+ }
+
+ void VisitClinitClassesObject(mirror::Object* object) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(object != nullptr);
+ if (marked_objects_.find(object) != marked_objects_.end()) {
+ // Already processed.
+ return;
+ }
+
+ // Mark it.
+ marked_objects_.insert(object);
+
+ if (object->IsClass()) {
+ // If it is a class, add it.
+ StackHandleScope<1> hs(self_);
+ MaybeAddToImageClasses(hs.NewHandle(object->AsClass()), image_class_descriptors_);
+ } else {
+ // Else visit the object's class.
+ VisitClinitClassesObject(object->GetClass());
+ }
+
+ // If it is not a dex cache or an ArtMethod, visit all references.
+ mirror::Class* klass = object->GetClass();
+ if (klass != art_method_class_ && klass != dex_cache_class_) {
+ object->VisitReferences<false /* visit class */>(*this, *this);
+ }
+ }
+
+ mutable std::unordered_set<mirror::Object*> marked_objects_;
+ std::set<std::string>* const image_class_descriptors_;
+ std::vector<mirror::Class*> image_classes_;
+ const mirror::Class* art_method_class_;
+ const mirror::Class* dex_cache_class_;
+ Thread* const self_;
+ const char* old_cause_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClinitImageUpdate);
+};
void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
if (IsImage()) {
TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
- // Update image_classes_ with classes for objects created by <clinit> methods.
- gc::Heap* heap = Runtime::Current()->GetHeap();
- // TODO: Image spaces only?
- ScopedObjectAccess soa(Thread::Current());
- WriterMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
- heap->VisitObjects(FindClinitImageClassesCallback, this);
+
+ Runtime* current = Runtime::Current();
+
+ // Suspend all threads.
+ current->GetThreadList()->SuspendAll();
+
+ std::string error_msg;
+ std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(image_classes_.get(),
+ Thread::Current(),
+ current->GetClassLinker(),
+ &error_msg));
+ CHECK(update.get() != nullptr) << error_msg; // TODO: Soft failure?
+
+ // Do the marking.
+ update->Walk();
+
+ // Resume threads.
+ current->GetThreadList()->ResumeAll();
}
}
@@ -1194,11 +1316,10 @@
target_method->dex_method_index = method->GetDexMethodIndex();
} else {
if (no_guarantee_of_dex_cache_entry) {
- StackHandleScope<1> hs(Thread::Current());
- MethodHelper mh(hs.NewHandle(method));
// See if the method is also declared in this dex cache.
- uint32_t dex_method_idx = mh.FindDexMethodIndexInOtherDexFile(
- *target_method->dex_file, target_method->dex_method_index);
+ uint32_t dex_method_idx =
+ method->FindDexMethodIndexInOtherDexFile(*target_method->dex_file,
+ target_method->dex_method_index);
if (dex_method_idx != DexFile::kDexNoIndex) {
target_method->dex_method_index = dex_method_idx;
} else {
@@ -1820,6 +1941,12 @@
mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
<< exception->Dump();
+ std::ostream* file_log = manager->GetCompiler()->
+ GetCompilerOptions().GetInitFailureOutput();
+ if (file_log != nullptr) {
+ *file_log << descriptor << "\n";
+ *file_log << exception->Dump() << "\n";
+ }
soa.Self()->ClearException();
transaction.Abort();
CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 437a1a9..d837dbc 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -340,6 +340,9 @@
ArenaPool* GetArenaPool() {
return &arena_pool_;
}
+ const ArenaPool* GetArenaPool() const {
+ return &arena_pool_;
+ }
bool WriteElf(const std::string& android_root,
bool is_host,
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 0592f0c..aec7d24 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
+#include <ostream>
#include <string>
#include <vector>
@@ -70,7 +71,8 @@
#ifdef ART_SEA_IR_MODE
sea_ir_mode_(false),
#endif
- verbose_methods_(nullptr) {
+ verbose_methods_(nullptr),
+ init_failure_output_(nullptr) {
}
CompilerOptions(CompilerFilter compiler_filter,
@@ -90,7 +92,8 @@
#ifdef ART_SEA_IR_MODE
bool sea_ir_mode,
#endif
- const std::vector<std::string>* verbose_methods
+ const std::vector<std::string>* verbose_methods,
+ std::ostream* init_failure_output
) : // NOLINT(whitespace/parens)
compiler_filter_(compiler_filter),
huge_method_threshold_(huge_method_threshold),
@@ -109,7 +112,8 @@
#ifdef ART_SEA_IR_MODE
sea_ir_mode_(sea_ir_mode),
#endif
- verbose_methods_(verbose_methods) {
+ verbose_methods_(verbose_methods),
+ init_failure_output_(init_failure_output) {
}
CompilerFilter GetCompilerFilter() const {
@@ -217,6 +221,10 @@
return false;
}
+ std::ostream* GetInitFailureOutput() const {
+ return init_failure_output_;
+ }
+
private:
CompilerFilter compiler_filter_;
const size_t huge_method_threshold_;
@@ -241,6 +249,9 @@
// Vector of methods to have verbose output enabled for.
const std::vector<std::string>* const verbose_methods_;
+ // Log initialization of initialization failures to this stream if not null.
+ std::ostream* const init_failure_output_;
+
DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
};
std::ostream& operator<<(std::ostream& os, const CompilerOptions::CompilerFilter& rhs);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 777a117..eb6181c 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -155,6 +155,37 @@
current_block_ = nullptr;
}
+static bool ShouldSkipCompilation(const CompilerDriver& compiler_driver,
+ const DexCompilationUnit& dex_compilation_unit,
+ size_t number_of_dex_instructions,
+ size_t number_of_blocks ATTRIBUTE_UNUSED,
+ size_t number_of_branches) {
+ const CompilerOptions& compiler_options = compiler_driver.GetCompilerOptions();
+ CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
+ if (compiler_filter == CompilerOptions::kEverything) {
+ return false;
+ }
+
+ if (compiler_options.IsHugeMethod(number_of_dex_instructions)) {
+ LOG(INFO) << "Skip compilation of huge method "
+ << PrettyMethod(dex_compilation_unit.GetDexMethodIndex(),
+ *dex_compilation_unit.GetDexFile())
+ << ": " << number_of_dex_instructions << " dex instructions";
+ return true;
+ }
+
+ // If it's large and contains no branches, it's likely to be machine generated initialization.
+ if (compiler_options.IsLargeMethod(number_of_dex_instructions) && (number_of_branches == 0)) {
+ LOG(INFO) << "Skip compilation of large method with no branch "
+ << PrettyMethod(dex_compilation_unit.GetDexMethodIndex(),
+ *dex_compilation_unit.GetDexFile())
+ << ": " << number_of_dex_instructions << " dex instructions";
+ return true;
+ }
+
+ return false;
+}
+
HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
const uint16_t* code_ptr = code_item.insns_;
const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
@@ -171,9 +202,27 @@
InitializeLocals(code_item.registers_size_);
graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
+ // Compute the number of dex instructions, blocks, and branches. We will
+ // check these values against limits given to the compiler.
+ size_t number_of_dex_instructions = 0;
+ size_t number_of_blocks = 0;
+ size_t number_of_branches = 0;
+
// To avoid splitting blocks, we compute ahead of time the instructions that
// start a new block, and create these blocks.
- ComputeBranchTargets(code_ptr, code_end);
+ ComputeBranchTargets(
+ code_ptr, code_end, &number_of_dex_instructions, &number_of_blocks, &number_of_branches);
+
+ // Note that the compiler driver is null when unit testing.
+ if (compiler_driver_ != nullptr) {
+ if (ShouldSkipCompilation(*compiler_driver_,
+ *dex_compilation_unit_,
+ number_of_dex_instructions,
+ number_of_blocks,
+ number_of_branches)) {
+ return nullptr;
+ }
+ }
// Also create blocks for catch handlers.
if (code_item.tries_size_ != 0) {
@@ -232,7 +281,11 @@
current_block_ = block;
}
-void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
+void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr,
+ const uint16_t* code_end,
+ size_t* number_of_dex_instructions,
+ size_t* number_of_blocks,
+ size_t* number_of_branches) {
// TODO: Support switch instructions.
branch_targets_.SetSize(code_end - code_ptr);
@@ -245,19 +298,23 @@
// the locations these instructions branch to.
size_t dex_pc = 0;
while (code_ptr < code_end) {
+ (*number_of_dex_instructions)++;
const Instruction& instruction = *Instruction::At(code_ptr);
if (instruction.IsBranch()) {
+ (*number_of_branches)++;
int32_t target = instruction.GetTargetOffset() + dex_pc;
// Create a block for the target instruction.
if (FindBlockStartingAt(target) == nullptr) {
block = new (arena_) HBasicBlock(graph_, target);
branch_targets_.Put(target, block);
+ (*number_of_blocks)++;
}
dex_pc += instruction.SizeInCodeUnits();
code_ptr += instruction.SizeInCodeUnits();
if ((code_ptr < code_end) && (FindBlockStartingAt(dex_pc) == nullptr)) {
block = new (arena_) HBasicBlock(graph_, dex_pc);
branch_targets_.Put(dex_pc, block);
+ (*number_of_blocks)++;
}
} else {
code_ptr += instruction.SizeInCodeUnits();
@@ -423,38 +480,36 @@
bool is_instance_call = invoke_type != kStatic;
const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
- HInvoke* invoke = nullptr;
- if (invoke_type == kVirtual || invoke_type == kInterface || invoke_type == kSuper) {
- MethodReference target_method(dex_file_, method_idx);
- uintptr_t direct_code;
- uintptr_t direct_method;
- int table_index;
- InvokeType optimized_invoke_type = invoke_type;
- compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true,
- &optimized_invoke_type, &target_method, &table_index,
- &direct_code, &direct_method);
- if (table_index == -1) {
- return false;
- }
+ MethodReference target_method(dex_file_, method_idx);
+ uintptr_t direct_code;
+ uintptr_t direct_method;
+ int table_index;
+ InvokeType optimized_invoke_type = invoke_type;
- if (optimized_invoke_type == kVirtual) {
- invoke = new (arena_) HInvokeVirtual(
- arena_, number_of_arguments, return_type, dex_pc, table_index);
- } else if (optimized_invoke_type == kInterface) {
- invoke = new (arena_) HInvokeInterface(
- arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
- } else if (optimized_invoke_type == kDirect) {
- // For this compiler, sharpening only works if we compile PIC.
- DCHECK(compiler_driver_->GetCompilerOptions().GetCompilePic());
- // Treat invoke-direct like static calls for now.
- invoke = new (arena_) HInvokeStatic(
- arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index);
- }
+ if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true,
+ &optimized_invoke_type, &target_method, &table_index,
+ &direct_code, &direct_method)) {
+ LOG(INFO) << "Did not compile " << PrettyMethod(method_idx, *dex_file_)
+ << " because a method call could not be resolved";
+ return false;
+ }
+ DCHECK(optimized_invoke_type != kSuper);
+
+ HInvoke* invoke = nullptr;
+ if (optimized_invoke_type == kVirtual) {
+ invoke = new (arena_) HInvokeVirtual(
+ arena_, number_of_arguments, return_type, dex_pc, table_index);
+ } else if (optimized_invoke_type == kInterface) {
+ invoke = new (arena_) HInvokeInterface(
+ arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
} else {
- DCHECK(invoke_type == kDirect || invoke_type == kStatic);
+ DCHECK(optimized_invoke_type == kDirect || optimized_invoke_type == kStatic);
+ // Sharpening to kDirect only works if we compile PIC.
+ DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect)
+ || compiler_driver_->GetCompilerOptions().GetCompilePic());
// Treat invoke-direct like static calls for now.
invoke = new (arena_) HInvokeStatic(
- arena_, number_of_arguments, return_type, dex_pc, method_idx);
+ arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index);
}
size_t start_index = 0;
@@ -1053,6 +1108,11 @@
break;
}
+ case Instruction::FLOAT_TO_INT: {
+ Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt);
+ break;
+ }
+
case Instruction::INT_TO_BYTE: {
Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte);
break;
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 25781b0..8519bcb 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -80,7 +80,13 @@
// Finds all instructions that start a new block, and populates branch_targets_ with
// the newly created blocks.
- void ComputeBranchTargets(const uint16_t* start, const uint16_t* end);
+ // As a side effect, also compute the number of dex instructions, blocks, and
+ // branches.
+ void ComputeBranchTargets(const uint16_t* start,
+ const uint16_t* end,
+ size_t* number_of_dex_instructions,
+ size_t* number_of_block,
+ size_t* number_of_branches);
void MaybeUpdateCurrentBlock(size_t index);
HBasicBlock* FindBlockStartingAt(int32_t index) const;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4c0d3ea..7c8f6a2 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -35,6 +35,9 @@
// Binary encoding of 2^31 for type double.
static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
+// Maximum value for a primitive integer.
+static int32_t constexpr kPrimIntMax = 0x7fffffff;
+
class Assembler;
class CodeGenerator;
class DexCompilationUnit;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5b2be2e..448a5a0 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1406,6 +1406,12 @@
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1580,7 +1586,15 @@
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
+ __ vmovs(temp, in.AsFpuRegister<SRegister>());
+ __ vcvtis(temp, temp);
+ __ vmovrs(out.AsRegister<Register>(), temp);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index fd794f9..6f83d9f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1373,6 +1373,12 @@
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1559,7 +1565,31 @@
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ Register output = out.AsRegister<Register>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-float(output)
+ __ cvtsi2ss(temp, output);
+ // if input >= temp goto done
+ __ comiss(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = float-to-int-truncate(input)
+ __ cvttss2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 4d70efc..47fd304 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1363,6 +1363,12 @@
break;
case Primitive::kPrimFloat:
+ // Processing a Dex `float-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
@@ -1550,7 +1556,31 @@
}
break;
- case Primitive::kPrimFloat:
+ case Primitive::kPrimFloat: {
+ // Processing a Dex `float-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ CpuRegister output = out.AsRegister<CpuRegister>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-float(output)
+ __ cvtsi2ss(temp, output);
+ // if input >= temp goto done
+ __ comiss(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = float-to-int-truncate(input)
+ __ cvttss2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
+ break;
+ }
+
case Primitive::kPrimDouble:
LOG(FATAL) << "Type conversion from " << input_type
<< " to " << result_type << " not yet implemented";
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index c36b143..82fe03c 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -32,7 +32,7 @@
const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
HGraph* graph = builder.BuildGraph(*item);
graph->BuildDominatorTree();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
return graph;
}
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index ad6e338..a6a68ca 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -175,7 +175,7 @@
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
GlobalValueNumberer(&allocator, graph).Run();
// Check that all field get instructions are still there.
@@ -239,7 +239,7 @@
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
*outer_loop_header->GetLoopInformation()));
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index c49cf7e..28ca5e8 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -44,7 +44,7 @@
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
x86::CodeGeneratorX86 codegen(graph);
SsaLivenessAnalysis liveness(*graph, &codegen);
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index e3c6fec..5c7e6f0 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -38,7 +38,7 @@
RemoveSuspendChecks(graph);
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
// `Inline` conditions into ifs.
PrepareForRegisterAllocation(graph).Run();
return graph;
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 246e7ef..4b69e57 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -50,7 +50,7 @@
ASSERT_NE(graph, nullptr);
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
// `Inline` conditions into ifs.
PrepareForRegisterAllocation(graph).Run();
x86::CodeGeneratorX86 codegen(graph);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 8cb2ef6..ba4dccf 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -30,6 +30,36 @@
VisitBlockForBackEdges(entry_block_, visited, &visiting);
}
+static void RemoveAsUser(HInstruction* instruction) {
+ for (size_t i = 0; i < instruction->InputCount(); i++) {
+ instruction->InputAt(i)->RemoveUser(instruction, i);
+ }
+
+ HEnvironment* environment = instruction->GetEnvironment();
+ if (environment != nullptr) {
+ for (size_t i = 0, e = environment->Size(); i < e; ++i) {
+ HInstruction* vreg = environment->GetInstructionAt(i);
+ if (vreg != nullptr) {
+ vreg->RemoveEnvironmentUser(environment, i);
+ }
+ }
+ }
+}
+
+void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
+ for (size_t i = 0; i < blocks_.Size(); ++i) {
+ if (!visited.IsBitSet(i)) {
+ HBasicBlock* block = blocks_.Get(i);
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ RemoveAsUser(it.Current());
+ }
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ RemoveAsUser(it.Current());
+ }
+ }
+ }
+}
+
void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
for (size_t i = 0; i < blocks_.Size(); ++i) {
if (!visited.IsBitSet(i)) {
@@ -72,16 +102,21 @@
// (1) Find the back edges in the graph doing a DFS traversal.
FindBackEdges(&visited);
- // (2) Remove blocks not visited during the initial DFS.
- // Step (3) requires dead blocks to be removed from the
+ // (2) Remove instructions and phis from blocks not visited during
+ // the initial DFS as users from other instructions, so that
+ // users can be safely removed before uses later.
+ RemoveInstructionsAsUsersFromDeadBlocks(visited);
+
+ // (3) Remove blocks not visited during the initial DFS.
+ // Step (4) requires dead blocks to be removed from the
// predecessors list of live blocks.
RemoveDeadBlocks(visited);
- // (3) Simplify the CFG now, so that we don't need to recompute
+ // (4) Simplify the CFG now, so that we don't need to recompute
// dominators and the reverse post order.
SimplifyCFG();
- // (4) Compute the immediate dominator of each block. We visit
+ // (5) Compute the immediate dominator of each block. We visit
// the successors of a block only when all its forward branches
// have been processed.
GrowableArray<size_t> visits(arena_, blocks_.Size());
@@ -237,7 +272,7 @@
}
}
-bool HGraph::FindNaturalLoops() const {
+bool HGraph::AnalyzeNaturalLoops() const {
for (size_t i = 0; i < blocks_.Size(); ++i) {
HBasicBlock* block = blocks_.Get(i);
if (block->IsLoopHeader()) {
@@ -391,19 +426,7 @@
instruction->SetBlock(nullptr);
instruction_list->RemoveInstruction(instruction);
- for (size_t i = 0; i < instruction->InputCount(); i++) {
- instruction->InputAt(i)->RemoveUser(instruction, i);
- }
-
- HEnvironment* environment = instruction->GetEnvironment();
- if (environment != nullptr) {
- for (size_t i = 0, e = environment->Size(); i < e; ++i) {
- HInstruction* vreg = environment->GetInstructionAt(i);
- if (vreg != nullptr) {
- vreg->RemoveEnvironmentUser(environment, i);
- }
- }
- }
+ RemoveAsUser(instruction);
}
void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 28496e4..3908a61 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -112,10 +112,10 @@
void TransformToSSA();
void SimplifyCFG();
- // Find all natural loops in this graph. Aborts computation and returns false
- // if one loop is not natural, that is the header does not dominate the back
- // edge.
- bool FindNaturalLoops() const;
+ // Analyze all natural loops in this graph. Returns false if one
+ // loop is not natural, that is the header does not dominate the
+ // back edge.
+ bool AnalyzeNaturalLoops() const;
void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
void SimplifyLoop(HBasicBlock* header);
@@ -173,6 +173,7 @@
void VisitBlockForBackEdges(HBasicBlock* block,
ArenaBitVector* visited,
ArenaBitVector* visiting);
+ void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
void RemoveDeadBlocks(const ArenaBitVector& visited) const;
ArenaAllocator* const arena_;
@@ -1669,7 +1670,12 @@
uint16_t GetTypeIndex() const { return type_index_; }
// Calls runtime so needs an environment.
- virtual bool NeedsEnvironment() const { return true; }
+ bool NeedsEnvironment() const OVERRIDE { return true; }
+ // It may throw when called on:
+ // - interfaces
+ // - abstract/innaccessible/unknown classes
+ // TODO: optimize when possible.
+ bool CanThrow() const OVERRIDE { return true; }
DECLARE_INSTRUCTION(NewInstance);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index d8533eb..100a6bc 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -192,7 +192,6 @@
}
static void RunOptimizations(HGraph* graph, const HGraphVisualizer& visualizer) {
- TransformToSsa ssa(graph);
HDeadCodeElimination opt1(graph);
HConstantFolding opt2(graph);
SsaRedundantPhiElimination opt3(graph);
@@ -202,7 +201,6 @@
InstructionSimplifier opt7(graph);
HOptimization* optimizations[] = {
- &ssa,
&opt1,
&opt2,
&opt3,
@@ -220,6 +218,23 @@
}
}
+static bool TryBuildingSsa(HGraph* graph,
+ const DexCompilationUnit& dex_compilation_unit,
+ const HGraphVisualizer& visualizer) {
+ graph->BuildDominatorTree();
+ graph->TransformToSSA();
+
+ if (!graph->AnalyzeNaturalLoops()) {
+ LOG(INFO) << "Skipping compilation of "
+ << PrettyMethod(dex_compilation_unit.GetDexMethodIndex(),
+ *dex_compilation_unit.GetDexFile())
+ << ": it contains a non natural loop";
+ return false;
+ }
+ visualizer.DumpGraph("ssa transform");
+ return true;
+}
+
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -281,7 +296,12 @@
if (run_optimizations_
&& CanOptimize(*code_item)
&& RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
+ VLOG(compiler) << "Optimizing " << PrettyMethod(method_idx, dex_file);
optimized_compiled_methods_++;
+ if (!TryBuildingSsa(graph, dex_compilation_unit, visualizer)) {
+ // We could not transform the graph to SSA, bailout.
+ return nullptr;
+ }
RunOptimizations(graph, visualizer);
PrepareForRegisterAllocation(graph).Run();
@@ -316,23 +336,10 @@
LOG(FATAL) << "Could not allocate registers in optimizing compiler";
UNREACHABLE();
} else {
+ VLOG(compiler) << "Compile baseline " << PrettyMethod(method_idx, dex_file);
unoptimized_compiled_methods_++;
codegen->CompileBaseline(&allocator);
- if (CanOptimize(*code_item)) {
- // Run these phases to get some test coverage.
- graph->BuildDominatorTree();
- graph->TransformToSSA();
- visualizer.DumpGraph("ssa");
- graph->FindNaturalLoops();
- SsaRedundantPhiElimination(graph).Run();
- SsaDeadPhiElimination(graph).Run();
- GVNOptimization(graph).Run();
- SsaLivenessAnalysis liveness(*graph, codegen);
- liveness.Analyze();
- visualizer.DumpGraph(kLivenessPassName);
- }
-
std::vector<uint8_t> mapping_table;
SrcMap src_mapping_table;
codegen->BuildMappingTable(&mapping_table,
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index ba4be34..8d75db9 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -41,7 +41,7 @@
HGraph* graph = builder.BuildGraph(*item);
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
x86::CodeGeneratorX86 codegen(graph);
SsaLivenessAnalysis liveness(*graph, &codegen);
liveness.Analyze();
@@ -255,7 +255,7 @@
HGraph* graph = builder.BuildGraph(*item);
graph->BuildDominatorTree();
graph->TransformToSSA();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
return graph;
}
@@ -494,7 +494,7 @@
(*phi)->AddInput(*input2);
graph->BuildDominatorTree();
- graph->FindNaturalLoops();
+ graph->AnalyzeNaturalLoops();
return graph;
}
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 5ab328f..2cbd51a 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -22,20 +22,6 @@
namespace art {
-class TransformToSsa : public HOptimization {
- public:
- explicit TransformToSsa(HGraph* graph) : HOptimization(graph, true, "ssa transform") {}
-
- void Run() OVERRIDE {
- graph_->BuildDominatorTree();
- graph_->TransformToSSA();
- graph_->FindNaturalLoops();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TransformToSsa);
-};
-
static constexpr int kDefaultNumberOfLoops = 2;
class SsaBuilder : public HGraphVisitor {
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index 004af98..a80ad93 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -189,6 +189,15 @@
return ret;
}
+size_t ArenaPool::GetBytesAllocated() const {
+ size_t total = 0;
+ MutexLock lock(Thread::Current(), lock_);
+ for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
+ total += arena->GetBytesAllocated();
+ }
+ return total;
+}
+
void ArenaPool::FreeArenaChain(Arena* first) {
if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
diff --git a/compiler/utils/arena_allocator.h b/compiler/utils/arena_allocator.h
index 6d21399..7f5bc9a 100644
--- a/compiler/utils/arena_allocator.h
+++ b/compiler/utils/arena_allocator.h
@@ -135,6 +135,10 @@
return Size() - bytes_allocated_;
}
+ size_t GetBytesAllocated() const {
+ return bytes_allocated_;
+ }
+
private:
size_t bytes_allocated_;
uint8_t* memory_;
@@ -153,11 +157,12 @@
public:
ArenaPool();
~ArenaPool();
- Arena* AllocArena(size_t size);
- void FreeArenaChain(Arena* first);
+ Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_);
+ void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_);
+ size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_);
private:
- Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
Arena* free_arenas_ GUARDED_BY(lock_);
DISALLOW_COPY_AND_ASSIGN(ArenaPool);
};
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 869c822..a1ac2f0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -25,6 +25,10 @@
#include <string>
#include <vector>
+#ifndef __APPLE__
+#include <malloc.h> // For mallinfo
+#endif
+
#if defined(__linux__) && defined(__arm__)
#include <sys/personality.h>
#include <sys/utsname.h>
@@ -450,10 +454,10 @@
timings_(timings) {}
~Dex2Oat() {
+ LogCompletionTime(); // Needs to be before since it accesses the runtime.
if (kIsDebugBuild || (RUNNING_ON_VALGRIND != 0)) {
delete runtime_; // See field declaration for why this is manual.
}
- LogCompletionTime();
}
// Parse the arguments from the command line. In case of an unrecognized option or impossible
@@ -709,6 +713,16 @@
// on having verbost methods.
gLogVerbosity.compiler = false;
Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods_);
+ } else if (option.starts_with("--dump-init-failures=")) {
+ std::string file_name = option.substr(strlen("--dump-init-failures=")).data();
+ init_failure_output_.reset(new std::ofstream(file_name));
+ if (init_failure_output_.get() == nullptr) {
+ LOG(ERROR) << "Failed to allocate ofstream";
+ } else if (init_failure_output_->fail()) {
+ LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization "
+ << "failures.";
+ init_failure_output_.reset();
+ }
} else {
Usage("Unknown argument %s", option.data());
}
@@ -918,7 +932,8 @@
#endif
verbose_methods_.empty() ?
nullptr :
- &verbose_methods_));
+ &verbose_methods_,
+ init_failure_output_.get()));
// Done with usage checks, enable watchdog if requested
if (watch_dog_enabled) {
@@ -1593,9 +1608,21 @@
return ReadImageClasses(image_classes_stream);
}
- void LogCompletionTime() const {
+ void LogCompletionTime() {
+ std::ostringstream mallinfostr;
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ const size_t allocated_space = static_cast<size_t>(info.uordblks);
+ const size_t free_space = static_cast<size_t>(info.fordblks);
+ mallinfostr << " native alloc=" << PrettySize(allocated_space) << " free="
+ << PrettySize(free_space);
+#endif
+ const ArenaPool* arena_pool = driver_->GetArenaPool();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
- << " (threads: " << thread_count_ << ")";
+ << " (threads: " << thread_count_ << ")"
+ << " arena alloc=" << PrettySize(arena_pool->GetBytesAllocated())
+ << " java alloc=" << PrettySize(heap->GetBytesAllocated()) << mallinfostr.str();
}
std::unique_ptr<CompilerOptions> compiler_options_;
@@ -1652,6 +1679,7 @@
std::string profile_file_; // Profile file to use
TimingLogger* timings_;
std::unique_ptr<CumulativeLogger> compiler_phases_timings_;
+ std::unique_ptr<std::ostream> init_failure_output_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
};
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d28b626..b048833 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -32,7 +32,6 @@
#include "dex_instruction.h"
#include "disassembler.h"
#include "elf_builder.h"
-#include "field_helper.h"
#include "gc_map.h"
#include "gc/space/image_space.h"
#include "gc/space/large_object_space.h"
@@ -1459,50 +1458,54 @@
static void PrintField(std::ostream& os, mirror::ArtField* field, mirror::Object* obj)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const char* descriptor = field->GetTypeDescriptor();
os << StringPrintf("%s: ", field->GetName());
- if (descriptor[0] != 'L' && descriptor[0] != '[') {
- StackHandleScope<1> hs(Thread::Current());
- FieldHelper fh(hs.NewHandle(field));
- mirror::Class* type = fh.GetType();
- DCHECK(type->IsPrimitive());
- if (type->IsPrimitiveLong()) {
+ switch (field->GetTypeAsPrimitiveType()) {
+ case Primitive::kPrimLong:
os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
- } else if (type->IsPrimitiveDouble()) {
+ break;
+ case Primitive::kPrimDouble:
os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
- } else if (type->IsPrimitiveFloat()) {
+ break;
+ case Primitive::kPrimFloat:
os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
- } else if (type->IsPrimitiveInt()) {
+ break;
+ case Primitive::kPrimInt:
os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
- } else if (type->IsPrimitiveChar()) {
+ break;
+ case Primitive::kPrimChar:
os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
- } else if (type->IsPrimitiveShort()) {
+ break;
+ case Primitive::kPrimShort:
os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
- } else if (type->IsPrimitiveBoolean()) {
+ break;
+ case Primitive::kPrimBoolean:
os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
field->GetBoolean(obj));
- } else if (type->IsPrimitiveByte()) {
+ break;
+ case Primitive::kPrimByte:
os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
- } else {
- LOG(FATAL) << "Unknown type: " << PrettyClass(type);
- }
- } else {
- // Get the value, don't compute the type unless it is non-null as we don't want
- // to cause class loading.
- mirror::Object* value = field->GetObj(obj);
- if (value == nullptr) {
- os << StringPrintf("null %s\n", PrettyDescriptor(descriptor).c_str());
- } else {
- // Grab the field type without causing resolution.
- StackHandleScope<1> hs(Thread::Current());
- FieldHelper fh(hs.NewHandle(field));
- mirror::Class* field_type = fh.GetType(false);
- if (field_type != nullptr) {
- PrettyObjectValue(os, field_type, value);
+ break;
+ case Primitive::kPrimNot: {
+ // Get the value, don't compute the type unless it is non-null as we don't want
+ // to cause class loading.
+ mirror::Object* value = field->GetObj(obj);
+ if (value == nullptr) {
+ os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
} else {
- os << StringPrintf("%p %s\n", value, PrettyDescriptor(descriptor).c_str());
+ // Grab the field type without causing resolution.
+ mirror::Class* field_type = field->GetType(false);
+ if (field_type != nullptr) {
+ PrettyObjectValue(os, field_type, value);
+ } else {
+ os << StringPrintf("%p %s\n", value,
+ PrettyDescriptor(field->GetTypeDescriptor()).c_str());
+ }
}
+ break;
}
+ default:
+ os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
+ break;
}
}
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 087c0ea..7dfdb75 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -42,7 +42,6 @@
dex_file_verifier.cc \
dex_instruction.cc \
elf_file.cc \
- field_helper.cc \
gc/allocator/dlmalloc.cc \
gc/allocator/rosalloc.cc \
gc/accounting/card_table.cc \
@@ -91,7 +90,6 @@
jobject_comparator.cc \
mem_map.cc \
memory_region.cc \
- method_helper.cc \
mirror/art_field.cc \
mirror/art_method.cc \
mirror/array.cc \
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index fe5b765..e45d3a3 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -24,7 +24,6 @@
#include "class_linker.h"
#include "class_linker-inl.h"
#include "dex_file-inl.h"
-#include "field_helper.h"
#include "gc/space/space.h"
#include "java_vm_ext.h"
#include "jni_internal.h"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4bd702d..6aab632 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -43,7 +43,6 @@
#include "intern_table.h"
#include "interpreter/interpreter.h"
#include "leb128.h"
-#include "method_helper-inl.h"
#include "oat.h"
#include "oat_file.h"
#include "object_lock.h"
@@ -1671,6 +1670,7 @@
LOG(FATAL) << "Failed to open dex file " << dex_file_location
<< " from within oat file " << oat_file.GetLocation()
<< " error '" << error_msg << "'";
+ UNREACHABLE();
}
CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
@@ -2393,6 +2393,7 @@
break;
default:
LOG(FATAL) << "Unknown descriptor: " << c;
+ UNREACHABLE();
}
}
}
@@ -2442,7 +2443,7 @@
}
DCHECK(!it.HasNext());
LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation();
- return 0;
+ UNREACHABLE();
}
const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) {
@@ -3078,7 +3079,7 @@
LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
}
LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
- return nullptr;
+ UNREACHABLE();
}
void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
@@ -3749,8 +3750,7 @@
LOG(FATAL) << "Unexpected class status: " << oat_file_class_status
<< " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " "
<< klass->GetDescriptor(&temp);
-
- return false;
+ UNREACHABLE();
}
void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
@@ -4345,6 +4345,41 @@
UNREACHABLE();
}
+static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
+ Handle<mirror::ArtMethod> method1,
+ Handle<mirror::ArtMethod> method2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType()));
+ if (UNLIKELY(method2->GetReturnType() != return_type.Get())) {
+ return false;
+ }
+ }
+ const DexFile::TypeList* types1 = method1->GetParameterTypeList();
+ const DexFile::TypeList* types2 = method2->GetParameterTypeList();
+ if (types1 == nullptr) {
+ return (types2 == nullptr) || (types2->Size() == 0);
+ } else if (UNLIKELY(types2 == nullptr)) {
+ return types1->Size() == 0;
+ }
+ uint32_t num_types = types1->Size();
+ if (UNLIKELY(num_types != types2->Size())) {
+ return false;
+ }
+ for (uint32_t i = 0; i < num_types; ++i) {
+ mirror::Class* param_type =
+ method1->GetClassFromTypeIndex(types1->GetTypeItem(i).type_idx_, true);
+ mirror::Class* other_param_type =
+ method2->GetClassFromTypeIndex(types2->GetTypeItem(i).type_idx_, true);
+ if (UNLIKELY(param_type != other_param_type)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
if (klass->IsInterface()) {
return true;
@@ -4352,19 +4387,19 @@
// Begin with the methods local to the superclass.
Thread* self = Thread::Current();
StackHandleScope<2> hs(self);
- MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
- MutableMethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+ MutableHandle<mirror::ArtMethod> h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
+ MutableHandle<mirror::ArtMethod> super_h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
if (klass->HasSuperClass() &&
klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
for (int i = klass->GetSuperClass()->GetVTableLength() - 1; i >= 0; --i) {
- mh.ChangeMethod(klass->GetVTableEntry(i));
- super_mh.ChangeMethod(klass->GetSuperClass()->GetVTableEntry(i));
- if (mh.GetMethod() != super_mh.GetMethod() &&
- !mh.HasSameSignatureWithDifferentClassLoaders(self, &super_mh)) {
+ h_m.Assign(klass->GetVTableEntry(i));
+ super_h_m.Assign(klass->GetSuperClass()->GetVTableEntry(i));
+ if (h_m.Get() != super_h_m.Get() &&
+ !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
ThrowLinkageError(klass.Get(),
"Class %s method %s resolves differently in superclass %s",
PrettyDescriptor(klass.Get()).c_str(),
- PrettyMethod(mh.GetMethod()).c_str(),
+ PrettyMethod(h_m.Get()).c_str(),
PrettyDescriptor(klass->GetSuperClass()).c_str());
return false;
}
@@ -4374,14 +4409,14 @@
if (klass->GetClassLoader() != klass->GetIfTable()->GetInterface(i)->GetClassLoader()) {
uint32_t num_methods = klass->GetIfTable()->GetInterface(i)->NumVirtualMethods();
for (uint32_t j = 0; j < num_methods; ++j) {
- mh.ChangeMethod(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
- super_mh.ChangeMethod(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
- if (mh.GetMethod() != super_mh.GetMethod() &&
- !mh.HasSameSignatureWithDifferentClassLoaders(self, &super_mh)) {
+ h_m.Assign(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
+ super_h_m.Assign(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
+ if (h_m.Get() != super_h_m.Get() &&
+ !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
ThrowLinkageError(klass.Get(),
"Class %s method %s resolves differently in interface %s",
PrettyDescriptor(klass.Get()).c_str(),
- PrettyMethod(mh.GetMethod()).c_str(),
+ PrettyMethod(h_m.Get()).c_str(),
PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str());
return false;
}
@@ -5566,71 +5601,73 @@
}
// If we found something, check that it can be accessed by the referrer.
+ bool exception_generated = false;
if (resolved != nullptr && referrer.Get() != nullptr) {
mirror::Class* methods_class = resolved->GetDeclaringClass();
mirror::Class* referring_class = referrer->GetDeclaringClass();
if (!referring_class->CanAccess(methods_class)) {
ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class,
resolved, type);
- return nullptr;
+ exception_generated = true;
} else if (!referring_class->CanAccessMember(methods_class,
resolved->GetAccessFlags())) {
ThrowIllegalAccessErrorMethod(referring_class, resolved);
- return nullptr;
+ exception_generated = true;
}
}
-
- // Otherwise, throw an IncompatibleClassChangeError if we found something, and check interface
- // methods and throw if we find the method there. If we find nothing, throw a
- // NoSuchMethodError.
- switch (type) {
- case kDirect:
- case kStatic:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
- } else {
- resolved = klass->FindInterfaceMethod(name, signature);
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- }
- break;
- case kInterface:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
- } else {
- resolved = klass->FindVirtualMethod(name, signature);
+ if (!exception_generated) {
+ // Otherwise, throw an IncompatibleClassChangeError if we found something, and check
+ // interface methods and throw if we find the method there. If we find nothing, throw a
+ // NoSuchMethodError.
+ switch (type) {
+ case kDirect:
+ case kStatic:
if (resolved != nullptr) {
ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
} else {
- ThrowNoSuchMethodError(type, klass, name, signature);
+ resolved = klass->FindInterfaceMethod(name, signature);
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+ } else {
+ ThrowNoSuchMethodError(type, klass, name, signature);
+ }
}
- }
- break;
- case kSuper:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- break;
- case kVirtual:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
- } else {
- resolved = klass->FindInterfaceMethod(name, signature);
+ break;
+ case kInterface:
if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+ ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+ } else {
+ resolved = klass->FindVirtualMethod(name, signature);
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
+ } else {
+ ThrowNoSuchMethodError(type, klass, name, signature);
+ }
+ }
+ break;
+ case kSuper:
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
} else {
ThrowNoSuchMethodError(type, klass, name, signature);
}
- }
- break;
+ break;
+ case kVirtual:
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+ } else {
+ resolved = klass->FindInterfaceMethod(name, signature);
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+ } else {
+ ThrowNoSuchMethodError(type, klass, name, signature);
+ }
+ }
+ break;
+ }
}
}
- DCHECK(Thread::Current()->IsExceptionPending());
+ Thread::Current()->AssertPendingException();
return nullptr;
}
}
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 99d0746..ac078aa 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -23,7 +23,6 @@
#include "common_runtime_test.h"
#include "dex_file.h"
#include "entrypoints/entrypoint_utils-inl.h"
-#include "field_helper.h"
#include "gc/heap.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method.h"
@@ -178,9 +177,7 @@
EXPECT_TRUE(field->GetClass() != nullptr);
EXPECT_EQ(klass, field->GetDeclaringClass());
EXPECT_TRUE(field->GetName() != nullptr);
- StackHandleScope<1> hs(Thread::Current());
- FieldHelper fh(hs.NewHandle(field));
- EXPECT_TRUE(fh.GetType() != nullptr);
+ EXPECT_TRUE(field->GetType(true) != nullptr);
}
void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass)
@@ -286,8 +283,7 @@
for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
mirror::ArtField* field = klass->GetInstanceField(i);
fhandle.Assign(field);
- FieldHelper fh(fhandle);
- mirror::Class* field_type = fh.GetType();
+ mirror::Class* field_type = fhandle->GetType(true);
ASSERT_TRUE(field_type != nullptr);
if (!field->IsPrimitiveType()) {
ASSERT_TRUE(!field_type->IsPrimitive());
@@ -295,7 +291,7 @@
if (current_ref_offset.Uint32Value() == end_ref_offset.Uint32Value()) {
// While Reference.referent is not primitive, the ClassLinker
// treats it as such so that the garbage collector won't scan it.
- EXPECT_EQ(PrettyField(fh.GetField()),
+ EXPECT_EQ(PrettyField(fhandle.Get()),
"java.lang.Object java.lang.ref.Reference.referent");
} else {
current_ref_offset = MemberOffset(current_ref_offset.Uint32Value() +
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 49b132d..d5cba50 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -25,13 +25,11 @@
#include "class_linker-inl.h"
#include "dex_file-inl.h"
#include "dex_instruction.h"
-#include "field_helper.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
#include "handle_scope.h"
#include "jdwp/object_registry.h"
-#include "method_helper-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class.h"
@@ -1924,7 +1922,7 @@
HandleWrapper<mirror::Object> h_v(hs.NewHandleWrapper(&v));
HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o));
- field_type = FieldHelper(h_f).GetType();
+ field_type = h_f->GetType(true);
}
if (!field_type->IsAssignableFrom(v->GetClass())) {
return JDWP::ERR_INVALID_OBJECT;
@@ -3679,7 +3677,7 @@
{
StackHandleScope<3> hs(soa.Self());
- MethodHelper mh(hs.NewHandle(m));
+ HandleWrapper<mirror::ArtMethod> h_m(hs.NewHandleWrapper(&m));
HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&receiver));
HandleWrapper<mirror::Class> h_klass(hs.NewHandleWrapper(&c));
const DexFile::TypeList* types = m->GetParameterTypeList();
@@ -3690,7 +3688,8 @@
if (shorty[i + 1] == 'L') {
// Did we really get an argument of an appropriate reference type?
- mirror::Class* parameter_type = mh.GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
+ mirror::Class* parameter_type =
+ h_m->GetClassFromTypeIndex(types->GetTypeItem(i).type_idx_, true);
mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i], &error);
if (error != JDWP::ERR_NONE) {
return JDWP::ERR_INVALID_OBJECT;
@@ -3704,8 +3703,6 @@
v.l = gRegistry->GetJObject(arg_values[i]);
}
}
- // Update in case it moved.
- m = mh.GetMethod();
}
req->receiver = receiver;
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index da2dfe1..c329fe6 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -20,7 +20,6 @@
#include "class_linker-inl.h"
#include "dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
-#include "method_helper-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 908d3cd..3b47f24 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -24,9 +24,7 @@
namespace art {
-// TODO: Make the MethodHelper here be compaction safe.
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
mirror::ArtMethod* method = shadow_frame->GetMethod();
// Ensure static methods are initialized.
@@ -50,11 +48,11 @@
}
uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
if (kUsePortableCompiler) {
- InvokeWithShadowFrame(self, shadow_frame, arg_offset, mh, result);
+ InvokeWithShadowFrame(self, shadow_frame, arg_offset, result);
} else {
method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
(shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
- result, mh->GetShorty());
+ result, method->GetShorty());
}
}
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.h b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
index 5d646e9..0952214 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.h
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
@@ -27,17 +27,14 @@
namespace art {
union JValue;
-class MethodHelper;
class ShadowFrame;
class Thread;
// Pointers to functions that are called by interpreter trampolines via thread-local storage.
struct PACKED(4) InterpreterEntryPoints {
- void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+ void (*pInterpreterToInterpreterBridge)(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result);
- void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+ void (*pInterpreterToCompiledCodeBridge)(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result);
};
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index e7975f8..2a2771f 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -27,6 +27,56 @@
namespace art {
+class ShortyHelper {
+ public:
+ ShortyHelper(const char* shorty, uint32_t shorty_len, bool is_static)
+ : shorty_(shorty), shorty_len_(shorty_len), is_static_(is_static) {
+ }
+
+ const char* GetShorty() const {
+ return shorty_;
+ }
+
+ uint32_t GetShortyLength() const {
+ return shorty_len_;
+ }
+
+ size_t NumArgs() const {
+ // "1 +" because the first in Args is the receiver.
+ // "- 1" because we don't count the return type.
+ return (is_static_ ? 0 : 1) + GetShortyLength() - 1;
+ }
+
+ // Get the primitive type associated with the given parameter.
+ Primitive::Type GetParamPrimitiveType(size_t param) const {
+ CHECK_LT(param, NumArgs());
+ if (is_static_) {
+ param++; // 0th argument must skip return value at start of the shorty.
+ } else if (param == 0) {
+ return Primitive::kPrimNot;
+ }
+ return Primitive::GetType(shorty_[param]);
+ }
+
+ // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods.
+ bool IsParamALongOrDouble(size_t param) const {
+ Primitive::Type type = GetParamPrimitiveType(param);
+ return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
+ }
+
+ // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods.
+ bool IsParamAReference(size_t param) const {
+ return GetParamPrimitiveType(param) == Primitive::kPrimNot;
+ }
+
+ private:
+ const char* const shorty_;
+ const uint32_t shorty_len_;
+ const bool is_static_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShortyHelper);
+};
+
// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
class PortableArgumentVisitor {
public:
@@ -60,7 +110,7 @@
#define PORTABLE_STACK_ARG_SKIP 0
#endif
- PortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp)
+ PortableArgumentVisitor(ShortyHelper& caller_mh, mirror::ArtMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
caller_mh_(caller_mh),
args_in_regs_(ComputeArgsInRegs(caller_mh)),
@@ -119,7 +169,7 @@
}
private:
- static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ static size_t ComputeArgsInRegs(ShortyHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
#if (defined(__i386__))
UNUSED(mh);
return 0;
@@ -136,7 +186,7 @@
return args_in_regs;
#endif
}
- MethodHelper& caller_mh_;
+ ShortyHelper& caller_mh_;
const size_t args_in_regs_;
const size_t num_params_;
uint8_t* const reg_args_;
@@ -149,7 +199,7 @@
// Visits arguments on the stack placing them into the shadow frame.
class BuildPortableShadowFrameVisitor : public PortableArgumentVisitor {
public:
- BuildPortableShadowFrameVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
+ BuildPortableShadowFrameVisitor(ShortyHelper& caller_mh, mirror::ArtMethod** sp,
ShadowFrame& sf, size_t first_arg_reg) :
PortableArgumentVisitor(caller_mh, sp), sf_(sf), cur_reg_(first_arg_reg) { }
virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -198,7 +248,9 @@
} else {
const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
StackHandleScope<2> hs(self);
- MethodHelper mh(hs.NewHandle(method));
+ uint32_t shorty_len;
+ const char* shorty = method->GetShorty(&shorty_len);
+ ShortyHelper mh(shorty, shorty_len, method->IsStatic());
const DexFile::CodeItem* code_item = method->GetCodeItem();
uint16_t num_regs = code_item->registers_size_;
void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
@@ -224,7 +276,7 @@
}
}
- JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
+ JValue result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);
// Pop transition.
self->PopManagedStackFragment(fragment);
return result.GetJ();
@@ -235,7 +287,7 @@
// to jobjects.
class BuildPortableArgumentVisitor : public PortableArgumentVisitor {
public:
- BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
+ BuildPortableArgumentVisitor(ShortyHelper& caller_mh, mirror::ArtMethod** sp,
ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
@@ -294,8 +346,9 @@
jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
// Placing arguments into args vector and remove the receiver.
- StackHandleScope<1> hs(self);
- MethodHelper proxy_mh(hs.NewHandle(proxy_method));
+ uint32_t shorty_len;
+ const char* shorty = proxy_method->GetShorty(&shorty_len);
+ ShortyHelper proxy_mh(shorty, shorty_len, false);
std::vector<jvalue> args;
BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
local_ref_visitor.VisitArguments();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 93dc62a..cb81629 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -22,6 +22,7 @@
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
+#include "method_reference.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -510,25 +511,25 @@
BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
shadow_frame, first_arg_reg);
shadow_frame_builder.VisitArguments();
+ const bool needs_initialization =
+ method->IsStatic() && !method->GetDeclaringClass()->IsInitialized();
// Push a transition back into managed code onto the linked list in thread.
ManagedStack fragment;
self->PushManagedStackFragment(&fragment);
self->PushShadowFrame(shadow_frame);
self->EndAssertNoThreadSuspension(old_cause);
- StackHandleScope<1> hs(self);
- MethodHelper mh(hs.NewHandle(method));
- if (mh.Get()->IsStatic() && !mh.Get()->GetDeclaringClass()->IsInitialized()) {
+ if (needs_initialization) {
// Ensure static method's class is initialized.
- StackHandleScope<1> hs2(self);
- Handle<mirror::Class> h_class(hs2.NewHandle(mh.Get()->GetDeclaringClass()));
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class(hs.NewHandle(shadow_frame->GetMethod()->GetDeclaringClass()));
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
- DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(mh.Get());
+ DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(shadow_frame->GetMethod());
self->PopManagedStackFragment(fragment);
return 0;
}
}
- JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
+ JValue result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);
// Pop transition.
self->PopManagedStackFragment(fragment);
// No need to restore the args since the method has already been run by the interpreter.
@@ -641,7 +642,7 @@
// Convert proxy method into expected interface method.
mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
- DCHECK(interface_method != NULL) << PrettyMethod(proxy_method);
+ DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method);
DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
@@ -710,12 +711,12 @@
ClassLinker* linker = Runtime::Current()->GetClassLinker();
mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
InvokeType invoke_type;
- const DexFile* dex_file;
- uint32_t dex_method_idx;
- if (called->IsRuntimeMethod()) {
+ MethodReference called_method(nullptr, 0);
+ const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+ if (!called_method_known_on_entry) {
uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
const DexFile::CodeItem* code;
- dex_file = caller->GetDexFile();
+ called_method.dex_file = caller->GetDexFile();
code = caller->GetCodeItem();
CHECK_LT(dex_pc, code->insns_size_in_code_units_);
const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
@@ -763,33 +764,33 @@
is_range = true;
break;
default:
- LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
- // Avoid used uninitialized warnings.
- invoke_type = kDirect;
- is_range = false;
+ LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);
+ UNREACHABLE();
}
- dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
+ called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
} else {
invoke_type = kStatic;
- dex_file = called->GetDexFile();
- dex_method_idx = called->GetDexMethodIndex();
+ called_method.dex_file = called->GetDexFile();
+ called_method.dex_method_index = called->GetDexMethodIndex();
}
uint32_t shorty_len;
const char* shorty =
- dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
+ called_method.dex_file->GetMethodShorty(
+ called_method.dex_file->GetMethodId(called_method.dex_method_index), &shorty_len);
RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
visitor.VisitArguments();
self->EndAssertNoThreadSuspension(old_cause);
- bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
+ const bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
// Resolve method filling in dex cache.
- if (UNLIKELY(called->IsRuntimeMethod())) {
+ if (!called_method_known_on_entry) {
StackHandleScope<1> hs(self);
mirror::Object* dummy = nullptr;
HandleWrapper<mirror::Object> h_receiver(
hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
- called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type);
+ DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+ called = linker->ResolveMethod(self, called_method.dex_method_index, &caller, invoke_type);
}
- const void* code = NULL;
+ const void* code = nullptr;
if (LIKELY(!self->IsExceptionPending())) {
// Incompatible class change should have been handled in resolve method.
CHECK(!called->CheckIncompatibleClassChange(invoke_type))
@@ -810,20 +811,26 @@
<< invoke_type << " " << orig_called->GetVtableIndex();
// We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
- // of the sharpened method.
- if (called->HasSameDexCacheResolvedMethods(caller)) {
- caller->SetDexCacheResolvedMethod(called->GetDexMethodIndex(), called);
- } else {
+ // of the sharpened method avoiding dirtying the dex cache if possible.
+ // Note, called_method.dex_method_index references the dex method before the
+ // FindVirtualMethodFor... This is ok for FindDexMethodIndexInOtherDexFile that only cares
+ // about the name and signature.
+ uint32_t update_dex_cache_method_index = called->GetDexMethodIndex();
+ if (!called->HasSameDexCacheResolvedMethods(caller)) {
// Calling from one dex file to another, need to compute the method index appropriate to
// the caller's dex file. Since we get here only if the original called was a runtime
// method, we've got the correct dex_file and a dex_method_idx from above.
- DCHECK_EQ(caller->GetDexFile(), dex_file);
- StackHandleScope<1> hs(self);
- MethodHelper mh(hs.NewHandle(called));
- uint32_t method_index = mh.FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
- if (method_index != DexFile::kDexNoIndex) {
- caller->SetDexCacheResolvedMethod(method_index, called);
- }
+ DCHECK(!called_method_known_on_entry);
+ DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+ const DexFile* caller_dex_file = called_method.dex_file;
+ uint32_t caller_method_name_and_sig_index = called_method.dex_method_index;
+ update_dex_cache_method_index =
+ called->FindDexMethodIndexInOtherDexFile(*caller_dex_file,
+ caller_method_name_and_sig_index);
+ }
+ if ((update_dex_cache_method_index != DexFile::kDexNoIndex) &&
+ (caller->GetDexCacheResolvedMethod(update_dex_cache_method_index) != called)) {
+ caller->SetDexCacheResolvedMethod(update_dex_cache_method_index, called);
}
}
// Ensure that the called method's class is initialized.
@@ -845,7 +852,7 @@
DCHECK(called_class->IsErroneous());
}
}
- CHECK_EQ(code == NULL, self->IsExceptionPending());
+ CHECK_EQ(code == nullptr, self->IsExceptionPending());
// Fixup any locally saved objects may have moved during a GC.
visitor.FixupReferences();
// Place called method in callee-save frame to be placed as first argument to quick method.
@@ -1262,6 +1269,7 @@
break;
default:
LOG(FATAL) << "Unexpected type: " << cur_type_ << " in " << shorty;
+ UNREACHABLE();
}
}
@@ -1785,7 +1793,7 @@
visitor.FixupReferences();
}
- if (UNLIKELY(method == NULL)) {
+ if (UNLIKELY(method == nullptr)) {
CHECK(self->IsExceptionPending());
return GetTwoWordFailureValue(); // Failure.
}
@@ -1794,7 +1802,7 @@
const void* code = method->GetEntryPointFromQuickCompiledCode();
// When we return, the caller will branch to this address, so it had better not be 0!
- DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+ DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
<< " location: "
<< method->GetDexFile()->GetLocation();
@@ -1880,7 +1888,7 @@
mirror::ArtMethod* method;
if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
- if (UNLIKELY(method == NULL)) {
+ if (UNLIKELY(method == nullptr)) {
ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object,
caller_method);
return GetTwoWordFailureValue(); // Failure.
@@ -1900,7 +1908,7 @@
Instruction::Code instr_code = instr->Opcode();
CHECK(instr_code == Instruction::INVOKE_INTERFACE ||
instr_code == Instruction::INVOKE_INTERFACE_RANGE)
- << "Unexpected call into interface trampoline: " << instr->DumpString(NULL);
+ << "Unexpected call into interface trampoline: " << instr->DumpString(nullptr);
uint32_t dex_method_idx;
if (instr_code == Instruction::INVOKE_INTERFACE) {
dex_method_idx = instr->VRegB_35c();
@@ -1932,7 +1940,7 @@
const void* code = method->GetEntryPointFromQuickCompiledCode();
// When we return, the caller will branch to this address, so it had better not be 0!
- DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+ DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
<< " location: " << method->GetDexFile()->GetLocation();
return GetTwoWordSuccessValue(reinterpret_cast<uintptr_t>(code),
diff --git a/runtime/field_helper.cc b/runtime/field_helper.cc
deleted file mode 100644
index 5c85c46..0000000
--- a/runtime/field_helper.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "field_helper.h"
-
-#include "class_linker-inl.h"
-#include "dex_file.h"
-#include "mirror/dex_cache.h"
-#include "runtime.h"
-#include "thread-inl.h"
-
-namespace art {
-
-mirror::Class* FieldHelper::GetType(bool resolve) {
- uint32_t field_index = field_->GetDexFieldIndex();
- if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) {
- return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
- field_->GetTypeDescriptor());
- }
- const DexFile* dex_file = field_->GetDexFile();
- const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
- mirror::Class* type = field_->GetDexCache()->GetResolvedType(field_id.type_idx_);
- if (resolve && (type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, field_.Get());
- CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
- }
- return type;
-}
-
-const char* FieldHelper::GetDeclaringClassDescriptor() {
- return field_->GetDeclaringClass()->GetDescriptor(&declaring_class_descriptor_);
-}
-
-} // namespace art
diff --git a/runtime/field_helper.h b/runtime/field_helper.h
deleted file mode 100644
index 8097025..0000000
--- a/runtime/field_helper.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_FIELD_HELPER_H_
-#define ART_RUNTIME_FIELD_HELPER_H_
-
-#include "base/macros.h"
-#include "handle.h"
-#include "mirror/art_field.h"
-
-namespace art {
-
-class FieldHelper {
- public:
- explicit FieldHelper(Handle<mirror::ArtField> f) : field_(f) {}
-
- mirror::ArtField* GetField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return field_.Get();
- }
-
- mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // The returned const char* is only guaranteed to be valid for the lifetime of the FieldHelper.
- // If you need it longer, copy it into a std::string.
- const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
- Handle<mirror::ArtField> field_;
- std::string declaring_class_descriptor_;
-
- DISALLOW_COPY_AND_ASSIGN(FieldHelper);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_FIELD_HELPER_H_
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index b17f303..b04a18b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -327,37 +327,31 @@
// Clang 3.4 fails to build the goto interpreter implementation.
static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImpl;
template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread*, MethodHelper&, const DexFile::CodeItem*, ShadowFrame&, JValue) {
+JValue ExecuteGotoImpl(Thread*, const DexFile::CodeItem*, ShadowFrame&, JValue) {
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
}
// Explicit definitions of ExecuteGotoImpl.
template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
-template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
#endif
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register)
+static JValue Execute(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
+ JValue result_register)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
- DCHECK(shadow_frame.GetMethod() == mh.GetMethod() ||
- shadow_frame.GetMethod()->GetDeclaringClass()->IsProxyClass());
DCHECK(!shadow_frame.GetMethod()->IsAbstract());
DCHECK(!shadow_frame.GetMethod()->IsNative());
shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
@@ -367,32 +361,32 @@
// Enter the "without access check" interpreter.
if (kInterpreterImplKind == kSwitchImpl) {
if (transaction_active) {
- return ExecuteSwitchImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register);
} else {
- return ExecuteSwitchImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register);
}
} else {
DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
if (transaction_active) {
- return ExecuteGotoImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteGotoImpl<false, true>(self, code_item, shadow_frame, result_register);
} else {
- return ExecuteGotoImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame, result_register);
}
}
} else {
// Enter the "with access check" interpreter.
if (kInterpreterImplKind == kSwitchImpl) {
if (transaction_active) {
- return ExecuteSwitchImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register);
} else {
- return ExecuteSwitchImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register);
}
} else {
DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
if (transaction_active) {
- return ExecuteGotoImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteGotoImpl<true, true>(self, code_item, shadow_frame, result_register);
} else {
- return ExecuteGotoImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+ return ExecuteGotoImpl<true, false>(self, code_item, shadow_frame, result_register);
}
}
}
@@ -473,9 +467,7 @@
}
}
if (LIKELY(!method->IsNative())) {
- StackHandleScope<1> hs(self);
- MethodHelper mh(hs.NewHandle(method));
- JValue r = Execute(self, mh, code_item, *shadow_frame, JValue());
+ JValue r = Execute(self, code_item, *shadow_frame, JValue());
if (result != NULL) {
*result = r;
}
@@ -500,10 +492,8 @@
value.SetJ(ret_val->GetJ()); // Set value to last known result in case the shadow frame chain is empty.
while (shadow_frame != NULL) {
self->SetTopOfShadowStack(shadow_frame);
- StackHandleScope<1> hs(self);
- MethodHelper mh(hs.NewHandle(shadow_frame->GetMethod()));
- const DexFile::CodeItem* code_item = mh.GetMethod()->GetCodeItem();
- value = Execute(self, mh, code_item, *shadow_frame, value);
+ const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem();
+ value = Execute(self, code_item, *shadow_frame, value);
ShadowFrame* old_frame = shadow_frame;
shadow_frame = shadow_frame->GetLink();
delete old_frame;
@@ -511,8 +501,7 @@
ret_val->SetJ(value.GetJ());
}
-JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame) {
DCHECK_EQ(self, Thread::Current());
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -521,11 +510,10 @@
return JValue();
}
- return Execute(self, *mh, code_item, *shadow_frame, JValue());
+ return Execute(self, code_item, *shadow_frame, JValue());
}
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) {
@@ -534,10 +522,10 @@
}
self->PushShadowFrame(shadow_frame);
- DCHECK_EQ(shadow_frame->GetMethod(), mh->Get());
// Ensure static methods are initialized.
- if (mh->Get()->IsStatic()) {
- mirror::Class* declaring_class = mh->Get()->GetDeclaringClass();
+ const bool is_static = shadow_frame->GetMethod()->IsStatic();
+ if (is_static) {
+ mirror::Class* declaring_class = shadow_frame->GetMethod()->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(self);
HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
@@ -551,15 +539,15 @@
}
}
- if (LIKELY(!mh->Get()->IsNative())) {
- result->SetJ(Execute(self, *mh, code_item, *shadow_frame, JValue()).GetJ());
+ if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
+ result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ());
} else {
// We don't expect to be asked to interpret native code (which is entered via a JNI compiler
// generated stub) except during testing and image writing.
CHECK(!Runtime::Current()->IsStarted());
- Object* receiver = mh->Get()->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
- uint32_t* args = shadow_frame->GetVRegArgs(mh->Get()->IsStatic() ? 0 : 1);
- UnstartedRuntimeJni(self, mh->Get(), receiver, args, result);
+ Object* receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0);
+ uint32_t* args = shadow_frame->GetVRegArgs(is_static ? 0 : 1);
+ UnstartedRuntimeJni(self, shadow_frame->GetMethod(), receiver, args, result);
}
self->PopShadowFrame();
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index d327a71..7d634b3 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -27,7 +27,6 @@
} // namespace mirror
union JValue;
-class MethodHelper;
class ShadowFrame;
class Thread;
@@ -42,21 +41,18 @@
JValue* ret_val)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-extern JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
} // namespace interpreter
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index eb80c30..3c7db85 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -16,7 +16,6 @@
#include "interpreter_common.h"
-#include "field_helper.h"
#include "mirror/array-inl.h"
namespace art {
@@ -267,8 +266,7 @@
HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(®));
HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
- FieldHelper fh(h_f);
- field_class = fh.GetType();
+ field_class = h_f->GetType(true);
}
if (!reg->VerifierInstanceOf(field_class)) {
// This should never happen.
@@ -505,14 +503,14 @@
return found_dex_pc;
}
-void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
- LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(mh.GetMethod()->GetDexFile());
- exit(0); // Unreachable, keep GCC happy.
+void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) {
+ LOG(FATAL) << "Unexpected instruction: "
+ << inst->DumpString(shadow_frame.GetMethod()->GetDexFile());
+ UNREACHABLE();
}
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
- JValue* result, size_t arg_offset)
+static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
@@ -541,29 +539,28 @@
}
template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, uint16_t inst_data, JValue* result) {
// Compute method information.
- const DexFile::CodeItem* code_item = method->GetCodeItem();
+ const DexFile::CodeItem* code_item = called_method->GetCodeItem();
const uint16_t num_ins = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
uint16_t num_regs;
if (LIKELY(code_item != NULL)) {
num_regs = code_item->registers_size_;
DCHECK_EQ(num_ins, code_item->ins_size_);
} else {
- DCHECK(method->IsNative() || method->IsProxyMethod());
+ DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
num_regs = num_ins;
}
// Allocate shadow frame on the stack.
const char* old_cause = self->StartAssertNoThreadSuspension("DoCall");
void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
- ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
+ ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, called_method, 0,
+ memory));
// Initialize new shadow frame.
const size_t first_dest_reg = num_regs - num_ins;
- StackHandleScope<1> hs(self);
- MethodHelper mh(hs.NewHandle(method));
if (do_assignability_check) {
// Slow path.
// We might need to do class loading, which incurs a thread state change to kNative. So
@@ -573,11 +570,12 @@
// We need to do runtime check on reference assignment. We need to load the shorty
// to get the exact type of each reference argument.
- const DexFile::TypeList* params = mh.Get()->GetParameterTypeList();
+ const DexFile::TypeList* params = new_shadow_frame->GetMethod()->GetParameterTypeList();
uint32_t shorty_len = 0;
- const char* shorty = mh.Get()->GetShorty(&shorty_len);
+ const char* shorty = new_shadow_frame->GetMethod()->GetShorty(&shorty_len);
- // TODO: find a cleaner way to separate non-range and range information without duplicating code.
+ // TODO: find a cleaner way to separate non-range and range information without duplicating
+ // code.
uint32_t arg[5]; // only used in invoke-XXX.
uint32_t vregC; // only used in invoke-XXX-range.
if (is_range) {
@@ -589,7 +587,7 @@
// Handle receiver apart since it's not part of the shorty.
size_t dest_reg = first_dest_reg;
size_t arg_offset = 0;
- if (!mh.Get()->IsStatic()) {
+ if (!new_shadow_frame->GetMethod()->IsStatic()) {
size_t receiver_reg = is_range ? vregC : arg[0];
new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
++dest_reg;
@@ -602,7 +600,9 @@
case 'L': {
Object* o = shadow_frame.GetVRegReference(src_reg);
if (do_assignability_check && o != NULL) {
- Class* arg_type = mh.GetClassFromTypeIdx(params->GetTypeItem(shorty_pos).type_idx_);
+ Class* arg_type =
+ new_shadow_frame->GetMethod()->GetClassFromTypeIndex(
+ params->GetTypeItem(shorty_pos).type_idx_, true);
if (arg_type == NULL) {
CHECK(self->IsExceptionPending());
return false;
@@ -613,7 +613,7 @@
self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
"Ljava/lang/VirtualMachineError;",
"Invoking %s with bad arg %d, type '%s' not instance of '%s'",
- mh.Get()->GetName(), shorty_pos,
+ new_shadow_frame->GetMethod()->GetName(), shorty_pos,
o->GetClass()->GetDescriptor(&temp1),
arg_type->GetDescriptor(&temp2));
return false;
@@ -650,7 +650,8 @@
uint16_t regList = inst->Fetch16(2);
uint16_t count = num_ins;
if (count == 5) {
- AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U, (inst_data >> 8) & 0x0f);
+ AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U,
+ (inst_data >> 8) & 0x0f);
--count;
}
for (size_t arg_index = 0; arg_index < count; ++arg_index, regList >>= 4) {
@@ -662,17 +663,24 @@
// Do the call now.
if (LIKELY(Runtime::Current()->IsStarted())) {
- if (kIsDebugBuild && mh.Get()->GetEntryPointFromInterpreter() == nullptr) {
- LOG(FATAL) << "Attempt to invoke non-executable method: " << PrettyMethod(mh.Get());
+ if (kIsDebugBuild && new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter() == nullptr) {
+ LOG(FATAL) << "Attempt to invoke non-executable method: "
+ << PrettyMethod(new_shadow_frame->GetMethod());
+ UNREACHABLE();
}
if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
- !mh.Get()->IsNative() && !mh.Get()->IsProxyMethod() &&
- mh.Get()->GetEntryPointFromInterpreter() == artInterpreterToCompiledCodeBridge) {
- LOG(FATAL) << "Attempt to call compiled code when -Xint: " << PrettyMethod(mh.Get());
+ !new_shadow_frame->GetMethod()->IsNative() &&
+ !new_shadow_frame->GetMethod()->IsProxyMethod() &&
+ new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter()
+ == artInterpreterToCompiledCodeBridge) {
+ LOG(FATAL) << "Attempt to call compiled code when -Xint: "
+ << PrettyMethod(new_shadow_frame->GetMethod());
+ UNREACHABLE();
}
- (mh.Get()->GetEntryPointFromInterpreter())(self, &mh, code_item, new_shadow_frame, result);
+ (new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter())(self, code_item,
+ new_shadow_frame, result);
} else {
- UnstartedRuntimeInvoke(self, &mh, code_item, new_shadow_frame, result, first_dest_reg);
+ UnstartedRuntimeInvoke(self, code_item, new_shadow_frame, result, first_dest_reg);
}
return !self->IsExceptionPending();
}
@@ -813,8 +821,8 @@
result->SetL(found);
}
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
+static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
@@ -934,7 +942,7 @@
}
} else {
// Not special, continue with regular interpreter execution.
- artInterpreterToInterpreterBridge(self, mh, code_item, shadow_frame, result);
+ artInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
}
}
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index f88d56a..ce7c1c3 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -33,7 +33,6 @@
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
-#include "method_helper-inl.h"
#include "nth_caller_visitor.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method.h"
@@ -70,13 +69,11 @@
// External references to both interpreter implementations.
template<bool do_access_check, bool transaction_active>
-extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+extern JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template<bool do_access_check, bool transaction_active>
-extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+extern JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
void ThrowNullPointerExceptionFromInterpreter(const ShadowFrame& shadow_frame)
@@ -100,7 +97,7 @@
// DoInvokeVirtualQuick functions.
// Returns true on success, otherwise throws an exception and returns false.
template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, uint16_t inst_data, JValue* result);
// Handles invoke-XXX/range instructions.
@@ -112,19 +109,20 @@
const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
mirror::ArtMethod* sf_method = shadow_frame.GetMethod();
- ArtMethod* const method = FindMethodFromCode<type, do_access_check>(
+ ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>(
method_idx, &receiver, &sf_method, self);
// The shadow frame should already be pushed, so we don't need to update it.
- if (UNLIKELY(method == nullptr)) {
+ if (UNLIKELY(called_method == nullptr)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
return false;
- } else if (UNLIKELY(method->IsAbstract())) {
- ThrowAbstractMethodError(method);
+ } else if (UNLIKELY(called_method->IsAbstract())) {
+ ThrowAbstractMethodError(called_method);
result->SetJ(0);
return false;
} else {
- return DoCall<is_range, do_access_check>(method, self, shadow_frame, inst, inst_data, result);
+ return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
+ result);
}
}
@@ -144,18 +142,18 @@
}
const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
CHECK(receiver->GetClass()->ShouldHaveEmbeddedImtAndVTable());
- ArtMethod* const method = receiver->GetClass()->GetEmbeddedVTableEntry(vtable_idx);
- if (UNLIKELY(method == nullptr)) {
+ ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry(vtable_idx);
+ if (UNLIKELY(called_method == nullptr)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
return false;
- } else if (UNLIKELY(method->IsAbstract())) {
- ThrowAbstractMethodError(method);
+ } else if (UNLIKELY(called_method->IsAbstract())) {
+ ThrowAbstractMethodError(called_method);
result->SetJ(0);
return false;
} else {
// No need to check since we've been quickened.
- return DoCall<is_range, false>(method, self, shadow_frame, inst, inst_data, result);
+ return DoCall<is_range, false>(called_method, self, shadow_frame, inst, inst_data, result);
}
}
@@ -351,12 +349,12 @@
uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
+void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame)
__attribute__((cold, noreturn))
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
- const uint32_t dex_pc, MethodHelper& mh)
+ const uint32_t dex_pc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
constexpr bool kTracing = false;
if (kTracing) {
@@ -364,7 +362,7 @@
std::ostringstream oss;
oss << PrettyMethod(shadow_frame.GetMethod())
<< StringPrintf("\n0x%x: ", dex_pc)
- << inst->DumpString(mh.GetMethod()->GetDexFile()) << "\n";
+ << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n";
for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
uint32_t raw_value = shadow_frame.GetVReg(i);
Object* ref_value = shadow_frame.GetVRegReference(i);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 6350c56..c332a7b 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -26,7 +26,6 @@
// - "inst_data" : the current instruction's first 16 bits.
// - "dex_pc": the current pc.
// - "shadow_frame": the current shadow frame.
-// - "mh": the current MethodHelper.
// - "currentHandlersTable": the current table of pointer to each instruction handler.
// Advance to the next instruction and updates interpreter state.
@@ -36,7 +35,7 @@
inst = inst->RelativeAt(disp); \
dex_pc = static_cast<uint32_t>(static_cast<int32_t>(dex_pc) + disp); \
shadow_frame.SetDexPC(dex_pc); \
- TraceExecution(shadow_frame, inst, dex_pc, mh); \
+ TraceExecution(shadow_frame, inst, dex_pc); \
inst_data = inst->Fetch16(0); \
goto *currentHandlersTable[inst->Opcode(inst_data)]; \
} while (false)
@@ -59,6 +58,7 @@
do { \
if (kIsDebugBuild) { \
LOG(FATAL) << "We should not be here !"; \
+ UNREACHABLE(); \
} \
} while (false)
@@ -111,8 +111,8 @@
*
*/
template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register) {
+JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
+ JValue result_register) {
// Define handler tables:
// - The main handler table contains execution handlers for each instruction.
// - The alternative handler table contains prelude handlers which check for thread suspend and
@@ -2279,103 +2279,103 @@
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_3E)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_3F)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_40)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_41)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_42)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_43)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_79)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_7A)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_EF)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F0)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F1)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F2)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F3)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F4)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F5)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F6)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F7)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F8)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_F9)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FA)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FB)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FC)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FD)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FE)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(UNUSED_FF)
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
HANDLE_INSTRUCTION_END();
exception_pending_label: {
@@ -2430,21 +2430,17 @@
// Explicit definitions of ExecuteGotoImpl.
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
} // namespace interpreter
} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 1b6f53e..f9bbfa1 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -57,7 +57,7 @@
} while (false)
template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
bool do_assignability_check = do_access_check;
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
@@ -82,7 +82,7 @@
while (true) {
dex_pc = inst->GetDexPc(insns);
shadow_frame.SetDexPC(dex_pc);
- TraceExecution(shadow_frame, inst, dex_pc, mh);
+ TraceExecution(shadow_frame, inst, dex_pc);
inst_data = inst->Fetch16(0);
switch (inst->Opcode(inst_data)) {
case Instruction::NOP:
@@ -2140,27 +2140,23 @@
case Instruction::UNUSED_EF ... Instruction::UNUSED_FF:
case Instruction::UNUSED_79:
case Instruction::UNUSED_7A:
- UnexpectedOpcode(inst, mh);
+ UnexpectedOpcode(inst, shadow_frame);
}
}
} // NOLINT(readability/fn_size)
// Explicit definitions of ExecuteSwitchImpl.
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<true, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<false, false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteSwitchImpl<true, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteSwitchImpl<false, true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
} // namespace interpreter
diff --git a/runtime/method_helper-inl.h b/runtime/method_helper-inl.h
deleted file mode 100644
index 7a7949e..0000000
--- a/runtime/method_helper-inl.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_METHOD_HELPER_INL_H_
-#define ART_RUNTIME_METHOD_HELPER_INL_H_
-
-#include "method_helper.h"
-
-#include "class_linker.h"
-#include "mirror/object_array.h"
-#include "runtime.h"
-#include "thread-inl.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-template <template <class T2> class HandleKind2>
-inline bool MethodHelperT<HandleKind>::HasSameNameAndSignature(MethodHelperT<HandleKind2>* other) {
- const DexFile* dex_file = method_->GetDexFile();
- const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
- if (method_->GetDexCache() == other->method_->GetDexCache()) {
- const DexFile::MethodId& other_mid =
- dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
- return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
- }
- const DexFile* other_dex_file = other->method_->GetDexFile();
- const DexFile::MethodId& other_mid =
- other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
- if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) {
- return false; // Name mismatch.
- }
- return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
-}
-
-template <template <class T> class HandleKind>
-inline mirror::Class* MethodHelperT<HandleKind>::GetClassFromTypeIdx(uint16_t type_idx,
- bool resolve) {
- mirror::ArtMethod* method = GetMethod();
- mirror::Class* type = method->GetDexCacheResolvedType(type_idx);
- if (type == nullptr && resolve) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
- CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
- }
- return type;
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_METHOD_HELPER_INL_H_
diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc
deleted file mode 100644
index 81e1794..0000000
--- a/runtime/method_helper.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "method_helper-inl.h"
-
-#include "class_linker.h"
-#include "dex_file-inl.h"
-#include "handle_scope-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/dex_cache.h"
-#include "runtime.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-template <template <class T2> class HandleKind2>
-bool MethodHelperT<HandleKind>::HasSameSignatureWithDifferentClassLoaders(Thread* self,
- MethodHelperT<HandleKind2>* other) {
- {
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> return_type(hs.NewHandle(GetMethod()->GetReturnType()));
- if (UNLIKELY(other->GetMethod()->GetReturnType() != return_type.Get())) {
- return false;
- }
- }
- const DexFile::TypeList* types = method_->GetParameterTypeList();
- const DexFile::TypeList* other_types = other->method_->GetParameterTypeList();
- if (types == nullptr) {
- return (other_types == nullptr) || (other_types->Size() == 0);
- } else if (UNLIKELY(other_types == nullptr)) {
- return types->Size() == 0;
- }
- uint32_t num_types = types->Size();
- if (UNLIKELY(num_types != other_types->Size())) {
- return false;
- }
- for (uint32_t i = 0; i < num_types; ++i) {
- mirror::Class* param_type = GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
- mirror::Class* other_param_type =
- other->GetClassFromTypeIdx(other_types->GetTypeItem(i).type_idx_);
- if (UNLIKELY(param_type != other_param_type)) {
- return false;
- }
- }
- return true;
-}
-
-template <template <class T> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method = GetMethod();
- const DexFile* dexfile = method->GetDexFile();
- if (dexfile == &other_dexfile) {
- return method->GetDexMethodIndex();
- }
- const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex());
- const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
- const DexFile::StringId* other_descriptor =
- other_dexfile.FindStringId(mid_declaring_class_descriptor);
- if (other_descriptor != nullptr) {
- const DexFile::TypeId* other_type_id =
- other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
- if (other_type_id != nullptr) {
- const char* mid_name = dexfile->GetMethodName(mid);
- const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name);
- if (other_name != nullptr) {
- uint16_t other_return_type_idx;
- std::vector<uint16_t> other_param_type_idxs;
- bool success = other_dexfile.CreateTypeList(
- dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx,
- &other_param_type_idxs);
- if (success) {
- const DexFile::ProtoId* other_sig =
- other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs);
- if (other_sig != nullptr) {
- const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
- *other_type_id, *other_name, *other_sig);
- if (other_mid != nullptr) {
- return other_dexfile.GetIndexForMethodId(*other_mid);
- }
- }
- }
- }
- }
- }
- return DexFile::kDexNoIndex;
-}
-
-template <template <typename> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(
- const DexFile& other_dexfile, uint32_t name_and_signature_idx)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method = GetMethod();
- const DexFile* dexfile = method->GetDexFile();
- const uint32_t dex_method_idx = method->GetDexMethodIndex();
- const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
- const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
- DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
- DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
- if (dexfile == &other_dexfile) {
- return dex_method_idx;
- }
- const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
- const DexFile::StringId* other_descriptor =
- other_dexfile.FindStringId(mid_declaring_class_descriptor);
- if (other_descriptor != nullptr) {
- const DexFile::TypeId* other_type_id =
- other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
- if (other_type_id != nullptr) {
- const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
- *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
- other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
- if (other_mid != nullptr) {
- return other_dexfile.GetIndexForMethodId(*other_mid);
- }
- }
- }
- return DexFile::kDexNoIndex;
-}
-
-// Instantiate methods.
-template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
- const DexFile& other_dexfile);
-
-template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
- uint32_t name_and_signature_idx);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
- const DexFile& other_dexfile, uint32_t name_and_signature_idx);
-
-template
-bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<Handle>(Thread* self,
- MethodHelperT<Handle>* other);
-
-template
-bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(Thread* self,
- MethodHelperT<MutableHandle>* other);
-
-template
-bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<Handle>(Thread* self,
- MethodHelperT<Handle>* other);
-
-template
-bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(
- Thread* self, MethodHelperT<MutableHandle>* other);
-
-} // namespace art
diff --git a/runtime/method_helper.h b/runtime/method_helper.h
deleted file mode 100644
index dc305d5..0000000
--- a/runtime/method_helper.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_METHOD_HELPER_H_
-#define ART_RUNTIME_METHOD_HELPER_H_
-
-#include "base/macros.h"
-#include "handle.h"
-#include "mirror/art_method.h"
-#include "primitive.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-class MethodHelperT {
- public:
- explicit MethodHelperT(HandleKind<mirror::ArtMethod> m)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : method_(m), shorty_(nullptr), shorty_len_(0) {
- }
-
- mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return method_->GetInterfaceMethodIfProxy();
- }
-
- // GetMethod() != Get() for proxy methods.
- mirror::ArtMethod* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return method_.Get();
- }
-
- const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const char* result = shorty_;
- if (result == nullptr) {
- result = method_->GetShorty(&shorty_len_);
- shorty_ = result;
- }
- return result;
- }
-
- uint32_t GetShortyLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (shorty_ == nullptr) {
- GetShorty();
- }
- return shorty_len_;
- }
-
- // Counts the number of references in the parameter list of the corresponding method.
- // Note: Thus does _not_ include "this" for non-static methods.
- uint32_t GetNumberOfReferenceArgsWithoutReceiver() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const char* shorty = GetShorty();
- uint32_t refs = 0;
- for (uint32_t i = 1; i < shorty_len_ ; ++i) {
- if (shorty[i] == 'L') {
- refs++;
- }
- }
-
- return refs;
- }
-
- size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // "1 +" because the first in Args is the receiver.
- // "- 1" because we don't count the return type.
- return (method_->IsStatic() ? 0 : 1) + GetShortyLength() - 1;
- }
-
- // Get the primitive type associated with the given parameter.
- Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK_LT(param, NumArgs());
- if (GetMethod()->IsStatic()) {
- param++; // 0th argument must skip return value at start of the shorty
- } else if (param == 0) {
- return Primitive::kPrimNot;
- }
- return Primitive::GetType(GetShorty()[param]);
- }
-
- // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods.
- bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Primitive::Type type = GetParamPrimitiveType(param);
- return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
- }
-
- // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods.
- bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return GetParamPrimitiveType(param) == Primitive::kPrimNot;
- }
-
- template <template <class T> class HandleKind2>
- ALWAYS_INLINE bool HasSameNameAndSignature(MethodHelperT<HandleKind2>* other)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- template <template <class T> class HandleKind2>
- bool HasSameSignatureWithDifferentClassLoaders(Thread* self, MethodHelperT<HandleKind2>* other)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the
- // other_dexfile, such as the method index used to resolve this method in the other_dexfile.
- uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
- uint32_t name_and_signature_idx)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- protected:
- HandleKind<mirror::ArtMethod> method_;
-
- const char* shorty_;
- uint32_t shorty_len_;
-
- private:
- template <template <class T2> class HandleKind2> friend class MethodHelperT;
-
- DISALLOW_COPY_AND_ASSIGN(MethodHelperT);
-};
-
-class MethodHelper : public MethodHelperT<Handle> {
- using MethodHelperT<Handle>::MethodHelperT;
- private:
- DISALLOW_COPY_AND_ASSIGN(MethodHelper);
-};
-
-class MutableMethodHelper : public MethodHelperT<MutableHandle> {
- using MethodHelperT<MutableHandle>::MethodHelperT;
- public:
- void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(new_m != nullptr);
- SetMethod(new_m);
- shorty_ = nullptr;
- }
-
- private:
- // Set the method_ field, for proxy methods looking up the interface method via the resolved
- // methods table.
- void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- method_.Assign(method);
- }
-
- DISALLOW_COPY_AND_ASSIGN(MutableMethodHelper);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_METHOD_HELPER_H_
diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h
index 03425cc..2b406bd 100644
--- a/runtime/mirror/art_field-inl.h
+++ b/runtime/mirror/art_field-inl.h
@@ -20,6 +20,7 @@
#include "art_field.h"
#include "base/logging.h"
+#include "class_linker.h"
#include "dex_cache.h"
#include "gc/accounting/card_table-inl.h"
#include "jvalue.h"
@@ -289,6 +290,22 @@
return GetTypeAsPrimitiveType() != Primitive::kPrimNot;
}
+inline Class* ArtField::GetType(bool resolve) {
+ uint32_t field_index = GetDexFieldIndex();
+ if (UNLIKELY(GetDeclaringClass()->IsProxyClass())) {
+ return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
+ GetTypeDescriptor());
+ }
+ const DexFile* dex_file = GetDexFile();
+ const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
+ mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
+ if (resolve && (type == nullptr)) {
+ type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, this);
+ CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
+ }
+ return type;
+}
+
inline size_t ArtField::FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return Primitive::ComponentSize(GetTypeAsPrimitiveType());
}
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 50299b6..a1d8844 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -161,6 +161,8 @@
bool IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ Class* GetType(bool resolve) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
size_t FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 22d55e2..c29276a 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -24,7 +24,6 @@
#include "class_linker.h"
#include "dex_cache.h"
#include "dex_file.h"
-#include "method_helper.h"
#include "object-inl.h"
#include "object_array.h"
#include "oat.h"
@@ -141,6 +140,15 @@
return GetDexCacheResolvedTypes() == other->GetDexCacheResolvedTypes();
}
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx, bool resolve) {
+ mirror::Class* type = GetDexCacheResolvedType(type_idx);
+ if (type == nullptr && resolve) {
+ type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
+ CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
+ }
+ return type;
+}
+
inline uint32_t ArtMethod::GetCodeSize() {
DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
const void* code = EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode());
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 4f5ca3f..1729686 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -29,7 +29,6 @@
#include "interpreter/interpreter.h"
#include "jni_internal.h"
#include "mapping_table.h"
-#include "method_helper-inl.h"
#include "object_array-inl.h"
#include "object_array.h"
#include "object-inl.h"
@@ -93,7 +92,7 @@
void ArtMethod::SetClass(Class* java_lang_reflect_ArtMethod) {
CHECK(java_lang_reflect_ArtMethod_.IsNull());
- CHECK(java_lang_reflect_ArtMethod != NULL);
+ CHECK(java_lang_reflect_ArtMethod != nullptr);
java_lang_reflect_ArtMethod_ = GcRoot<Class>(java_lang_reflect_ArtMethod);
}
@@ -116,14 +115,31 @@
return num_registers;
}
+static bool HasSameNameAndSignature(ArtMethod* method1, ArtMethod* method2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature");
+ const DexFile* dex_file = method1->GetDexFile();
+ const DexFile::MethodId& mid = dex_file->GetMethodId(method1->GetDexMethodIndex());
+ if (method1->GetDexCache() == method2->GetDexCache()) {
+ const DexFile::MethodId& mid2 = dex_file->GetMethodId(method2->GetDexMethodIndex());
+ return mid.name_idx_ == mid2.name_idx_ && mid.proto_idx_ == mid2.proto_idx_;
+ }
+ const DexFile* dex_file2 = method2->GetDexFile();
+ const DexFile::MethodId& mid2 = dex_file2->GetMethodId(method2->GetDexMethodIndex());
+ if (!DexFileStringEquals(dex_file, mid.name_idx_, dex_file2, mid2.name_idx_)) {
+ return false; // Name mismatch.
+ }
+ return dex_file->GetMethodSignature(mid) == dex_file2->GetMethodSignature(mid2);
+}
+
ArtMethod* ArtMethod::FindOverriddenMethod() {
if (IsStatic()) {
- return NULL;
+ return nullptr;
}
Class* declaring_class = GetDeclaringClass();
Class* super_class = declaring_class->GetSuperClass();
uint16_t method_index = GetMethodIndex();
- ArtMethod* result = NULL;
+ ArtMethod* result = nullptr;
// Did this method override a super class method? If so load the result from the super class'
// vtable
if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) {
@@ -135,16 +151,13 @@
CHECK_EQ(result,
Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
} else {
- StackHandleScope<2> hs(Thread::Current());
- MethodHelper mh(hs.NewHandle(this));
- MutableMethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
IfTable* iftable = GetDeclaringClass()->GetIfTable();
- for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
+ for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) {
Class* interface = iftable->GetInterface(i);
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
- interface_mh.ChangeMethod(interface->GetVirtualMethod(j));
- if (mh.HasSameNameAndSignature(&interface_mh)) {
- result = interface_mh.GetMethod();
+ mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j);
+ if (HasSameNameAndSignature(this, interface_method)) {
+ result = interface_method;
break;
}
}
@@ -152,14 +165,40 @@
}
}
if (kIsDebugBuild) {
- StackHandleScope<2> hs(Thread::Current());
- MethodHelper result_mh(hs.NewHandle(result));
- MethodHelper this_mh(hs.NewHandle(this));
- DCHECK(result == nullptr || this_mh.HasSameNameAndSignature(&result_mh));
+ DCHECK(result == nullptr || HasSameNameAndSignature(this, result));
}
return result;
}
+uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+ uint32_t name_and_signature_idx) {
+ const DexFile* dexfile = GetDexFile();
+ const uint32_t dex_method_idx = GetDexMethodIndex();
+ const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
+ const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
+ DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
+ DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
+ if (dexfile == &other_dexfile) {
+ return dex_method_idx;
+ }
+ const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
+ const DexFile::StringId* other_descriptor =
+ other_dexfile.FindStringId(mid_declaring_class_descriptor);
+ if (other_descriptor != nullptr) {
+ const DexFile::TypeId* other_type_id =
+ other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
+ if (other_type_id != nullptr) {
+ const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
+ *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
+ other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
+ if (other_mid != nullptr) {
+ return other_dexfile.GetIndexForMethodId(*other_mid);
+ }
+ }
+ }
+ return DexFile::kDexNoIndex;
+}
+
uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
if (IsPortableCompiled()) {
// Portable doesn't use the machine pc, we just use dex pc instead.
@@ -228,7 +267,6 @@
uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
uint32_t dex_pc, bool* has_no_move_exception) {
- MethodHelper mh(h_this);
const DexFile::CodeItem* code_item = h_this->GetCodeItem();
// Set aside the exception while we resolve its type.
Thread* self = Thread::Current();
@@ -248,7 +286,7 @@
break;
}
// Does this catch exception type apply?
- Class* iter_exception_type = mh.GetClassFromTypeIdx(iter_type_idx);
+ Class* iter_exception_type = h_this->GetClassFromTypeIndex(iter_type_idx, true);
if (UNLIKELY(iter_exception_type == nullptr)) {
// Now have a NoClassDefFoundError as exception. Ignore in case the exception class was
// removed by a pro-guard like tool.
@@ -420,7 +458,7 @@
}
} else {
LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";
- if (result != NULL) {
+ if (result != nullptr) {
result->SetJ(0);
}
}
@@ -430,6 +468,21 @@
self->PopManagedStackFragment(fragment);
}
+// Counts the number of references in the parameter list of the corresponding method.
+// Note: Thus does _not_ include "this" for non-static methods.
+static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t shorty_len;
+ const char* shorty = method->GetShorty(&shorty_len);
+ uint32_t refs = 0;
+ for (uint32_t i = 1; i < shorty_len ; ++i) {
+ if (shorty[i] == 'L') {
+ refs++;
+ }
+ }
+ return refs;
+}
+
QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
if (UNLIKELY(IsPortableCompiled())) {
// Portable compiled dex bytecode or jni stub.
@@ -472,8 +525,7 @@
// Generic JNI frame.
DCHECK(IsNative());
StackHandleScope<1> hs(Thread::Current());
- uint32_t handle_refs =
- MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
+ uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(this) + 1;
size_t scope_size = HandleScope::SizeOf(handle_refs);
QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
@@ -493,7 +545,7 @@
void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
CHECK(IsNative()) << PrettyMethod(this);
CHECK(!IsFastNative()) << PrettyMethod(this);
- CHECK(native_method != NULL) << PrettyMethod(this);
+ CHECK(native_method != nullptr) << PrettyMethod(this);
if (is_fast) {
SetAccessFlags(GetAccessFlags() | kAccFastNative);
}
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index da494e0..2107944 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -32,15 +32,14 @@
struct ArtMethodOffsets;
struct ConstructorMethodOffsets;
union JValue;
-class MethodHelper;
class ScopedObjectAccessAlreadyRunnable;
class StringPiece;
class ShadowFrame;
namespace mirror {
-typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper* mh,
- const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
+typedef void (EntryPointFromInterpreter)(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
#define ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
@@ -238,9 +237,21 @@
bool HasSameDexCacheResolvedTypes(ObjectArray<Class>* other_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Find the method that this method overrides
+ // Get the Class* from the type index into this method's dex cache.
+ mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Find the method that this method overrides.
ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Find the method index for this method within other_dexfile. If this method isn't present then
+ // return DexFile::kDexNoIndex. The name_and_signature_idx MUST refer to a MethodId with the same
+ // name and signature in the other_dexfile, such as the method index used to resolve this method
+ // in the other_dexfile.
+ uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+ uint32_t name_and_signature_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 599f178..1662ebf 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -575,6 +575,10 @@
allocator_type, VoidFunctor());
if (add_finalizer && LIKELY(obj != nullptr)) {
heap->AddFinalizerReference(self, &obj);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ // Failed to allocate finalizer reference, it means that the whole allocation failed.
+ obj = nullptr;
+ }
}
return obj;
}
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index fa1f226..65d6ade 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -24,7 +24,6 @@
#include "class.h"
#include "class-inl.h"
#include "class_linker-inl.h"
-#include "field_helper.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
#include "iftable-inl.h"
@@ -202,12 +201,16 @@
if (fields != NULL) {
size_t num_ifields = fields->GetLength();
for (size_t i = 0; i < num_ifields; ++i) {
+ StackHandleScope<1> hs(Thread::Current());
+ Handle<Object> h_object(hs.NewHandle(new_value));
ArtField* field = fields->Get(i);
if (field->GetOffset().Int32Value() == field_offset.Int32Value()) {
CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
- StackHandleScope<1> hs(Thread::Current());
- FieldHelper fh(hs.NewHandle(field));
- CHECK(fh.GetType()->IsAssignableFrom(new_value->GetClass()));
+ // TODO: resolve the field type for moving GC.
+ mirror::Class* field_type = field->GetType(!kMovingCollector);
+ if (field_type != nullptr) {
+ CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
+ }
return;
}
}
@@ -225,9 +228,11 @@
ArtField* field = fields->Get(i);
if (field->GetOffset().Int32Value() == field_offset.Int32Value()) {
CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
- StackHandleScope<1> hs(Thread::Current());
- FieldHelper fh(hs.NewHandle(field));
- CHECK(fh.GetType()->IsAssignableFrom(new_value->GetClass()));
+ // TODO: resolve the field type for moving GC.
+ mirror::Class* field_type = field->GetType(!kMovingCollector);
+ if (field_type != nullptr) {
+ CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
+ }
return;
}
}
@@ -235,6 +240,7 @@
}
LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this)
<< " of type " << PrettyDescriptor(c) << " at offset " << field_offset;
+ UNREACHABLE();
}
} // namespace mirror
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 4402031..9d789cd 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -34,7 +34,6 @@
#include "gc/heap.h"
#include "handle_scope-inl.h"
#include "iftable-inl.h"
-#include "method_helper-inl.h"
#include "object-inl.h"
#include "object_array-inl.h"
#include "scoped_thread_state_change.h"
@@ -528,26 +527,6 @@
EXPECT_STREQ(m3_2->GetName(), "m3");
ArtMethod* m4_2 = klass2->GetVirtualMethod(3);
EXPECT_STREQ(m4_2->GetName(), "m4");
-
- MutableMethodHelper mh(hs.NewHandle(m1_1));
- MutableMethodHelper mh2(hs.NewHandle(m1_2));
- EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
- EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
- mh.ChangeMethod(m2_1);
- mh2.ChangeMethod(m2_2);
- EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
- EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
- mh.ChangeMethod(m3_1);
- mh2.ChangeMethod(m3_2);
- EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
- EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
- mh.ChangeMethod(m4_1);
- mh2.ChangeMethod(m4_2);
- EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
- EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
}
TEST_F(ObjectTest, StringHashCode) {
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index a042620..2cebf02 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -20,7 +20,6 @@
#include "class_linker-inl.h"
#include "common_throws.h"
#include "dex_file-inl.h"
-#include "field_helper.h"
#include "jni_internal.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -294,9 +293,8 @@
StackHandleScope<2> hs(soa.Self());
HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o));
HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
- FieldHelper fh(h_f);
// May cause resolution.
- field_type = fh.GetType(true);
+ field_type = h_f->GetType(true);
if (field_type == nullptr) {
DCHECK(soa.Self()->IsExceptionPending());
return;
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index ffadfc6..1775468 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -28,10 +28,8 @@
static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
ScopedObjectAccess soa(env);
- StackHandleScope<1> scope(soa.Self());
mirror::ArtMethod* m = soa.DecodeMethod(mid);
- MethodHelper mh(scope.NewHandle(m));
- return mh.GetShorty();
+ return m->GetShorty();
}
static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 1eded62..3260992 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -18,7 +18,6 @@
#include <vector>
#include "common_compiler_test.h"
-#include "field_helper.h"
#include "mirror/art_field-inl.h"
#include "scoped_thread_state_change.h"
@@ -184,21 +183,20 @@
// Test "Class[] interfaces" field.
MutableHandle<mirror::ArtField> fhandle = hs.NewHandle(static_fields->Get(0));
- FieldHelper fh(fhandle);
- EXPECT_EQ("interfaces", std::string(fh.GetField()->GetName()));
- EXPECT_EQ("[Ljava/lang/Class;", std::string(fh.GetField()->GetTypeDescriptor()));
- EXPECT_EQ(interfacesFieldClass.Get(), fh.GetType());
- EXPECT_EQ("L$Proxy1234;", std::string(fh.GetDeclaringClassDescriptor()));
- EXPECT_FALSE(fh.GetField()->IsPrimitiveType());
+ EXPECT_EQ("interfaces", std::string(fhandle->GetName()));
+ EXPECT_EQ("[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor()));
+ EXPECT_EQ(interfacesFieldClass.Get(), fhandle->GetType(true));
+ std::string temp;
+ EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp)));
+ EXPECT_FALSE(fhandle->IsPrimitiveType());
// Test "Class[][] throws" field.
fhandle.Assign(static_fields->Get(1));
- FieldHelper fh2(fhandle);
- EXPECT_EQ("throws", std::string(fh2.GetField()->GetName()));
- EXPECT_EQ("[[Ljava/lang/Class;", std::string(fh2.GetField()->GetTypeDescriptor()));
- EXPECT_EQ(throwsFieldClass.Get(), fh2.GetType());
- EXPECT_EQ("L$Proxy1234;", std::string(fh2.GetDeclaringClassDescriptor()));
- EXPECT_FALSE(fh2.GetField()->IsPrimitiveType());
+ EXPECT_EQ("throws", std::string(fhandle->GetName()));
+ EXPECT_EQ("[[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor()));
+ EXPECT_EQ(throwsFieldClass.Get(), fhandle->GetType(true));
+ EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp)));
+ EXPECT_FALSE(fhandle->IsPrimitiveType());
}
} // namespace art
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 44d1bc4..85f9938 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -21,7 +21,6 @@
#include "dex_file-inl.h"
#include "entrypoints/entrypoint_utils.h"
#include "jni_internal.h"
-#include "method_helper-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
@@ -220,9 +219,10 @@
}
bool BuildArgArrayFromObjectArray(mirror::Object* receiver,
- mirror::ObjectArray<mirror::Object>* args, MethodHelper& mh)
+ mirror::ObjectArray<mirror::Object>* args,
+ Handle<mirror::ArtMethod> h_m)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const DexFile::TypeList* classes = mh.GetMethod()->GetParameterTypeList();
+ const DexFile::TypeList* classes = h_m->GetParameterTypeList();
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
Append(receiver);
@@ -231,11 +231,11 @@
mirror::Object* arg = args->Get(args_offset);
if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
mirror::Class* dst_class =
- mh.GetClassFromTypeIdx(classes->GetTypeItem(args_offset).type_idx_);
+ h_m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_, true);
if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
ThrowIllegalArgumentException(nullptr,
StringPrintf("method %s argument %zd has type %s, got %s",
- PrettyMethod(mh.GetMethod(), false).c_str(),
+ PrettyMethod(h_m.Get(), false).c_str(),
args_offset + 1, // Humans don't count from 0.
PrettyDescriptor(dst_class).c_str(),
PrettyTypeOf(arg).c_str()).c_str());
@@ -263,7 +263,7 @@
} else { \
ThrowIllegalArgumentException(nullptr, \
StringPrintf("method %s argument %zd has type %s, got %s", \
- PrettyMethod(mh.GetMethod(), false).c_str(), \
+ PrettyMethod(h_m.Get(), false).c_str(), \
args_offset + 1, \
expected, \
PrettyTypeOf(arg).c_str()).c_str()); \
@@ -329,6 +329,7 @@
#ifndef NDEBUG
default:
LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+ UNREACHABLE();
#endif
}
#undef DO_FIRST_ARG
@@ -360,14 +361,13 @@
if (!m->IsStatic()) {
offset = 1;
}
- // TODO: If args contain object references, it may cause problems
+ // TODO: If args contain object references, it may cause problems.
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
- MethodHelper mh(h_m);
for (uint32_t i = 0; i < num_params; i++) {
uint16_t type_idx = params->GetTypeItem(i).type_idx_;
- mirror::Class* param_type = mh.GetClassFromTypeIdx(type_idx);
+ mirror::Class* param_type = h_m->GetClassFromTypeIndex(type_idx, true);
if (param_type == nullptr) {
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
@@ -528,7 +528,7 @@
}
void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
- MethodHelper* mh, JValue* result) {
+ JValue* result) {
// We want to make sure that the stack is not within a small distance from the
// protected region in case we are calling into a leaf function whose stack
// check has been elided.
@@ -536,11 +536,12 @@
ThrowStackOverflowError(self);
return;
}
-
- ArgArray arg_array(mh->GetShorty(), mh->GetShortyLength());
+ uint32_t shorty_len;
+ const char* shorty = shadow_frame->GetMethod()->GetShorty(&shorty_len);
+ ArgArray arg_array(shorty, shorty_len);
arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
shadow_frame->GetMethod()->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
- mh->GetShorty());
+ shorty);
}
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
@@ -571,7 +572,7 @@
// Check that the receiver is non-null and an instance of the field's declaring class.
receiver = soa.Decode<mirror::Object*>(javaReceiver);
if (!VerifyObjectIsClass(receiver, declaring_class)) {
- return NULL;
+ return nullptr;
}
// Find the actual implementation of the virtual method.
@@ -585,10 +586,10 @@
uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
if (arg_count != classes_size) {
- ThrowIllegalArgumentException(NULL,
+ ThrowIllegalArgumentException(nullptr,
StringPrintf("Wrong number of arguments; expected %d, got %d",
classes_size, arg_count).c_str());
- return NULL;
+ return nullptr;
}
// If method is not set to be accessible, verify it can be accessed by the caller.
@@ -611,8 +612,8 @@
const char* shorty = m->GetShorty(&shorty_len);
ArgArray arg_array(shorty, shorty_len);
StackHandleScope<1> hs(soa.Self());
- MethodHelper mh(hs.NewHandle(m));
- if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, mh)) {
+ Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
+ if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, h_m)) {
CHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
@@ -627,22 +628,21 @@
jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th);
soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance));
- return NULL;
+ return nullptr;
}
// Box if necessary and return.
- return soa.AddLocalReference<jobject>(
- BoxPrimitive(Primitive::GetType(mh.GetMethod()->GetReturnTypeDescriptor()[0]), result));
+ return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
}
bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
- if (o == NULL) {
- ThrowNullPointerException(NULL, "null receiver");
+ if (o == nullptr) {
+ ThrowNullPointerException(nullptr, "null receiver");
return false;
} else if (!o->InstanceOf(c)) {
std::string expected_class_name(PrettyDescriptor(c));
std::string actual_class_name(PrettyTypeOf(o));
- ThrowIllegalArgumentException(NULL,
+ ThrowIllegalArgumentException(nullptr,
StringPrintf("Expected receiver of type %s, but got %s",
expected_class_name.c_str(),
actual_class_name.c_str()).c_str());
diff --git a/runtime/reflection.h b/runtime/reflection.h
index f9a7951..1a64871 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -29,7 +29,6 @@
class Object;
} // namespace mirror
union JValue;
-class MethodHelper;
class ScopedObjectAccessAlreadyRunnable;
class ShadowFrame;
class ThrowLocation;
@@ -65,7 +64,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
- MethodHelper* mh, JValue* result)
+ JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index e30e745..7aed8b0 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -69,7 +69,12 @@
// Cannot use this code to change into Runnable as changing to Runnable should fail if
// old_state_and_flags.suspend_request is true.
DCHECK_NE(new_state, kRunnable);
- DCHECK_EQ(this, Thread::Current());
+ if (kIsDebugBuild && this != Thread::Current()) {
+ std::string name;
+ GetThreadName(name);
+ LOG(FATAL) << "Thread \"" << name << "\"(" << this << " != Thread::Current()="
+ << Thread::Current() << ") changing state to " << new_state;
+ }
union StateAndFlags old_state_and_flags;
old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
tls32_.state_and_flags.as_struct.state = new_state;
diff --git a/runtime/thread.h b/runtime/thread.h
index b69d2f4..5b3e746 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1189,7 +1189,7 @@
private:
Thread* const self_;
- const char* old_cause_;
+ const char* const old_cause_;
};
std::ostream& operator<<(std::ostream& os, const Thread& thread);
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 5ff90d6..beafcda 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -168,7 +168,9 @@
const uint32_t kWaitTimeoutMs = 10000;
bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kWaitTimeoutMs);
if (timed_out) {
- LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during dump checkpoint.";
+ // Avoid a recursive abort.
+ LOG((kIsDebugBuild && (gAborting == 0)) ? FATAL : ERROR)
+ << "Unexpected time out during dump checkpoint.";
}
}
diff --git a/runtime/utils.cc b/runtime/utils.cc
index ad46be6..1211547 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -28,7 +28,6 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "dex_file-inl.h"
-#include "field_helper.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
@@ -324,8 +323,8 @@
result += PrettyDescriptor(f->GetTypeDescriptor());
result += ' ';
}
- StackHandleScope<1> hs(Thread::Current());
- result += PrettyDescriptor(FieldHelper(hs.NewHandle(f)).GetDeclaringClassDescriptor());
+ std::string temp;
+ result += PrettyDescriptor(f->GetDeclaringClass()->GetDescriptor(&temp));
result += '.';
result += f->GetName();
return result;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index a10c7cb..1b3cc8f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -25,12 +25,10 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex_instruction_visitor.h"
-#include "field_helper.h"
#include "gc/accounting/card_table-inl.h"
#include "indenter.h"
#include "intern_table.h"
#include "leb128.h"
-#include "method_helper-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class.h"
@@ -3827,7 +3825,7 @@
{
StackHandleScope<1> hs(self_);
HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
- field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
+ field_type_class = h_field->GetType(can_load_classes_);
}
if (field_type_class != nullptr) {
field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
@@ -3951,7 +3949,7 @@
{
StackHandleScope<1> hs(Thread::Current());
HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
- field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
+ field_type_class = h_field->GetType(can_load_classes_);
}
if (field_type_class != nullptr) {
diff --git a/test/080-oom-throw-with-finalizer/expected.txt b/test/080-oom-throw-with-finalizer/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/expected.txt
diff --git a/test/080-oom-throw-with-finalizer/info.txt b/test/080-oom-throw-with-finalizer/info.txt
new file mode 100644
index 0000000..37091ef
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/info.txt
@@ -0,0 +1 @@
+Regression test on correct processing of OOM thrown while adding a finalizer reference.
diff --git a/test/080-oom-throw-with-finalizer/src/Main.java b/test/080-oom-throw-with-finalizer/src/Main.java
new file mode 100644
index 0000000..57e9721
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/src/Main.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Vector;
+
+public class Main {
+ static char [][] holder;
+
+ static class ArrayMemEater {
+ static boolean sawOome;
+
+ static void blowup(char[][] holder) {
+ try {
+ for (int i = 0; i < holder.length; ++i) {
+ holder[i] = new char[1024 * 1024];
+ }
+ } catch (OutOfMemoryError oome) {
+ ArrayMemEater.sawOome = true;
+ }
+ }
+ }
+
+ static class InstanceFinalizerMemEater {
+ public void finalize() {}
+ }
+
+ static boolean triggerArrayOOM(char[][] holder) {
+ ArrayMemEater.blowup(holder);
+ return ArrayMemEater.sawOome;
+ }
+
+ static boolean triggerInstanceFinalizerOOM() {
+ boolean sawOome = false;
+ try {
+ Vector v = new Vector();
+ while (true) {
+ v.add(new InstanceFinalizerMemEater());
+ }
+ } catch (OutOfMemoryError e) {
+ sawOome = true;
+ }
+ return sawOome;
+ }
+
+ public static void main(String[] args) {
+ // Keep holder alive to make instance OOM happen faster.
+ holder = new char[128 * 1024][];
+ if (!triggerArrayOOM(holder)) {
+ System.out.println("NEW_ARRAY did not throw OOME");
+ }
+
+ if (!triggerInstanceFinalizerOOM()) {
+ System.out.println("NEW_INSTANCE (finalize) did not throw OOME");
+ }
+
+ System.runFinalization();
+ }
+}
diff --git a/test/421-large-frame/src/Main.java b/test/421-large-frame/src/Main.java
index 01b89ba..dae72fb 100644
--- a/test/421-large-frame/src/Main.java
+++ b/test/421-large-frame/src/Main.java
@@ -2029,6 +2029,11 @@
l997 += l996;
l998 += l997;
l999 += l998;
- return l999;
+ // Create a branch to beat the large method check.
+ if (l998 == l999) {
+ return l998;
+ } else {
+ return l999;
+ }
}
}
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index c434db3..e7dbe24 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -91,6 +91,9 @@
// Generate, compile and check long-to-double Dex instructions.
longToDouble();
+ // Generate, compile and check float-to-int Dex instructions.
+ floatToInt();
+
// Generate, compile and check int-to-byte Dex instructions.
shortToByte();
intToByte();
@@ -313,6 +316,32 @@
assertDoubleEquals(-9223372036854775808D, $opt$LongToDouble(-9223372036854775808L)); // -(2^63)
}
+ private static void floatToInt() {
+ assertIntEquals(1, $opt$FloatToInt(1F));
+ assertIntEquals(0, $opt$FloatToInt(0F));
+ assertIntEquals(0, $opt$FloatToInt(-0F));
+ assertIntEquals(-1, $opt$FloatToInt(-1F));
+ assertIntEquals(51, $opt$FloatToInt(51F));
+ assertIntEquals(-51, $opt$FloatToInt(-51F));
+ assertIntEquals(0, $opt$FloatToInt(0.5F));
+ assertIntEquals(0, $opt$FloatToInt(0.4999999F));
+ assertIntEquals(0, $opt$FloatToInt(-0.4999999F));
+ assertIntEquals(0, $opt$FloatToInt(-0.5F));
+ assertIntEquals(42, $opt$FloatToInt(42.199F));
+ assertIntEquals(-42, $opt$FloatToInt(-42.199F));
+ assertIntEquals(2147483647, $opt$FloatToInt(2147483647F)); // 2^31 - 1
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483647F)); // -(2^31 - 1)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483648F)); // -(2^31)
+ assertIntEquals(2147483647, $opt$FloatToInt(2147483648F)); // (2^31)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-2147483649F)); // -(2^31 + 1)
+ assertIntEquals(2147483647, $opt$FloatToInt(9223372036854775807F)); // 2^63 - 1
+ assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775807F)); // -(2^63 - 1)
+ assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775808F)); // -(2^63)
+ assertIntEquals(0, $opt$FloatToInt(Float.NaN));
+ assertIntEquals(2147483647, $opt$FloatToInt(Float.POSITIVE_INFINITY));
+ assertIntEquals(-2147483648, $opt$FloatToInt(Float.NEGATIVE_INFINITY));
+ }
+
private static void shortToByte() {
assertByteEquals((byte)1, $opt$ShortToByte((short)1));
assertByteEquals((byte)0, $opt$ShortToByte((short)0));
@@ -468,6 +497,9 @@
// This method produces a long-to-double Dex instruction.
static double $opt$LongToDouble(long a){ return (double)a; }
+ // This method produces a float-to-int Dex instruction.
+ static int $opt$FloatToInt(float a){ return (int)a; }
+
// These methods produce int-to-byte Dex instructions.
static byte $opt$ShortToByte(short a){ return (byte)a; }
static byte $opt$IntToByte(int a){ return (byte)a; }
diff --git a/test/434-invoke-direct/expected.txt b/test/434-invoke-direct/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/434-invoke-direct/expected.txt
diff --git a/test/434-invoke-direct/info.txt b/test/434-invoke-direct/info.txt
new file mode 100644
index 0000000..eae1ef0
--- /dev/null
+++ b/test/434-invoke-direct/info.txt
@@ -0,0 +1,2 @@
+Tests that IllegalAccessError is thrown when a subclass invokes-direct a
+private method from the super class.
diff --git a/test/434-invoke-direct/smali/invoke.smali b/test/434-invoke-direct/smali/invoke.smali
new file mode 100644
index 0000000..b3cdd1e
--- /dev/null
+++ b/test/434-invoke-direct/smali/invoke.smali
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LInvokeDirect;
+.super LInvokeDirectSuper;
+
+.method public constructor <init>()V
+ .registers 2
+ invoke-direct {v1}, LInvokeDirectSuper;-><init>()V
+ return-void
+.end method
+
+.method public run()I
+ .registers 3
+ invoke-super {v2}, LInvokeDirectSuper;->privateMethod()I
+ move-result v0
+ return v0
+.end method
diff --git a/test/434-invoke-direct/src/InvokeDirectSuper.java b/test/434-invoke-direct/src/InvokeDirectSuper.java
new file mode 100644
index 0000000..c80a18b
--- /dev/null
+++ b/test/434-invoke-direct/src/InvokeDirectSuper.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class InvokeDirectSuper {
+ public int val;
+
+ private int privateMethod() {
+ return val;
+ }
+}
diff --git a/test/434-invoke-direct/src/Main.java b/test/434-invoke-direct/src/Main.java
new file mode 100644
index 0000000..c363e1a
--- /dev/null
+++ b/test/434-invoke-direct/src/Main.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+
+ public static void main(String[] args) throws Throwable {
+ $opt$InvokeDirect();
+ }
+
+ private static void $opt$InvokeDirect() throws Throwable {
+ try {
+ Class<?> c = Class.forName("InvokeDirect");
+ Method m = c.getMethod("run");
+ m.invoke(c.newInstance());
+ throw new RuntimeException("Failed to throw IllegalAccessError");
+ } catch (InvocationTargetException e) {
+ if (!(e.getCause() instanceof IllegalAccessError)) {
+ throw new RuntimeException("Failed to throw IllegalAccessError");
+ }
+ }
+ }
+
+}
+
diff --git a/test/435-new-instance/expected.txt b/test/435-new-instance/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/435-new-instance/expected.txt
diff --git a/test/435-new-instance/info.txt b/test/435-new-instance/info.txt
new file mode 100644
index 0000000..3f30c1b
--- /dev/null
+++ b/test/435-new-instance/info.txt
@@ -0,0 +1,7 @@
+Tests that new-instance throws:
+- InstantiationError on interfaces and abstract classes
+- IllegalAccessError on inaccessible classes
+- NoClassDefFoundError on unknown classes
+
+This also verifies that we don't remove dead (code) new-instances which may
+throw.
diff --git a/test/435-new-instance/smali/instance.smali b/test/435-new-instance/smali/instance.smali
new file mode 100644
index 0000000..2189498
--- /dev/null
+++ b/test/435-new-instance/smali/instance.smali
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LNewInstance;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+ .registers 1
+ invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method public newInstanceInterface()Ljava/lang/Object;
+ .registers 5
+ new-instance v1, LTestInterface;
+ # invoke-direct {v3}, LTestInterface;-><init>()V
+ # intentionally return v4 ("this")
+ return-object v4
+.end method
+
+.method public newInstanceClass()Ljava/lang/Object;
+ .registers 5
+ new-instance v1, LTestClass;
+ # invoke-direct {v3}, LTestClass;-><init>()V
+ # intentionally return v4 ("this")
+ return-object v4
+.end method
+
+.method public newInstancePrivateClass()Ljava/lang/Object;
+ .registers 5
+ new-instance v1, Lpkg/ProtectedClass;
+ # invoke-direct {v3}, Lpck/ProtectedClass;-><init>()V
+ # intentionally return v4 ("this")
+ return-object v4
+.end method
+
+.method public newInstanceUnknownClass()Ljava/lang/Object;
+ .registers 5
+ new-instance v1, LUnknownClass;
+ # invoke-direct {v3}, LUnknownClass;-><init>()V
+ # intentionally return v4 ("this")
+ return-object v4
+.end method
diff --git a/test/435-new-instance/src/Main.java b/test/435-new-instance/src/Main.java
new file mode 100644
index 0000000..b5431ad
--- /dev/null
+++ b/test/435-new-instance/src/Main.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+
+ public static void main(String[] args) throws Throwable {
+ // Attempt to instantiate an interface.
+ $opt$NewInstance("newInstanceInterface", InstantiationError.class.getCanonicalName());
+ // Attempt to instantiate an abstract class.
+ $opt$NewInstance("newInstanceClass", InstantiationError.class.getCanonicalName());
+ // Attempt to instantiate an interface.
+ $opt$NewInstance("newInstancePrivateClass", IllegalAccessError.class.getCanonicalName());
+ // Attempt to instantiate an abstract class.
+ $opt$NewInstance("newInstanceUnknownClass", NoClassDefFoundError.class.getCanonicalName());
+ }
+
+ private static void $opt$NewInstance(String method, String errorName) throws Throwable {
+ try {
+ Class<?> c = Class.forName("NewInstance");
+ Method m = c.getMethod(method);
+ m.invoke(c.newInstance());
+ throw new RuntimeException("Failed to throw " + errorName);
+ } catch (InvocationTargetException e) {
+ if (!e.getCause().getClass().getCanonicalName().equals(errorName)) {
+ throw new RuntimeException("Failed to throw " + errorName
+ + ". Threw: " + e.getCause());
+ }
+ }
+ }
+}
diff --git a/test/435-new-instance/src/TestClass.java b/test/435-new-instance/src/TestClass.java
new file mode 100644
index 0000000..15b0a0d
--- /dev/null
+++ b/test/435-new-instance/src/TestClass.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public abstract class TestClass {
+ // Bogus fields to satisfy dex merger. See b/18051191
+ public int val;
+ public void method() {};
+}
diff --git a/test/435-new-instance/src/TestInterface.java b/test/435-new-instance/src/TestInterface.java
new file mode 100644
index 0000000..db6f3e0
--- /dev/null
+++ b/test/435-new-instance/src/TestInterface.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public interface TestInterface {
+ public void method();
+}
diff --git a/test/435-new-instance/src/pkg/ProtectedClass.java b/test/435-new-instance/src/pkg/ProtectedClass.java
new file mode 100644
index 0000000..b262155
--- /dev/null
+++ b/test/435-new-instance/src/pkg/ProtectedClass.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg;
+
+class ProtectedClass {
+}
diff --git a/test/435-try-finally-without-catch/expected.txt b/test/435-try-finally-without-catch/expected.txt
new file mode 100644
index 0000000..8a67802
--- /dev/null
+++ b/test/435-try-finally-without-catch/expected.txt
@@ -0,0 +1,3 @@
+In finally
+In finally
+In finally
diff --git a/test/435-try-finally-without-catch/info.txt b/test/435-try-finally-without-catch/info.txt
new file mode 100644
index 0000000..46217c5
--- /dev/null
+++ b/test/435-try-finally-without-catch/info.txt
@@ -0,0 +1,26 @@
+Exercise a method containing a `try' statement with several
+instructions with a `finally' clause but without any `catch' block,
+enclosed in a loop.
+
+When dx processes an integer division (or modulo) enclosing a `try'
+block and whose result is assigned to a local value, it is smart
+enough not to emit a `div-int' (or `rem-int') instruction when the
+divisor is non-null, as it wouldn't be used. However, dx is not
+that clever regarding exception handling: if the divisor is known to
+be non-null at compile-time (as is the case in this test), it will
+still emit a block with the exception catching and rethrowing
+mechanism, even if it is not used.
+
+This used to be a problem for a `try' block followed by a `finally'
+clause but with no `catch' block: in that case, the generated Dex code
+item would list zero catch block for this method (see
+art::CodeItem::tries_size_) and the optimizing compiler would have no
+clue that it contains a `try' statement, which it cannot optimize
+(yet). With no hint that this method might contain one (or several)
+special block(s) related to `catch'-less `try' statement(s), the
+optimizing compiler considered this (these) as dead block(s) and
+improperly tried to remove its (their) instructions, sometimes
+removing instructions used by others instructions, thus triggering
+assertions. The optimizing compiler was thus adjusted to remove these
+instructions in a proper fashion, by removing them as users first, and
+then by suppressing them for good.
diff --git a/test/435-try-finally-without-catch/src/Main.java b/test/435-try-finally-without-catch/src/Main.java
new file mode 100644
index 0000000..3c29ce8
--- /dev/null
+++ b/test/435-try-finally-without-catch/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static void main(String[] args){
+ foo();
+ }
+
+ // Reduced test case inspired by constantPropagationTest() from
+ // test/083-compiler-regressions.
+ static void foo() {
+ int a = 0;
+ int b = 1;
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ a = 1;
+ // Would throw an ArithmeticException if b were null (hence
+ // the enclosing `try' statement).
+ int c = a % b;
+ }
+ finally {
+ System.out.println("In finally");
+ }
+ }
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 3c959fb..b85685b 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -472,6 +472,7 @@
else
ifeq ($(4),default)
test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
+ run_test_options += --quick
else
$$(error found $(4) expected $(COMPILER_TYPES))
endif
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index d2cd8ab..5c0f83f 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -108,6 +108,11 @@
DEV_MODE="y"
TIME_OUT="n"
shift
+ elif [ "x$1" = "x--gdb-arg" ]; then
+ shift
+ gdb_arg="$1"
+ GDB_ARGS="${GDB_ARGS} $gdb_arg"
+ shift
elif [ "x$1" = "x--zygote" ]; then
ZYGOTE="-Xzygote"
msg "Spawning from zygote"
@@ -229,11 +234,11 @@
else
if [ `uname` = "Darwin" ]; then
GDB=lldb
- GDB_ARGS="-- $DALVIKVM"
+ GDB_ARGS="$GDB_ARGS -- $DALVIKVM"
DALVIKVM=
else
GDB=gdb
- GDB_ARGS="--args $DALVIKVM"
+ GDB_ARGS="$GDB_ARGS --args $DALVIKVM"
# Enable for Emacs "M-x gdb" support. TODO: allow extra gdb arguments on command line.
# gdbargs="--annotate=3 $gdbargs"
fi
diff --git a/test/run-test b/test/run-test
index e9dd86a..2abc1fa 100755
--- a/test/run-test
+++ b/test/run-test
@@ -171,6 +171,11 @@
option="$1"
run_args="${run_args} --runtime-option $option"
shift
+ elif [ "x$1" = "x--gdb-arg" ]; then
+ shift
+ gdb_arg="$1"
+ run_args="${run_args} --gdb-arg $gdb_arg"
+ shift
elif [ "x$1" = "x--debug" ]; then
run_args="${run_args} --debug"
shift
@@ -189,6 +194,9 @@
run_args="${run_args} -Xcompiler-option --compiler-backend=Optimizing"
image_suffix="-optimizing"
shift
+ elif [ "x$1" = "x--quick" ]; then
+ run_args="${run_args} -Xcompiler-option --compiler-backend=Quick"
+ shift
elif [ "x$1" = "x--no-verify" ]; then
run_args="${run_args} --no-verify"
shift
@@ -416,6 +424,7 @@
echo " --build-only Build test files only (off by default)."
echo " --interpreter Enable interpreter only mode (off by default)."
echo " --optimizing Enable optimizing compiler (off by default)."
+ echo " --quick Use Quick compiler (default)."
echo " --no-verify Turn off verification (on by default)."
echo " --no-optimize Turn off optimization (on by default)."
echo " --no-precise Turn off precise GC (on by default)."
diff --git a/tools/analyze-init-failures.py b/tools/analyze-init-failures.py
new file mode 100755
index 0000000..f803ea3
--- /dev/null
+++ b/tools/analyze-init-failures.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Analyzes the dump of initialization failures and creates a Graphviz dot file
+ representing dependencies."""
+
+import codecs
+import os
+import re
+import string
+import sys
+
+
+_CLASS_RE = re.compile(r'^L(.*);$')
+_ERROR_LINE_RE = re.compile(r'^java.lang.InternalError: (.*)')
+_STACK_LINE_RE = re.compile(r'^\s*at\s[^\s]*\s([^\s]*)')
+
+def Confused(filename, line_number, line):
+ sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
+ raise Exception("giving up!")
+ sys.exit(1)
+
+
+def ProcessFile(filename):
+ lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+ it = iter(lines)
+
+ class_fail_class = {}
+ class_fail_method = {}
+ root_failures = set()
+ root_errors = {}
+
+ while True:
+ try:
+ # We start with a class descriptor.
+ raw_line = it.next()
+ m = _CLASS_RE.search(raw_line)
+ # print(raw_line)
+ if m is None:
+ continue
+ # Found a class.
+ failed_clazz = m.group(1).replace('/','.')
+ # print('Is a class %s' % failed_clazz)
+ # The error line should be next.
+ raw_line = it.next()
+ m = _ERROR_LINE_RE.search(raw_line)
+ # print(raw_line)
+ if m is None:
+ Confused(filename, -1, raw_line)
+ continue
+ # Found an error line.
+ error = m.group(1)
+ # print('Is an error %s' % error)
+ # Get the top of the stack
+ raw_line = it.next()
+ m = _STACK_LINE_RE.search(raw_line)
+ if m is None:
+ continue
+ # Found a stack line. Get the method.
+ method = m.group(1)
+ # print('Is a stack element %s' % method)
+ (left_of_paren,paren,right_of_paren) = method.partition('(')
+ (root_err_class,dot,root_method_name) = left_of_paren.rpartition('.')
+ # print('Error class %s' % err_class)
+ # print('Error method %s' % method_name)
+ # Record the root error.
+ root_failures.add(root_err_class)
+ # Parse all the trace elements to find the "immediate" cause.
+ immediate_class = root_err_class
+ immediate_method = root_method_name
+ root_errors[root_err_class] = error
+ # Now go "up" the stack.
+ while True:
+ raw_line = it.next()
+ m = _STACK_LINE_RE.search(raw_line)
+ if m is None:
+ break # Nothing more to see here.
+ method = m.group(1)
+ (left_of_paren,paren,right_of_paren) = method.partition('(')
+ (err_class,dot,err_method_name) = left_of_paren.rpartition('.')
+ if err_method_name == "<clinit>":
+ # A class initializer is on the stack...
+ class_fail_class[err_class] = immediate_class
+ class_fail_method[err_class] = immediate_method
+ immediate_class = err_class
+ immediate_method = err_method_name
+ except StopIteration:
+ # print('Done')
+ break # Done
+
+ # Assign IDs.
+ fail_sources = set(class_fail_class.values());
+ all_classes = fail_sources | set(class_fail_class.keys())
+ i = 0
+ class_index = {}
+ for clazz in all_classes:
+ class_index[clazz] = i
+ i = i + 1
+
+ # Now create the nodes.
+ for (r_class, r_id) in class_index.items():
+ error_string = ''
+ if r_class in root_failures:
+ error_string = ',color=Red,tooltip="' + root_errors[r_class] + '",URL="' + root_errors[r_class] + '"'
+ print(' n%d [shape=box,label="%s"%s];' % (r_id, r_class, error_string))
+
+ # Some space.
+ print('')
+
+ # Connections.
+ for (failed_class,error_class) in class_fail_class.items():
+ print(' n%d -> n%d;' % (class_index[failed_class], class_index[error_class]))
+
+
+def main():
+ print('digraph {')
+ print(' overlap=false;')
+ print(' splines=true;')
+ ProcessFile(sys.argv[1])
+ print('}')
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
new file mode 100644
index 0000000..8eac1d3
--- /dev/null
+++ b/tools/libcore_failures.txt
@@ -0,0 +1,21 @@
+/*
+ * This file contains expectations for ART's buildbot. The purpose of this file is
+ * to temporary and quickly list failing tests and not break the bots, until the
+ * libcore expectation files get properly updated. The script that uses this file
+ * is art/tools/run-libcore-tests.sh.
+ *
+ * It is also used to enable AOSP experiments, and not mess up with CTS's expectations.
+ */
+
+[
+{
+ description: "Assert.java differences between vogar and junit.",
+ result: EXEC_FAILED,
+ name: "libcore.java.math.RunCSVTests#test_csv"
+},
+{
+ description: "Test is currently being updated.",
+ result: EXEC_FAILED,
+ name: "libcore.java.util.OldTimeZoneTest#test_getDisplayNameZILjava_util_Locale"
+}
+]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 5c7e3c5..9fa3fda 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -27,16 +27,18 @@
exit 1
fi
-# Packages that currently report no failures.
+# Packages that currently work correctly with the expectation files.
working_packages=("libcore.java.lang"
+ "libcore.java.math"
"libcore.java.util"
"org.apache.harmony.annotation"
"org.apache.harmony.regex"
"org.apache.harmony.tests.java.lang"
+ "org.apache.harmony.tests.java.math"
"org.apache.harmony.tests.java.util"
"tests.java.lang.String")
# Run the tests using vogar.
echo "Running tests for the following test packages:"
echo ${working_packages[@]} | tr " " "\n"
-vogar $@ --classpath $test_jar ${working_packages[@]}
+vogar $@ --expectations art/tools/libcore_failures.txt --classpath $test_jar ${working_packages[@]}