summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/builder.cc51
-rw-r--r--compiler/optimizing/code_generator.cc41
-rw-r--r--compiler/optimizing/code_generator.h1
-rw-r--r--compiler/optimizing/code_generator_arm.cc26
-rw-r--r--compiler/optimizing/code_generator_arm.h52
-rw-r--r--compiler/optimizing/code_generator_arm64.cc2
-rw-r--r--compiler/optimizing/code_generator_arm64.h47
-rw-r--r--compiler/optimizing/code_generator_x86.cc24
-rw-r--r--compiler/optimizing/code_generator_x86.h52
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc26
-rw-r--r--compiler/optimizing/code_generator_x86_64.h56
-rw-r--r--compiler/optimizing/nodes.h47
-rw-r--r--compiler/optimizing/optimizing_compiler.cc33
-rw-r--r--runtime/mirror/art_method.cc10
-rw-r--r--runtime/mirror/art_method.h3
-rw-r--r--test/004-ReferenceMap/stack_walk_refmap_jni.cc45
-rw-r--r--test/401-optimizing-compiler/src/Main.java12
-rw-r--r--test/421-exceptions/expected.txt20
-rw-r--r--test/421-exceptions/info.txt1
-rw-r--r--test/421-exceptions/src/Main.java65
-rw-r--r--test/Android.run-test.mk31
21 files changed, 497 insertions, 148 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index e43841a..6eff23a 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -119,13 +119,6 @@ bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
return true;
}
-static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
- if (code_item.tries_size_ > 0) {
- return false;
- }
- return true;
-}
-
template<typename T>
void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
int32_t target_offset = instruction.GetTargetOffset();
@@ -164,10 +157,6 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset)
}
HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
- if (!CanHandleCodeItem(code_item)) {
- return nullptr;
- }
-
const uint16_t* code_ptr = code_item.insns_;
const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
code_start_ = code_ptr;
@@ -187,6 +176,25 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
// start a new block, and create these blocks.
ComputeBranchTargets(code_ptr, code_end);
+ // Also create blocks for catch handlers.
+ if (code_item.tries_size_ != 0) {
+ const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0);
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ for (uint32_t idx = 0; idx < handlers_size; ++idx) {
+ CatchHandlerIterator iterator(handlers_ptr);
+ for (; iterator.HasNext(); iterator.Next()) {
+ uint32_t address = iterator.GetHandlerAddress();
+ HBasicBlock* block = FindBlockStartingAt(address);
+ if (block == nullptr) {
+ block = new (arena_) HBasicBlock(graph_, address);
+ branch_targets_.Put(address, block);
+ }
+ block->SetIsCatchBlock();
+ }
+ handlers_ptr = iterator.EndDataPointer();
+ }
+ }
+
if (!InitializeParameters(code_item.ins_size_)) {
return nullptr;
}
@@ -1217,6 +1225,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::ARRAY_LENGTH: {
HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+ // No need for a temporary for the null check, it is the only input of the following
+ // instruction.
+ object = new (arena_) HNullCheck(object, dex_offset);
+ current_block_->AddInstruction(object);
current_block_->AddInstruction(new (arena_) HArrayLength(object));
UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
break;
@@ -1251,6 +1263,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::MOVE_EXCEPTION: {
+ current_block_->AddInstruction(new (arena_) HLoadException());
+ UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
+ break;
+ }
+
+ case Instruction::THROW: {
+ HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+ current_block_->AddInstruction(new (arena_) HThrow(exception, dex_offset));
+ // A throw instruction must branch to the exit block.
+ current_block_->AddSuccessor(exit_block_);
+ // We finished building this block. Set the current block to null to avoid
+ // adding dead instructions to it.
+ current_block_ = nullptr;
+ break;
+ }
+
default:
return false;
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index ac72a33..c75980d 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -356,12 +356,13 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
int32_t pc2dex_dalvik_offset = 0;
uint32_t dex2pc_data_size = 0u;
uint32_t dex2pc_entries = 0u;
+ uint32_t dex2pc_offset = 0u;
+ int32_t dex2pc_dalvik_offset = 0;
if (src_map != nullptr) {
src_map->reserve(pc2dex_entries);
}
- // We currently only have pc2dex entries.
for (size_t i = 0; i < pc2dex_entries; i++) {
struct PcInfo pc_info = pc_infos_.Get(i);
pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset);
@@ -373,6 +374,19 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
}
}
+ // Walk over the blocks and find which ones correspond to catch block entries.
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ intptr_t native_pc = GetAddressOf(block);
+ ++dex2pc_entries;
+ dex2pc_data_size += UnsignedLeb128Size(native_pc - dex2pc_offset);
+ dex2pc_data_size += SignedLeb128Size(block->GetDexPc() - dex2pc_dalvik_offset);
+ dex2pc_offset = native_pc;
+ dex2pc_dalvik_offset = block->GetDexPc();
+ }
+ }
+
uint32_t total_entries = pc2dex_entries + dex2pc_entries;
uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
@@ -380,6 +394,7 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
uint8_t* data_ptr = &(*data)[0];
uint8_t* write_pos = data_ptr;
+
write_pos = EncodeUnsignedLeb128(write_pos, total_entries);
write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries);
DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size);
@@ -387,6 +402,9 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
pc2dex_offset = 0u;
pc2dex_dalvik_offset = 0u;
+ dex2pc_offset = 0u;
+ dex2pc_dalvik_offset = 0u;
+
for (size_t i = 0; i < pc2dex_entries; i++) {
struct PcInfo pc_info = pc_infos_.Get(i);
DCHECK(pc2dex_offset <= pc_info.native_pc);
@@ -395,6 +413,19 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
pc2dex_offset = pc_info.native_pc;
pc2dex_dalvik_offset = pc_info.dex_pc;
}
+
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ intptr_t native_pc = GetAddressOf(block);
+ write_pos2 = EncodeUnsignedLeb128(write_pos2, native_pc - dex2pc_offset);
+ write_pos2 = EncodeSignedLeb128(write_pos2, block->GetDexPc() - dex2pc_dalvik_offset);
+ dex2pc_offset = native_pc;
+ dex2pc_dalvik_offset = block->GetDexPc();
+ }
+ }
+
+
DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size + pc2dex_data_size);
DCHECK_EQ(static_cast<size_t>(write_pos2 - data_ptr), data_size);
@@ -411,6 +442,14 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
CHECK_EQ(pc_info.dex_pc, it.DexPc());
++it;
}
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ CHECK_EQ(GetAddressOf(block), it2.NativePcOffset());
+ CHECK_EQ(block->GetDexPc(), it2.DexPc());
+ ++it2;
+ }
+ }
CHECK(it == table.PcToDexEnd());
CHECK(it2 == table.DexToPcEnd());
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 01c5cc9..fc4ea4b 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -92,6 +92,7 @@ class CodeGenerator : public ArenaObject<kArenaAllocMisc> {
virtual HGraphVisitor* GetInstructionVisitor() = 0;
virtual Assembler* GetAssembler() = 0;
virtual size_t GetWordSize() const = 0;
+ virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
void ComputeFrameSize(size_t number_of_spill_slots,
size_t maximum_number_of_live_registers,
size_t number_of_out_slots);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index dd595d9..adedf78 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2509,5 +2509,31 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
+ Register out = load->GetLocations()->Out().As<Register>();
+ int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
+ __ LoadFromOffset(kLoadWord, out, TR, offset);
+ __ LoadImmediate(IP, 0);
+ __ StoreToOffset(kStoreWord, IP, TR, offset);
+}
+
+void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
+ codegen_->InvokeRuntime(
+ QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+}
+
} // namespace arm
} // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 5076a4b..5d51993 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -77,10 +77,10 @@ class ParallelMoveResolverARM : public ParallelMoveResolver {
ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
ArmAssembler* GetAssembler() const;
@@ -99,7 +99,7 @@ class LocationsBuilderARM : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr);
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -119,7 +119,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor {
InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr);
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -145,39 +145,43 @@ class CodeGeneratorARM : public CodeGenerator {
explicit CodeGeneratorARM(HGraph* graph);
virtual ~CodeGeneratorARM() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kArmWordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual ArmAssembler* GetAssembler() OVERRIDE {
+ ArmAssembler* GetAssembler() OVERRIDE {
return &assembler_;
}
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
// Blocks all register pairs made out of blocked core registers.
void UpdateBlockedPairRegisters() const;
@@ -186,7 +190,7 @@ class CodeGeneratorARM : public CodeGenerator {
return &move_resolver_;
}
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kThumb2;
}
@@ -208,7 +212,7 @@ class CodeGeneratorARM : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index c26b0ab..31526e2 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -540,12 +540,14 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
M(DivZeroCheck) \
M(FloatConstant) \
M(LoadClass) \
+ M(LoadException) \
M(LoadString) \
M(Neg) \
M(NewArray) \
M(ParallelMove) \
M(StaticFieldGet) \
M(StaticFieldSet) \
+ M(Throw) \
M(TypeConversion) \
#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 5530f46..4a41000 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -95,7 +95,7 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor {
InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
#undef DECLARE_VISIT_INSTRUCTION
@@ -118,7 +118,7 @@ class LocationsBuilderARM64 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
#undef DECLARE_VISIT_INSTRUCTION
@@ -135,10 +135,10 @@ class LocationsBuilderARM64 : public HGraphVisitor {
class CodeGeneratorARM64 : public CodeGenerator {
public:
explicit CodeGeneratorARM64(HGraph* graph);
- virtual ~CodeGeneratorARM64() { }
+ virtual ~CodeGeneratorARM64() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
static const vixl::CPURegList& GetFramePreservedRegisters() {
static const vixl::CPURegList frame_preserved_regs =
@@ -149,44 +149,49 @@ class CodeGeneratorARM64 : public CodeGenerator {
return GetFramePreservedRegisters().TotalSizeInBytes();
}
- virtual void Bind(HBasicBlock* block) OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
vixl::Label* GetLabelOf(HBasicBlock* block) const {
return block_labels_ + block->GetBlockId();
}
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kArm64WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block ATTRIBUTE_UNUSED) const OVERRIDE {
+ UNIMPLEMENTED(INFO) << "TODO: GetAddressOf";
+ return 0u;
+ }
+
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
- virtual Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+ HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
+ Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
// Emit a write barrier.
void MarkGCCard(vixl::Register object, vixl::Register value);
// Register allocation.
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ void SetupBlockedRegisters() const OVERRIDE;
// AllocateFreeRegister() is only used when allocating registers locally
// during CompileBaseline().
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
UNUSED(stack_index);
UNUSED(reg_id);
UNIMPLEMENTED(INFO) << "TODO: SaveCoreRegister";
return 0;
}
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
UNUSED(stack_index);
UNUSED(reg_id);
UNIMPLEMENTED(INFO) << "TODO: RestoreCoreRegister";
@@ -205,16 +210,16 @@ class CodeGeneratorARM64 : public CodeGenerator {
kNumberOfAllocatableCoreRegisters + kNumberOfAllocatableFloatingPointRegisters;
static constexpr int kNumberOfAllocatableRegisterPairs = 0;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kArm64;
}
void MoveHelper(Location destination, Location source, Primitive::Type type);
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
HGraph* graph = GetGraph();
int length = graph->GetBlocks().Size();
block_labels_ = graph->GetArena()->AllocArray<vixl::Label>(length);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index b2d9187..2a8eded 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2596,5 +2596,29 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
+ Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
+ __ fs()->movl(load->GetLocations()->Out().As<Register>(), address);
+ __ fs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
} // namespace x86
} // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 176a269..85fe21c 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -71,10 +71,10 @@ class ParallelMoveResolverX86 : public ParallelMoveResolver {
ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
X86Assembler* GetAssembler() const;
@@ -94,7 +94,7 @@ class LocationsBuilderX86 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -114,7 +114,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor {
InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -140,39 +140,43 @@ class CodeGeneratorX86 : public CodeGenerator {
explicit CodeGeneratorX86(HGraph* graph);
virtual ~CodeGeneratorX86() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kX86WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual X86Assembler* GetAssembler() OVERRIDE {
+ X86Assembler* GetAssembler() OVERRIDE {
return &assembler_;
}
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
// Blocks all register pairs made out of blocked core registers.
void UpdateBlockedPairRegisters() const;
@@ -181,7 +185,7 @@ class CodeGeneratorX86 : public CodeGenerator {
return &move_resolver_;
}
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kX86;
}
@@ -199,7 +203,7 @@ class CodeGeneratorX86 : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 2bd76c1..41f3c59 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2549,5 +2549,31 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
+ Address address = Address::Absolute(
+ Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
+ __ gs()->movl(load->GetLocations()->Out().As<CpuRegister>(), address);
+ __ gs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
+ __ gs()->call(
+ Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
} // namespace x86_64
} // namespace art
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 0de3045..9565b6f 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -72,10 +72,10 @@ class ParallelMoveResolverX86_64 : public ParallelMoveResolver {
ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
X86_64Assembler* GetAssembler() const;
@@ -98,7 +98,7 @@ class LocationsBuilderX86_64 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -118,7 +118,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor {
InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -144,30 +144,30 @@ class CodeGeneratorX86_64 : public CodeGenerator {
explicit CodeGeneratorX86_64(HGraph* graph);
virtual ~CodeGeneratorX86_64() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kX86_64WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual X86_64Assembler* GetAssembler() OVERRIDE {
+ X86_64Assembler* GetAssembler() OVERRIDE {
return &assembler_;
}
@@ -175,14 +175,18 @@ class CodeGeneratorX86_64 : public CodeGenerator {
return &move_resolver_;
}
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void SetupBlockedRegisters() const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kX86_64;
}
@@ -198,7 +202,7 @@ class CodeGeneratorX86_64 : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index a57bbdb..37e5e6b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -292,7 +292,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
block_id_(-1),
dex_pc_(dex_pc),
lifetime_start_(kNoLifetime),
- lifetime_end_(kNoLifetime) {}
+ lifetime_end_(kNoLifetime),
+ is_catch_block_(false) {}
const GrowableArray<HBasicBlock*>& GetPredecessors() const {
return predecessors_;
@@ -450,6 +451,9 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
uint32_t GetDexPc() const { return dex_pc_; }
+ bool IsCatchBlock() const { return is_catch_block_; }
+ void SetIsCatchBlock() { is_catch_block_ = true; }
+
private:
HGraph* const graph_;
GrowableArray<HBasicBlock*> predecessors_;
@@ -464,6 +468,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
const uint32_t dex_pc_;
size_t lifetime_start_;
size_t lifetime_end_;
+ bool is_catch_block_;
DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
};
@@ -495,6 +500,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
M(LessThan, Condition) \
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
+ M(LoadException, Instruction) \
M(LoadLocal, Instruction) \
M(LoadString, Instruction) \
M(Local, Instruction) \
@@ -517,6 +523,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
M(Sub, BinaryOperation) \
M(SuspendCheck, Instruction) \
M(Temporary, Instruction) \
+ M(Throw, Instruction) \
M(TypeConversion, Instruction) \
#define FOR_EACH_INSTRUCTION(M) \
@@ -1052,7 +1059,7 @@ class HReturn : public HTemplateInstruction<1> {
};
// The exit instruction is the only instruction of the exit block.
-// Instructions aborting the method (HTrow and HReturn) must branch to the
+// Instructions aborting the method (HThrow and HReturn) must branch to the
// exit block.
class HExit : public HTemplateInstruction<0> {
public:
@@ -1071,7 +1078,7 @@ class HGoto : public HTemplateInstruction<0> {
public:
HGoto() : HTemplateInstruction(SideEffects::None()) {}
- virtual bool IsControlFlow() const { return true; }
+ bool IsControlFlow() const OVERRIDE { return true; }
HBasicBlock* GetSuccessor() const {
return GetBlock()->GetSuccessors().Get(0);
@@ -1092,7 +1099,7 @@ class HIf : public HTemplateInstruction<1> {
SetRawInputAt(0, input);
}
- virtual bool IsControlFlow() const { return true; }
+ bool IsControlFlow() const OVERRIDE { return true; }
HBasicBlock* IfTrueSuccessor() const {
return GetBlock()->GetSuccessors().Get(0);
@@ -2284,6 +2291,38 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
};
+// Implement the move-exception DEX instruction.
+class HLoadException : public HExpression<0> {
+ public:
+ HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+
+ DECLARE_INSTRUCTION(LoadException);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HLoadException);
+};
+
+class HThrow : public HTemplateInstruction<1> {
+ public:
+ HThrow(HInstruction* exception, uint32_t dex_pc)
+ : HTemplateInstruction(SideEffects::None()), dex_pc_(dex_pc) {
+ SetRawInputAt(0, exception);
+ }
+
+ bool IsControlFlow() const OVERRIDE { return true; }
+
+ bool NeedsEnvironment() const OVERRIDE { return true; }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
+ DECLARE_INSTRUCTION(Throw);
+
+ private:
+ uint32_t dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HThrow);
+};
+
class MoveOperands : public ArenaObject<kArenaAllocMisc> {
public:
MoveOperands(Location source, Location destination, HInstruction* instruction)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 08b74c7..6e3653a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -206,6 +206,11 @@ static bool IsInstructionSetSupported(InstructionSet instruction_set) {
|| instruction_set == kX86_64;
}
+static bool CanOptimize(const DexFile::CodeItem& code_item) {
+ // TODO: We currently cannot optimize methods with try/catch.
+ return code_item.tries_size_ == 0;
+}
+
CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -264,7 +269,9 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
CodeVectorAllocator allocator;
- if (run_optimizations_ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
+ if (run_optimizations_
+ && CanOptimize(*code_item)
+ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
optimized_compiled_methods_++;
graph->BuildDominatorTree();
graph->TransformToSSA();
@@ -315,17 +322,19 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
unoptimized_compiled_methods_++;
codegen->CompileBaseline(&allocator);
- // Run these phases to get some test coverage.
- graph->BuildDominatorTree();
- graph->TransformToSSA();
- visualizer.DumpGraph("ssa");
- graph->FindNaturalLoops();
- SsaRedundantPhiElimination(graph).Run();
- SsaDeadPhiElimination(graph).Run();
- GlobalValueNumberer(graph->GetArena(), graph).Run();
- SsaLivenessAnalysis liveness(*graph, codegen);
- liveness.Analyze();
- visualizer.DumpGraph(kLivenessPassName);
+ 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();
+ GlobalValueNumberer(graph->GetArena(), graph).Run();
+ SsaLivenessAnalysis liveness(*graph, codegen);
+ liveness.Analyze();
+ visualizer.DumpGraph(kLivenessPassName);
+ }
std::vector<uint8_t> mapping_table;
SrcMap src_mapping_table;
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index acd1043..a742aaa 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -197,7 +197,7 @@ uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
return DexFile::kDexNoIndex;
}
-uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc) {
+uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure) {
const void* entry_point = GetQuickOatEntryPoint();
MappingTable table(
entry_point != nullptr ? GetMappingTable(EntryPointToCodePointer(entry_point)) : nullptr);
@@ -219,9 +219,11 @@ uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc) {
return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
}
}
- LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
- << " in " << PrettyMethod(this);
- return 0;
+ if (abort_on_failure) {
+ LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
+ << " in " << PrettyMethod(this);
+ }
+ return UINTPTR_MAX;
}
uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 08c0996..d92d00a 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -453,7 +453,8 @@ class MANAGED ArtMethod FINAL : public Object {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Converts a dex PC to a native PC.
- uintptr_t ToNativeQuickPc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ uintptr_t ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure = true)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Find the catch block for the given exception type and dex_pc. When a catch block is found,
// indicates whether the found catch block is responsible for clearing the exception or whether
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 291b45f..631c4be 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -19,10 +19,13 @@
namespace art {
-#define CHECK_REGS_CONTAIN_REFS(native_pc_offset, ...) do { \
+#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \
int t[] = {__VA_ARGS__}; \
int t_size = sizeof(t) / sizeof(*t); \
- CheckReferences(t, t_size, m->NativeQuickPcOffset(m->ToNativeQuickPc(native_pc_offset))); \
+ uintptr_t native_quick_pc = m->ToNativeQuickPc(dex_pc, abort_if_not_found); \
+ if (native_quick_pc != UINTPTR_MAX) { \
+ CheckReferences(t, t_size, m->NativeQuickPcOffset(native_quick_pc)); \
+ } \
} while (false);
struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
@@ -40,31 +43,33 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
// we know the Dex registers with live reference values. Assert that what we
// find is what is expected.
if (m_name.compare("f") == 0) {
- CHECK_REGS_CONTAIN_REFS(0x03U, 8); // v8: this
- CHECK_REGS_CONTAIN_REFS(0x06U, 8, 1); // v8: this, v1: x
- CHECK_REGS_CONTAIN_REFS(0x08U, 8, 3, 1); // v8: this, v3: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x0cU, 8, 3, 1); // v8: this, v3: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x0eU, 8, 3, 1); // v8: this, v3: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x10U, 8, 3, 1); // v8: this, v3: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x03U, true, 8); // v8: this
+ CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1); // v8: this, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1); // v8: this, v3: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1); // v8: this, v3: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1); // v8: this, v3: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1); // v8: this, v3: y, v1: x
// v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See:
// 0024: move-object v3, v2
// 0025: goto 0013
// Detaled dex instructions for ReferenceMap.java are at the end of this function.
// CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1); // v8: this, v3: y, v2: y, v1: x
- // We eliminate the non-live registers at a return, so only v3 is live:
- CHECK_REGS_CONTAIN_REFS(0x13U); // v3: y
- CHECK_REGS_CONTAIN_REFS(0x18U, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
- CHECK_REGS_CONTAIN_REFS(0x1aU, 8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex
- CHECK_REGS_CONTAIN_REFS(0x1dU, 8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex
+ // We eliminate the non-live registers at a return, so only v3 is live.
+ // Note that it is OK for a compiler to not have a dex map at this dex PC because
+ // a return is not a safepoint.
+ CHECK_REGS_CONTAIN_REFS(0x13U, false); // v3: y
+ CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
+ CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex
+ CHECK_REGS_CONTAIN_REFS(0x1dU, true, 8, 5, 2, 1, 0); // v8: this, v5: x[1], v2: y, v1: x, v0: ex
// v5 is removed from the root set because there is a "merge" operation.
// See 0015: if-nez v2, 001f.
- CHECK_REGS_CONTAIN_REFS(0x1fU, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
- CHECK_REGS_CONTAIN_REFS(0x21U, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
- CHECK_REGS_CONTAIN_REFS(0x27U, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x29U, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x2cU, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x2fU, 8, 4, 3, 2, 1); // v8: this, v4: ex, v3: y, v2: y, v1: x
- CHECK_REGS_CONTAIN_REFS(0x32U, 8, 3, 2, 1, 0); // v8: this, v3: y, v2: y, v1: x, v0: ex
+ CHECK_REGS_CONTAIN_REFS(0x1fU, true, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
+ CHECK_REGS_CONTAIN_REFS(0x21U, true, 8, 2, 1, 0); // v8: this, v2: y, v1: x, v0: ex
+ CHECK_REGS_CONTAIN_REFS(0x27U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x29U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x2cU, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x2fU, true, 8, 4, 3, 2, 1); // v8: this, v4: ex, v3: y, v2: y, v1: x
+ CHECK_REGS_CONTAIN_REFS(0x32U, true, 8, 3, 2, 1, 0); // v8: this, v3: y, v2: y, v1: x, v0: ex
}
return true;
diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java
index 07c407b..7c3fd25 100644
--- a/test/401-optimizing-compiler/src/Main.java
+++ b/test/401-optimizing-compiler/src/Main.java
@@ -94,6 +94,14 @@ public class Main {
exception = e;
}
+ // Test that we do NPE checks on array length.
+ exception = null;
+ try {
+ $opt$ArrayLengthOfNull(null);
+ } catch (NullPointerException e) {
+ exception = e;
+ }
+
if (exception == null) {
throw new Error("Missing NullPointerException");
}
@@ -218,5 +226,9 @@ public class Main {
return 42;
}
+ public static int $opt$ArrayLengthOfNull(int[] array) {
+ return array.length;
+ }
+
Object o;
}
diff --git a/test/421-exceptions/expected.txt b/test/421-exceptions/expected.txt
new file mode 100644
index 0000000..94db350
--- /dev/null
+++ b/test/421-exceptions/expected.txt
@@ -0,0 +1,20 @@
+1
+3
+4
+1
+4
+1
+4
+1
+4
+Caught class java.lang.RuntimeException
+1
+2
+4
+1
+4
+1
+4
+1
+4
+Caught class java.lang.NullPointerException
diff --git a/test/421-exceptions/info.txt b/test/421-exceptions/info.txt
new file mode 100644
index 0000000..bdec67e
--- /dev/null
+++ b/test/421-exceptions/info.txt
@@ -0,0 +1 @@
+Simple test for try/catch/throw.
diff --git a/test/421-exceptions/src/Main.java b/test/421-exceptions/src/Main.java
new file mode 100644
index 0000000..6bf2377
--- /dev/null
+++ b/test/421-exceptions/src/Main.java
@@ -0,0 +1,65 @@
+/*
+ * 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 $opt$bar() {
+ try {
+ $opt$foo(1);
+ } catch (NullPointerException e) {
+ $opt$foo(2);
+ } catch (RuntimeException e) {
+ $opt$foo(3);
+ } finally {
+ $opt$foo(4);
+ }
+ }
+
+ static int barState;
+ static int fooState;
+
+ public static void main(String[] args) {
+ fooState = 0;
+ $opt$runTest();
+ fooState = 1;
+ $opt$runTest();
+ }
+
+ public static void $opt$runTest() {
+ barState = 1;
+ $opt$bar();
+ barState = 2;
+ $opt$bar();
+ barState = 3;
+ $opt$bar();
+ barState = 4;
+ try {
+ $opt$bar();
+ } catch (RuntimeException e) {
+ System.out.println("Caught " + e.getClass());
+ }
+ }
+
+ public static void $opt$foo(int value) {
+ System.out.println(value);
+ if (value == barState) {
+ if (fooState == 0) {
+ throw new RuntimeException();
+ } else {
+ throw new NullPointerException();
+ }
+ }
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 7d56271..269f2fb 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -312,26 +312,39 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
003-omnibus-opcodes \
004-InterfaceTest \
004-JniTest \
+ 004-ReferenceMap \
+ 004-SignalTest \
004-StackWalk \
004-UnsafeTest \
+ 005-annotations \
006-args \
007-count10 \
+ 008-exceptions \
011-array-copy \
013-math2 \
016-intern \
017-float \
018-stack-overflow \
+ 019-wrong-array-type \
020-string \
+ 021-string2 \
022-interface \
023-many-interfaces \
+ 024-illegal-access \
026-access \
028-array-write \
+ 029-assert \
030-bad-finalizer \
031-class-attributes \
032-concrete-sub \
+ 033-class-init-deadlock \
+ 035-enum \
036-finalizer \
037-inherit \
038-inner-null \
+ 039-join-main \
+ 040-miranda \
+ 042-new-instance \
043-privates \
044-proxy \
045-reflect-array \
@@ -342,9 +355,13 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
051-thread \
052-verifier-fun \
054-uncaught \
+ 055-enum-performance \
056-const-string-jumbo \
061-out-of-memory \
063-process-manager \
+ 064-field-access \
+ 065-mismatched-implements \
+ 066-mismatched-super \
067-preemptive-unpark \
068-classloader \
069-field-type \
@@ -352,16 +369,20 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
071-dexfile \
072-precise-gc \
074-gc-thrash \
+ 075-verification-error \
076-boolean-put \
077-method-override \
+ 078-polymorphic-virtual \
079-phantom \
080-oom-throw \
+ 081-hot-exceptions \
082-inline-execute \
083-compiler-regressions \
084-class-init \
085-old-style-inner-class \
086-null-super \
087-gc-after-link \
+ 088-monitor-verification \
090-loop-formation \
092-locale \
093-serialization \
@@ -370,6 +391,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
097-duplicate-method \
098-ddmc \
100-reflect2 \
+ 101-fibonacci \
102-concurrent-gc \
103-string-append \
105-invoke \
@@ -377,20 +399,28 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
107-int-math2 \
109-suspend-check \
110-field-access \
+ 111-unresolvable-exception \
112-double-math \
113-multidex \
117-nopatchoat \
+ 118-noimage-dex2oat \
+ 119-noimage-patchoat \
121-modifiers \
+ 121-simple-suspend-check \
122-npe \
123-compiler-regressions-mt \
124-missing-classes \
125-gc-and-classloading \
126-miranda-multidex \
+ 201-built-in-exception-detail-messages \
+ 202-thread-oome \
300-package-override \
301-abstract-protected \
303-verification-stress \
401-optimizing-compiler \
+ 402-optimizing-control-flow \
403-optimizing-long \
+ 404-optimizing-allocator \
405-optimizing-long-allocator \
406-fields \
407-arrays \
@@ -407,6 +437,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
418-const-string \
419-long-parameter \
420-const-class \
+ 421-exceptions \
422-type-conversion \
700-LoadArgRegs \
701-easy-div-rem \