summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Geoffray <ngeoffray@google.com>2014-09-02 15:17:15 +0100
committerNicolas Geoffray <ngeoffray@google.com>2014-09-08 12:15:07 +0100
commit3946844c34ad965515f677084b07d663d70ad1b8 (patch)
tree0d85bfba2ff69c34a2897351d1e50a1464509305
parente2c23739c6395a83b30ece38f8a2e9e1bf7cf3ce (diff)
downloadart-3946844c34ad965515f677084b07d663d70ad1b8.zip
art-3946844c34ad965515f677084b07d663d70ad1b8.tar.gz
art-3946844c34ad965515f677084b07d663d70ad1b8.tar.bz2
Runtime support for the new stack maps for the opt compiler.
Now most of the methods supported by the compiler can be optimized, instead of using the baseline. Change-Id: I80ab36a34913fa4e7dd576c7bf55af63594dc1fa
-rw-r--r--compiler/compiled_method.cc19
-rw-r--r--compiler/compiled_method.h17
-rw-r--r--compiler/oat_writer.cc22
-rw-r--r--compiler/optimizing/builder.cc11
-rw-r--r--compiler/optimizing/code_generator.cc104
-rw-r--r--compiler/optimizing/code_generator.h16
-rw-r--r--compiler/optimizing/code_generator_arm.cc129
-rw-r--r--compiler/optimizing/code_generator_x86.cc120
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc128
-rw-r--r--compiler/optimizing/locations.cc22
-rw-r--r--compiler/optimizing/locations.h55
-rw-r--r--compiler/optimizing/nodes.cc4
-rw-r--r--compiler/optimizing/nodes.h33
-rw-r--r--compiler/optimizing/optimizing_compiler.cc63
-rw-r--r--compiler/optimizing/register_allocator.cc309
-rw-r--r--compiler/optimizing/register_allocator.h32
-rw-r--r--compiler/optimizing/register_allocator_test.cc22
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.h49
-rw-r--r--compiler/optimizing/ssa_phi_elimination.cc4
-rw-r--r--compiler/optimizing/stack_map_stream.h31
-rw-r--r--compiler/optimizing/stack_map_test.cc24
-rw-r--r--oatdump/oatdump.cc8
-rw-r--r--runtime/mirror/art_method-inl.h14
-rw-r--r--runtime/mirror/art_method.h10
-rw-r--r--runtime/stack.cc10
-rw-r--r--runtime/stack_map.h78
-rw-r--r--runtime/thread.cc100
-rw-r--r--test/407-arrays/src/Main.java2
28 files changed, 951 insertions, 485 deletions
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f9a78be..ba5bd30 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -164,6 +164,25 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver,
CompiledMethod::CompiledMethod(CompilerDriver* driver,
InstructionSet instruction_set,
+ const std::vector<uint8_t>& quick_code,
+ const size_t frame_size_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const std::vector<uint8_t>& mapping_table,
+ const std::vector<uint8_t>& stack_map)
+ : CompiledCode(driver, instruction_set, quick_code),
+ frame_size_in_bytes_(frame_size_in_bytes),
+ core_spill_mask_(core_spill_mask),
+ fp_spill_mask_(fp_spill_mask),
+ src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
+ mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
+ vmap_table_(driver->DeduplicateVMapTable(stack_map)),
+ gc_map_(nullptr),
+ cfi_info_(nullptr) {
+}
+
+CompiledMethod::CompiledMethod(CompilerDriver* driver,
+ InstructionSet instruction_set,
const std::vector<uint8_t>& code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 36f4745..3e34144 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -173,7 +173,7 @@ class SrcMap FINAL : public std::vector<SrcMapElem> {
class CompiledMethod FINAL : public CompiledCode {
public:
- // Constructs a CompiledMethod for the non-LLVM compilers.
+ // Constructs a CompiledMethod for Quick.
CompiledMethod(CompilerDriver* driver,
InstructionSet instruction_set,
const std::vector<uint8_t>& quick_code,
@@ -186,6 +186,16 @@ class CompiledMethod FINAL : public CompiledCode {
const std::vector<uint8_t>& native_gc_map,
const std::vector<uint8_t>* cfi_info);
+ // Constructs a CompiledMethod for Optimizing.
+ CompiledMethod(CompilerDriver* driver,
+ InstructionSet instruction_set,
+ const std::vector<uint8_t>& quick_code,
+ const size_t frame_size_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const std::vector<uint8_t>& mapping_table,
+ const std::vector<uint8_t>& vmap_table);
+
// Constructs a CompiledMethod for the QuickJniCompiler.
CompiledMethod(CompilerDriver* driver,
InstructionSet instruction_set,
@@ -232,9 +242,8 @@ class CompiledMethod FINAL : public CompiledCode {
return *vmap_table_;
}
- const std::vector<uint8_t>& GetGcMap() const {
- DCHECK(gc_map_ != nullptr);
- return *gc_map_;
+ std::vector<uint8_t> const* GetGcMap() const {
+ return gc_map_;
}
const std::vector<uint8_t>* GetCFIInfo() const {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 680ce0a..c5d1478 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -140,7 +140,7 @@ OatWriter::~OatWriter() {
struct OatWriter::GcMapDataAccess {
static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
- return &compiled_method->GetGcMap();
+ return compiled_method->GetGcMap();
}
static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
@@ -434,13 +434,15 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
} else {
status = mirror::Class::kStatusNotReady;
}
- const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
- size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
- bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
- CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
- << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
- << (status < mirror::Class::kStatusVerified) << " " << status << " "
- << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+ std::vector<uint8_t> const * gc_map = compiled_method->GetGcMap();
+ if (gc_map != nullptr) {
+ size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
+ bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+ CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
+ << gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
+ << (status < mirror::Class::kStatusVerified) << " " << status << " "
+ << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+ }
}
DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
@@ -475,7 +477,7 @@ class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
- uint32_t map_size = map->size() * sizeof((*map)[0]);
+ uint32_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
if (map_size != 0u) {
auto lb = dedupe_map_.lower_bound(map);
if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map, lb->first)) {
@@ -645,7 +647,7 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
// Write deduplicated map.
const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
- size_t map_size = map->size() * sizeof((*map)[0]);
+ size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
DCHECK((map_size == 0u && map_offset == 0u) ||
(map_size != 0u && map_offset != 0u && map_offset <= offset_))
<< PrettyMethod(it.GetMemberIndex(), *dex_file_);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 43e6b83..ecd6802 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -413,6 +413,7 @@ bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction,
current_block_->AddInstruction(new (arena_) HInstanceFieldSet(
null_check,
value,
+ field_type,
resolved_field->GetOffset()));
} else {
current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
@@ -453,7 +454,8 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
if (is_put) {
HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
// TODO: Insert a type check node if the type is Object.
- current_block_->AddInstruction(new (arena_) HArraySet(object, index, value, dex_offset));
+ current_block_->AddInstruction(new (arena_) HArraySet(
+ object, index, value, anticipated_type, dex_offset));
} else {
current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
@@ -750,6 +752,13 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_
ARRAY_XX(_CHAR, Primitive::kPrimChar);
ARRAY_XX(_SHORT, Primitive::kPrimShort);
+ case Instruction::ARRAY_LENGTH: {
+ HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+ current_block_->AddInstruction(new (arena_) HArrayLength(object));
+ UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
+ break;
+ }
+
default:
return false;
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 7269fff..7731e6e 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -41,10 +41,11 @@ void CodeGenerator::CompileBaseline(CodeAllocator* allocator, bool is_leaf) {
if (!is_leaf) {
MarkNotLeaf();
}
- ComputeFrameSize(GetGraph()->GetMaximumNumberOfOutVRegs()
- + GetGraph()->GetNumberOfLocalVRegs()
- + GetGraph()->GetNumberOfTemporaries()
- + 1 /* filler */);
+ ComputeFrameSize(GetGraph()->GetNumberOfLocalVRegs()
+ + GetGraph()->GetNumberOfTemporaries()
+ + 1 /* filler */,
+ GetGraph()->GetMaximumNumberOfOutVRegs()
+ + 1 /* current method */);
GenerateFrameEntry();
for (size_t i = 0, e = blocks.Size(); i < e; ++i) {
@@ -110,10 +111,10 @@ size_t CodeGenerator::AllocateFreeRegisterInternal(
return -1;
}
-void CodeGenerator::ComputeFrameSize(size_t number_of_spill_slots) {
+void CodeGenerator::ComputeFrameSize(size_t number_of_spill_slots, size_t number_of_out_slots) {
SetFrameSize(RoundUp(
number_of_spill_slots * kVRegSize
- + kVRegSize // Art method
+ + number_of_out_slots * kVRegSize
+ FrameEntrySpillSize(),
kStackAlignment));
}
@@ -376,4 +377,95 @@ void CodeGenerator::BuildVMapTable(std::vector<uint8_t>* data) const {
*data = vmap_encoder.GetData();
}
+void CodeGenerator::BuildStackMaps(std::vector<uint8_t>* data) {
+ uint32_t size = stack_map_stream_.ComputeNeededSize();
+ data->resize(size);
+ MemoryRegion region(data->data(), size);
+ stack_map_stream_.FillIn(region);
+}
+
+void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) {
+ // Collect PC infos for the mapping table.
+ struct PcInfo pc_info;
+ pc_info.dex_pc = dex_pc;
+ pc_info.native_pc = GetAssembler()->CodeSize();
+ pc_infos_.Add(pc_info);
+
+ // Populate stack map information.
+
+ if (instruction == nullptr) {
+ // For stack overflow checks.
+ stack_map_stream_.AddStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, 0);
+ return;
+ }
+
+ LocationSummary* locations = instruction->GetLocations();
+ HEnvironment* environment = instruction->GetEnvironment();
+
+ size_t environment_size = instruction->EnvironmentSize();
+
+ size_t register_mask = 0;
+ size_t inlining_depth = 0;
+ stack_map_stream_.AddStackMapEntry(
+ dex_pc, pc_info.native_pc, register_mask,
+ locations->GetStackMask(), environment_size, inlining_depth);
+
+ // Walk over the environment, and record the location of dex registers.
+ for (size_t i = 0; i < environment_size; ++i) {
+ HInstruction* current = environment->GetInstructionAt(i);
+ if (current == nullptr) {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kNone, 0);
+ continue;
+ }
+
+ Location location = locations->GetEnvironmentAt(i);
+ switch (location.GetKind()) {
+ case Location::kConstant: {
+ DCHECK(current == location.GetConstant());
+ if (current->IsLongConstant()) {
+ int64_t value = current->AsLongConstant()->GetValue();
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, Low32Bits(value));
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, High32Bits(value));
+ ++i;
+ DCHECK_LT(i, environment_size);
+ } else {
+ DCHECK(current->IsIntConstant());
+ int32_t value = current->AsIntConstant()->GetValue();
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, value);
+ }
+ break;
+ }
+
+ case Location::kStackSlot: {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInStack, location.GetStackIndex());
+ break;
+ }
+
+ case Location::kDoubleStackSlot: {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInStack, location.GetStackIndex());
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInStack,
+ location.GetHighStackIndex(kVRegSize));
+ ++i;
+ DCHECK_LT(i, environment_size);
+ break;
+ }
+
+ case Location::kRegister : {
+ int id = location.reg().RegId();
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, id);
+ if (current->GetType() == Primitive::kPrimDouble
+ || current->GetType() == Primitive::kPrimLong) {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, id);
+ ++i;
+ DCHECK_LT(i, environment_size);
+ }
+ break;
+ }
+
+ default:
+ LOG(FATAL) << "Unexpected kind " << location.GetKind();
+ }
+ }
+}
+
} // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 12337c9..a83d703 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -23,6 +23,7 @@
#include "locations.h"
#include "memory_region.h"
#include "nodes.h"
+#include "stack_map_stream.h"
#include "utils/assembler.h"
namespace art {
@@ -97,7 +98,7 @@ class CodeGenerator : public ArenaObject {
virtual HGraphVisitor* GetInstructionVisitor() = 0;
virtual Assembler* GetAssembler() = 0;
virtual size_t GetWordSize() const = 0;
- void ComputeFrameSize(size_t number_of_spill_slots);
+ void ComputeFrameSize(size_t number_of_spill_slots, size_t number_of_out_slots);
virtual size_t FrameEntrySpillSize() const = 0;
int32_t GetStackSlot(HLocal* local) const;
Location GetTemporaryLocation(HTemporary* temp) const;
@@ -114,12 +115,7 @@ class CodeGenerator : public ArenaObject {
virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const = 0;
virtual InstructionSet GetInstructionSet() const = 0;
- void RecordPcInfo(uint32_t dex_pc) {
- struct PcInfo pc_info;
- pc_info.dex_pc = dex_pc;
- pc_info.native_pc = GetAssembler()->CodeSize();
- pc_infos_.Add(pc_info);
- }
+ void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc);
void AddSlowPath(SlowPathCode* slow_path) {
slow_paths_.Add(slow_path);
@@ -131,6 +127,7 @@ class CodeGenerator : public ArenaObject {
void BuildVMapTable(std::vector<uint8_t>* vector) const;
void BuildNativeGCMap(
std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
+ void BuildStackMaps(std::vector<uint8_t>* vector);
bool IsLeafMethod() const {
return is_leaf_;
@@ -149,7 +146,8 @@ class CodeGenerator : public ArenaObject {
pc_infos_(graph->GetArena(), 32),
slow_paths_(graph->GetArena(), 8),
blocked_registers_(graph->GetArena()->AllocArray<bool>(number_of_registers)),
- is_leaf_(true) {}
+ is_leaf_(true),
+ stack_map_stream_(graph->GetArena()) {}
~CodeGenerator() {}
// Register allocation logic.
@@ -184,6 +182,8 @@ class CodeGenerator : public ArenaObject {
bool is_leaf_;
+ StackMapStream stack_map_stream_;
+
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2c954a0..e72e39b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -61,18 +61,18 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
class NullCheckSlowPathARM : public SlowPathCode {
public:
- explicit NullCheckSlowPathARM(uint32_t dex_pc) : dex_pc_(dex_pc) {}
+ explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
__ Bind(GetEntryLabel());
int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
__ ldr(LR, Address(TR, offset));
__ blx(LR);
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HNullCheck* const instruction_;
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
};
@@ -92,10 +92,12 @@ class StackOverflowCheckSlowPathARM : public SlowPathCode {
class BoundsCheckSlowPathARM : public SlowPathCode {
public:
- explicit BoundsCheckSlowPathARM(uint32_t dex_pc,
+ explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction,
Location index_location,
Location length_location)
- : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+ : instruction_(instruction),
+ index_location_(index_location),
+ length_location_(length_location) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
@@ -106,11 +108,11 @@ class BoundsCheckSlowPathARM : public SlowPathCode {
int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
__ ldr(LR, Address(TR, offset));
__ blx(LR);
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HBoundsCheck* const instruction_;
const Location index_location_;
const Location length_location_;
@@ -277,7 +279,7 @@ void CodeGeneratorARM::GenerateFrameEntry() {
} else {
__ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
__ ldr(IP, Address(IP, 0));
- RecordPcInfo(0);
+ RecordPcInfo(nullptr, 0);
}
}
@@ -545,14 +547,14 @@ void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
}
void LocationsBuilderARM::VisitIf(HIf* if_instr) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
HInstruction* cond = if_instr->InputAt(0);
DCHECK(cond->IsCondition());
HCondition* condition = cond->AsCondition();
if (condition->NeedsMaterialization()) {
locations->SetInAt(0, Location::Any());
}
- if_instr->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
@@ -595,13 +597,13 @@ void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
void LocationsBuilderARM::VisitCondition(HCondition* comp) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
if (comp->NeedsMaterialization()) {
locations->SetOut(Location::RequiresRegister());
}
- comp->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
@@ -695,7 +697,8 @@ void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
}
void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
switch (store->InputAt(1)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -713,25 +716,24 @@ void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
default:
LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
}
- store->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
}
void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
}
void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
@@ -747,7 +749,8 @@ void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
}
void LocationsBuilderARM::VisitReturn(HReturn* ret) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
switch (ret->InputAt(0)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -766,8 +769,6 @@ void LocationsBuilderARM::VisitReturn(HReturn* ret) {
default:
LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
}
-
- ret->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
@@ -794,8 +795,8 @@ void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
}
void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
locations->AddTemp(ArmCoreLocation(R0));
InvokeDexCallingConventionVisitor calling_convention_visitor;
@@ -826,8 +827,6 @@ void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
break;
}
-
- invoke->SetLocations(locations);
}
void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
@@ -859,12 +858,13 @@ void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
// LR()
__ blx(LR);
- codegen_->RecordPcInfo(invoke->GetDexPc());
+ codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
}
void LocationsBuilderARM::VisitAdd(HAdd* add) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
switch (add->GetResultType()) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
@@ -884,7 +884,6 @@ void LocationsBuilderARM::VisitAdd(HAdd* add) {
default:
LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
}
- add->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
@@ -924,7 +923,8 @@ void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
}
void LocationsBuilderARM::VisitSub(HSub* sub) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
switch (sub->GetResultType()) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
@@ -944,7 +944,6 @@ void LocationsBuilderARM::VisitSub(HSub* sub) {
default:
LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
}
- sub->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
@@ -985,13 +984,12 @@ void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
}
void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
locations->SetOut(ArmCoreLocation(R0));
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
@@ -1003,12 +1001,13 @@ void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
__ ldr(LR, Address(TR, offset));
__ blx(LR);
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
}
void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
if (location.IsStackSlot()) {
location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
@@ -1016,7 +1015,6 @@ void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
}
locations->SetOut(location);
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
@@ -1024,10 +1022,10 @@ void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instructi
}
void LocationsBuilderARM::VisitNot(HNot* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
@@ -1037,11 +1035,11 @@ void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
}
void LocationsBuilderARM::VisitCompare(HCompare* compare) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- compare->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
@@ -1081,12 +1079,12 @@ void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
}
void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
locations->SetInAt(i, Location::Any());
}
locations->SetOut(Location::Any());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
@@ -1094,22 +1092,22 @@ void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
}
void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// Temporary registers for the write barrier.
- if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
+ if (instruction->GetFieldType() == Primitive::kPrimNot) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsArm().AsCoreRegister();
uint32_t offset = instruction->GetFieldOffset().Uint32Value();
- Primitive::Type field_type = instruction->InputAt(1)->GetType();
+ Primitive::Type field_type = instruction->GetFieldType();
switch (field_type) {
case Primitive::kPrimBoolean:
@@ -1154,10 +1152,10 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instr
}
void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1214,16 +1212,15 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instr
}
void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
- SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction->GetDexPc());
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
codegen_->AddSlowPath(slow_path);
LocationSummary* locations = instruction->GetLocations();
@@ -1237,11 +1234,11 @@ void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
}
void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
@@ -1340,27 +1337,27 @@ void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
}
void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
- if (value_type == Primitive::kPrimNot) {
+ Primitive::Type value_type = instruction->GetComponentType();
+ bool is_object = value_type == Primitive::kPrimNot;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+ instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
+ if (is_object) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
- codegen_->MarkNotLeaf();
} else {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetInAt(2, Location::RequiresRegister());
}
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsArm().AsCoreRegister();
Location index = locations->InAt(1);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ Primitive::Type value_type = instruction->GetComponentType();
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -1408,7 +1405,7 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
__ ldr(LR, Address(TR, offset));
__ blx(LR);
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
break;
}
@@ -1436,10 +1433,10 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
}
void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
@@ -1451,18 +1448,18 @@ void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
}
void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
LocationSummary* locations = instruction->GetLocations();
SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
- instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ instruction, locations->InAt(0), locations->InAt(1));
codegen_->AddSlowPath(slow_path);
Register index = locations->InAt(0).AsArm().AsCoreRegister();
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 35b8116..6602d3f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -61,16 +61,16 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
class NullCheckSlowPathX86 : public SlowPathCode {
public:
- explicit NullCheckSlowPathX86(uint32_t dex_pc) : dex_pc_(dex_pc) {}
+ explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
__ Bind(GetEntryLabel());
__ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HNullCheck* const instruction_;
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
};
@@ -91,10 +91,10 @@ class StackOverflowCheckSlowPathX86 : public SlowPathCode {
class BoundsCheckSlowPathX86 : public SlowPathCode {
public:
- explicit BoundsCheckSlowPathX86(uint32_t dex_pc,
+ explicit BoundsCheckSlowPathX86(HBoundsCheck* instruction,
Location index_location,
Location length_location)
- : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+ : instruction_(instruction), index_location_(index_location), length_location_(length_location) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorX86* x86_codegen = reinterpret_cast<CodeGeneratorX86*>(codegen);
@@ -103,11 +103,11 @@ class BoundsCheckSlowPathX86 : public SlowPathCode {
x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
__ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HBoundsCheck* const instruction_;
const Location index_location_;
const Location length_location_;
@@ -244,7 +244,7 @@ void CodeGeneratorX86::GenerateFrameEntry() {
bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
__ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
- RecordPcInfo(0);
+ RecordPcInfo(nullptr, 0);
}
// The return PC has already been pushed on the stack.
@@ -398,6 +398,7 @@ void CodeGeneratorX86::Move64(Location destination, Location source) {
__ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)));
}
} else {
+ DCHECK(destination.IsDoubleStackSlot());
if (source.IsRegister()) {
__ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
__ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
@@ -503,14 +504,14 @@ void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
}
void LocationsBuilderX86::VisitIf(HIf* if_instr) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
HInstruction* cond = if_instr->InputAt(0);
DCHECK(cond->IsCondition());
HCondition* condition = cond->AsCondition();
if (condition->NeedsMaterialization()) {
locations->SetInAt(0, Location::Any());
}
- if_instr->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
@@ -564,7 +565,8 @@ void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
}
void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
switch (store->InputAt(1)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -589,13 +591,13 @@ void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
}
void LocationsBuilderX86::VisitCondition(HCondition* comp) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::Any());
if (comp->NeedsMaterialization()) {
locations->SetOut(Location::RequiresRegister());
}
- comp->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
@@ -665,18 +667,18 @@ void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* c
}
void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
}
void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
@@ -693,7 +695,8 @@ void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
}
void LocationsBuilderX86::VisitReturn(HReturn* ret) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
switch (ret->InputAt(0)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -712,7 +715,6 @@ void LocationsBuilderX86::VisitReturn(HReturn* ret) {
default:
LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
}
- ret->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
@@ -740,8 +742,8 @@ void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
}
void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
locations->AddTemp(X86CpuLocation(EAX));
InvokeDexCallingConventionVisitor calling_convention_visitor;
@@ -799,11 +801,12 @@ void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
__ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke->GetDexPc());
+ codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86::VisitAdd(HAdd* add) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
switch (add->GetResultType()) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
@@ -823,7 +826,6 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) {
default:
LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
}
- add->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
@@ -876,7 +878,8 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
}
void LocationsBuilderX86::VisitSub(HSub* sub) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
switch (sub->GetResultType()) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
@@ -896,7 +899,6 @@ void LocationsBuilderX86::VisitSub(HSub* sub) {
default:
LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
}
- sub->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
@@ -949,13 +951,12 @@ void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
}
void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
locations->SetOut(X86CpuLocation(EAX));
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(0)));
locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(1)));
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
@@ -966,12 +967,13 @@ void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
__ fs()->call(
Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
}
void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
if (location.IsStackSlot()) {
location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
@@ -979,17 +981,16 @@ void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
}
locations->SetOut(location);
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
}
void LocationsBuilderX86::VisitNot(HNot* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
@@ -1000,11 +1001,11 @@ void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
}
void LocationsBuilderX86::VisitCompare(HCompare* compare) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::Any());
locations->SetOut(Location::RequiresRegister());
- compare->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
@@ -1050,12 +1051,12 @@ void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
}
void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
locations->SetInAt(i, Location::Any());
}
locations->SetOut(Location::Any());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
@@ -1063,9 +1064,10 @@ void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
}
void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
- Primitive::Type field_type = instruction->InputAt(1)->GetType();
+ Primitive::Type field_type = instruction->GetFieldType();
if (field_type == Primitive::kPrimBoolean || field_type == Primitive::kPrimByte) {
// Ensure the value is in a byte register.
locations->SetInAt(1, X86CpuLocation(EAX));
@@ -1078,14 +1080,13 @@ void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction)
// Ensure the card is in a byte register.
locations->AddTemp(X86CpuLocation(ECX));
}
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsX86().AsCpuRegister();
uint32_t offset = instruction->GetFieldOffset().Uint32Value();
- Primitive::Type field_type = instruction->InputAt(1)->GetType();
+ Primitive::Type field_type = instruction->GetFieldType();
switch (field_type) {
case Primitive::kPrimBoolean:
@@ -1144,10 +1145,10 @@ void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object,
}
void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1205,16 +1206,15 @@ void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instr
}
void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::Any());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
- SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction->GetDexPc());
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
codegen_->AddSlowPath(slow_path);
LocationSummary* locations = instruction->GetLocations();
@@ -1231,11 +1231,11 @@ void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
}
void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
@@ -1331,14 +1331,16 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
}
void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ Primitive::Type value_type = instruction->GetComponentType();
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+ instruction,
+ value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
+
if (value_type == Primitive::kPrimNot) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, X86CpuLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, X86CpuLocation(calling_convention.GetRegisterAt(1)));
locations->SetInAt(2, X86CpuLocation(calling_convention.GetRegisterAt(2)));
- codegen_->MarkNotLeaf();
} else {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
@@ -1349,15 +1351,13 @@ void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
locations->SetInAt(2, Location::RequiresRegister());
}
}
-
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsX86().AsCpuRegister();
Location index = locations->InAt(1);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ Primitive::Type value_type = instruction->GetComponentType();
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -1401,7 +1401,7 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
case Primitive::kPrimNot: {
DCHECK(!codegen_->IsLeafMethod());
__ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
break;
}
@@ -1446,18 +1446,18 @@ void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
}
void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
LocationSummary* locations = instruction->GetLocations();
SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
- instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ instruction, locations->InAt(0), locations->InAt(1));
codegen_->AddSlowPath(slow_path);
Register index = locations->InAt(0).AsX86().AsCpuRegister();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index c4571ca..b2d81e3 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -65,17 +65,17 @@ class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
class NullCheckSlowPathX86_64 : public SlowPathCode {
public:
- explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
+ explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
__ Bind(GetEntryLabel());
__ gs()->call(
Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HNullCheck* const instruction_;
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
};
@@ -97,10 +97,12 @@ class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
class BoundsCheckSlowPathX86_64 : public SlowPathCode {
public:
- explicit BoundsCheckSlowPathX86_64(uint32_t dex_pc,
+ explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
Location index_location,
Location length_location)
- : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+ : instruction_(instruction),
+ index_location_(index_location),
+ length_location_(length_location) {}
virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
@@ -110,11 +112,11 @@ class BoundsCheckSlowPathX86_64 : public SlowPathCode {
x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
__ gs()->call(Address::Absolute(
QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
- codegen->RecordPcInfo(dex_pc_);
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
}
private:
- const uint32_t dex_pc_;
+ HBoundsCheck* const instruction_;
const Location index_location_;
const Location length_location_;
@@ -214,7 +216,7 @@ void CodeGeneratorX86_64::GenerateFrameEntry() {
if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
__ testq(CpuRegister(RAX), Address(
CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
- RecordPcInfo(0);
+ RecordPcInfo(nullptr, 0);
}
// The return PC has already been pushed on the stack.
@@ -385,14 +387,14 @@ void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
}
void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
HInstruction* cond = if_instr->InputAt(0);
DCHECK(cond->IsCondition());
HCondition* condition = cond->AsCondition();
if (condition->NeedsMaterialization()) {
locations->SetInAt(0, Location::Any());
}
- if_instr->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
@@ -444,7 +446,8 @@ void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
}
void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
switch (store->InputAt(1)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -462,20 +465,19 @@ void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
default:
LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
}
- store->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
}
void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::Any());
if (comp->NeedsMaterialization()) {
locations->SetOut(Location::RequiresRegister());
}
- comp->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
@@ -545,11 +547,11 @@ void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual
}
void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- compare->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
@@ -578,18 +580,18 @@ void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
}
void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
}
void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
locations->SetOut(Location::ConstantLocation(constant));
- constant->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
@@ -605,7 +607,8 @@ void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
}
void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
switch (ret->InputAt(0)->GetType()) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
@@ -620,7 +623,6 @@ void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
default:
LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
}
- ret->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
@@ -686,8 +688,8 @@ Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type
}
void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
locations->AddTemp(X86_64CpuLocation(RDI));
InvokeDexCallingConventionVisitor calling_convention_visitor;
@@ -715,8 +717,6 @@ void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
break;
}
-
- invoke->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
@@ -742,11 +742,12 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
__ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke->GetDexPc());
+ codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
switch (add->GetResultType()) {
case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -771,7 +772,6 @@ void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
default:
LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
}
- add->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
@@ -812,7 +812,8 @@ void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
}
void LocationsBuilderX86_64::VisitSub(HSub* sub) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
switch (sub->GetResultType()) {
case Primitive::kPrimInt: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -837,7 +838,6 @@ void LocationsBuilderX86_64::VisitSub(HSub* sub) {
default:
LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
}
- sub->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
@@ -878,10 +878,9 @@ void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
}
void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
- codegen_->MarkNotLeaf();
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
locations->SetOut(X86_64CpuLocation(RAX));
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
@@ -893,11 +892,12 @@ void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction)
QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
}
void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
if (location.IsStackSlot()) {
location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
@@ -905,7 +905,6 @@ void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
}
locations->SetOut(location);
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
@@ -913,10 +912,10 @@ void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instru
}
void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
@@ -927,12 +926,12 @@ void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
}
void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
locations->SetInAt(i, Location::Any());
}
locations->SetOut(Location::Any());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
@@ -940,15 +939,15 @@ void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
}
void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// Temporary registers for the write barrier.
- if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
+ if (instruction->GetFieldType() == Primitive::kPrimNot) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -956,7 +955,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* in
CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
size_t offset = instruction->GetFieldOffset().SizeValue();
- Primitive::Type field_type = instruction->InputAt(1)->GetType();
+ Primitive::Type field_type = instruction->GetFieldType();
switch (field_type) {
case Primitive::kPrimBoolean:
@@ -997,10 +996,10 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* in
}
void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1051,16 +1050,15 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* in
}
void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::Any());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
- SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
codegen_->AddSlowPath(slow_path);
LocationSummary* locations = instruction->GetLocations();
@@ -1077,11 +1075,11 @@ void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
}
void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
@@ -1174,27 +1172,27 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
}
void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
- if (value_type == Primitive::kPrimNot) {
+ Primitive::Type value_type = instruction->GetComponentType();
+ bool is_object = value_type == Primitive::kPrimNot;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+ instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
+ if (is_object) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
- codegen_->MarkNotLeaf();
} else {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetInAt(2, Location::RequiresRegister());
}
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
LocationSummary* locations = instruction->GetLocations();
CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
Location index = locations->InAt(1);
- Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ Primitive::Type value_type = instruction->GetComponentType();
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -1238,7 +1236,7 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
case Primitive::kPrimNot: {
__ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(instruction->GetDexPc());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
break;
}
@@ -1264,10 +1262,10 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
}
void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
@@ -1279,18 +1277,18 @@ void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction)
}
void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
- LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// TODO: Have a normalization phase that makes this instruction never used.
locations->SetOut(Location::SameAsFirstInput());
- instruction->SetLocations(locations);
}
void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
LocationSummary* locations = instruction->GetLocations();
SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
- instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ instruction, locations->InAt(0), locations->InAt(1));
codegen_->AddSlowPath(slow_path);
CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 468cfb7..fce97bd 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -20,13 +20,29 @@
namespace art {
-LocationSummary::LocationSummary(HInstruction* instruction)
+LocationSummary::LocationSummary(HInstruction* instruction, CallKind call_kind)
: inputs_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
- temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0) {
+ temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0),
+ environment_(instruction->GetBlock()->GetGraph()->GetArena(),
+ instruction->EnvironmentSize()),
+ call_kind_(call_kind),
+ stack_mask_(nullptr),
+ register_mask_(0),
+ live_registers_(0) {
inputs_.SetSize(instruction->InputCount());
- for (size_t i = 0; i < instruction->InputCount(); i++) {
+ for (size_t i = 0; i < instruction->InputCount(); ++i) {
inputs_.Put(i, Location());
}
+ environment_.SetSize(instruction->EnvironmentSize());
+ for (size_t i = 0; i < instruction->EnvironmentSize(); ++i) {
+ environment_.Put(i, Location());
+ }
+ instruction->SetLocations(this);
+
+ if (NeedsSafepoint()) {
+ ArenaAllocator* arena = instruction->GetBlock()->GetGraph()->GetArena();
+ stack_mask_ = new (arena) ArenaBitVector(arena, 0, true);
+ }
}
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index aaddb09..041e85b 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_LOCATIONS_H_
#include "base/bit_field.h"
+#include "base/bit_vector.h"
#include "utils/allocation.h"
#include "utils/growable_array.h"
#include "utils/managed_register.h"
@@ -43,13 +44,13 @@ class Location : public ValueObject {
// low bits are in the last parameter register, and the high
// bits are in a stack slot. The kQuickParameter kind is for
// handling this special case.
- kQuickParameter = 5,
+ kQuickParameter = 6,
// Unallocated location represents a location that is not fixed and can be
// allocated by a register allocator. Each unallocated location has
// a policy that specifies what kind of location is suitable. Payload
// contains register allocation policy.
- kUnallocated = 6,
+ kUnallocated = 7,
};
Location() : value_(kInvalid) {
@@ -59,8 +60,8 @@ class Location : public ValueObject {
COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kConstant, TagError);
COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kConstant, TagError);
COMPILE_ASSERT((kRegister & kLocationTagMask) != kConstant, TagError);
+ COMPILE_ASSERT((kQuickParameter & kLocationTagMask) != kConstant, TagError);
COMPILE_ASSERT((kConstant & kLocationTagMask) == kConstant, TagError);
- COMPILE_ASSERT((kQuickParameter & kLocationTagMask) == kConstant, TagError);
DCHECK(!IsValid());
}
@@ -173,7 +174,7 @@ class Location : public ValueObject {
x86_64::X86_64ManagedRegister AsX86_64() const;
Kind GetKind() const {
- return KindField::Decode(value_);
+ return IsConstant() ? kConstant : KindField::Decode(value_);
}
bool Equals(Location other) const {
@@ -275,7 +276,13 @@ class Location : public ValueObject {
*/
class LocationSummary : public ArenaObject {
public:
- explicit LocationSummary(HInstruction* instruction);
+ enum CallKind {
+ kNoCall,
+ kCallOnSlowPath,
+ kCall
+ };
+
+ explicit LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
void SetInAt(uint32_t at, Location location) {
inputs_.Put(at, location);
@@ -309,12 +316,50 @@ class LocationSummary : public ArenaObject {
return temps_.Size();
}
+ void SetEnvironmentAt(uint32_t at, Location location) {
+ environment_.Put(at, location);
+ }
+
+ Location GetEnvironmentAt(uint32_t at) const {
+ return environment_.Get(at);
+ }
+
Location Out() const { return output_; }
+ bool CanCall() const { return call_kind_ != kNoCall; }
+ bool NeedsSafepoint() const { return CanCall(); }
+
+ void SetStackBit(uint32_t index) {
+ stack_mask_->SetBit(index);
+ }
+
+ void SetRegisterBit(uint32_t reg_id) {
+ register_mask_ |= (1 << reg_id);
+ }
+
+ void SetLiveRegister(uint32_t reg_id) {
+ live_registers_ |= (1 << reg_id);
+ }
+
+ BitVector* GetStackMask() const {
+ return stack_mask_;
+ }
+
private:
GrowableArray<Location> inputs_;
GrowableArray<Location> temps_;
+ GrowableArray<Location> environment_;
Location output_;
+ const CallKind call_kind_;
+
+ // Mask of objects that live in the stack.
+ BitVector* stack_mask_;
+
+ // Mask of objects that live in register.
+ uint32_t register_mask_;
+
+ // Registers that are in use at this position.
+ uint32_t live_registers_;
DISALLOW_COPY_AND_ASSIGN(LocationSummary);
};
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 490d345..f07029d 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -414,6 +414,10 @@ void HInstruction::ReplaceWith(HInstruction* other) {
env_uses_ = nullptr;
}
+size_t HInstruction::EnvironmentSize() const {
+ return HasEnvironment() ? environment_->Size() : 0;
+}
+
void HPhi::AddInput(HInstruction* input) {
DCHECK(input->GetBlock() != nullptr);
inputs_.Add(input);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index bb699e4..ea0cacc 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -554,6 +554,10 @@ class HInstruction : public ArenaObject {
HEnvironment* GetEnvironment() const { return environment_; }
void SetEnvironment(HEnvironment* environment) { environment_ = environment; }
+ // Returns the number of entries in the environment. Typically, that is the
+ // number of dex registers in a method. It could be more in case of inlining.
+ size_t EnvironmentSize() const;
+
LocationSummary* GetLocations() const { return locations_; }
void SetLocations(LocationSummary* locations) { locations_ = locations; }
@@ -583,7 +587,7 @@ class HInstruction : public ArenaObject {
// An instruction gets an id when it is added to the graph.
// It reflects creation order. A negative id means the instruction
- // has not beed added to the graph.
+ // has not been added to the graph.
int id_;
// When doing liveness analysis, instructions that have uses get an SSA index.
@@ -595,6 +599,8 @@ class HInstruction : public ArenaObject {
// List of environments that contain this instruction.
HUseListNode<HEnvironment>* env_uses_;
+ // The environment associated with this instruction. Not null if the instruction
+ // might jump out of the method.
HEnvironment* environment_;
// Set by the code generator.
@@ -660,10 +666,16 @@ class HEnvironment : public ArenaObject {
vregs_.Put(index, instruction);
}
+ HInstruction* GetInstructionAt(size_t index) const {
+ return vregs_.Get(index);
+ }
+
GrowableArray<HInstruction*>* GetVRegs() {
return &vregs_;
}
+ size_t Size() const { return vregs_.Size(); }
+
private:
GrowableArray<HInstruction*> vregs_;
@@ -1324,13 +1336,15 @@ class HNullCheck : public HExpression<1> {
class FieldInfo : public ValueObject {
public:
- explicit FieldInfo(MemberOffset field_offset)
- : field_offset_(field_offset) {}
+ explicit FieldInfo(MemberOffset field_offset, Primitive::Type field_type)
+ : field_offset_(field_offset), field_type_(field_type) {}
MemberOffset GetFieldOffset() const { return field_offset_; }
+ Primitive::Type GetFieldType() const { return field_type_; }
private:
const MemberOffset field_offset_;
+ const Primitive::Type field_type_;
};
class HInstanceFieldGet : public HExpression<1> {
@@ -1338,11 +1352,12 @@ class HInstanceFieldGet : public HExpression<1> {
HInstanceFieldGet(HInstruction* value,
Primitive::Type field_type,
MemberOffset field_offset)
- : HExpression(field_type), field_info_(field_offset) {
+ : HExpression(field_type), field_info_(field_offset, field_type) {
SetRawInputAt(0, value);
}
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
+ Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
DECLARE_INSTRUCTION(InstanceFieldGet);
@@ -1356,13 +1371,15 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
public:
HInstanceFieldSet(HInstruction* object,
HInstruction* value,
+ Primitive::Type field_type,
MemberOffset field_offset)
- : field_info_(field_offset) {
+ : field_info_(field_offset, field_type) {
SetRawInputAt(0, object);
SetRawInputAt(1, value);
}
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
+ Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
DECLARE_INSTRUCTION(InstanceFieldSet);
@@ -1391,7 +1408,8 @@ class HArraySet : public HTemplateInstruction<3> {
HArraySet(HInstruction* array,
HInstruction* index,
HInstruction* value,
- uint32_t dex_pc) : dex_pc_(dex_pc) {
+ Primitive::Type component_type,
+ uint32_t dex_pc) : dex_pc_(dex_pc), component_type_(component_type) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
@@ -1405,10 +1423,13 @@ class HArraySet : public HTemplateInstruction<3> {
uint32_t GetDexPc() const { return dex_pc_; }
+ Primitive::Type GetComponentType() const { return component_type_; }
+
DECLARE_INSTRUCTION(ArraySet);
private:
const uint32_t dex_pc_;
+ const Primitive::Type component_type_;
DISALLOW_COPY_AND_ASSIGN(HArraySet);
};
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 3461276..75f4155 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -240,8 +240,27 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
visualizer.DumpGraph(kRegisterAllocatorPassName);
codegen->CompileOptimized(&allocator);
+
+ std::vector<uint8_t> mapping_table;
+ SrcMap src_mapping_table;
+ codegen->BuildMappingTable(&mapping_table,
+ GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
+ &src_mapping_table : nullptr);
+
+ std::vector<uint8_t> stack_map;
+ codegen->BuildStackMaps(&stack_map);
+
+ return new CompiledMethod(GetCompilerDriver(),
+ instruction_set,
+ allocator.GetMemory(),
+ codegen->GetFrameSize(),
+ codegen->GetCoreSpillMask(),
+ 0, /* FPR spill mask, unused */
+ mapping_table,
+ stack_map);
} else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
LOG(FATAL) << "Could not allocate registers in optimizing compiler";
+ return nullptr;
} else {
codegen->CompileBaseline(&allocator);
@@ -253,29 +272,29 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
SsaLivenessAnalysis liveness(*graph, codegen);
liveness.Analyze();
visualizer.DumpGraph(kLivenessPassName);
- }
- std::vector<uint8_t> mapping_table;
- SrcMap src_mapping_table;
- codegen->BuildMappingTable(&mapping_table,
- GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
- &src_mapping_table : nullptr);
- std::vector<uint8_t> vmap_table;
- codegen->BuildVMapTable(&vmap_table);
- std::vector<uint8_t> gc_map;
- codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
-
- return new CompiledMethod(GetCompilerDriver(),
- instruction_set,
- allocator.GetMemory(),
- codegen->GetFrameSize(),
- codegen->GetCoreSpillMask(),
- 0, /* FPR spill mask, unused */
- &src_mapping_table,
- mapping_table,
- vmap_table,
- gc_map,
- nullptr);
+ std::vector<uint8_t> mapping_table;
+ SrcMap src_mapping_table;
+ codegen->BuildMappingTable(&mapping_table,
+ GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
+ &src_mapping_table : nullptr);
+ std::vector<uint8_t> vmap_table;
+ codegen->BuildVMapTable(&vmap_table);
+ std::vector<uint8_t> gc_map;
+ codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
+
+ return new CompiledMethod(GetCompilerDriver(),
+ instruction_set,
+ allocator.GetMemory(),
+ codegen->GetFrameSize(),
+ codegen->GetCoreSpillMask(),
+ 0, /* FPR spill mask, unused */
+ &src_mapping_table,
+ mapping_table,
+ vmap_table,
+ gc_map,
+ nullptr);
+ }
}
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index da13b1e..54888ba 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -31,18 +31,26 @@ RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
: allocator_(allocator),
codegen_(codegen),
liveness_(liveness),
- unhandled_(allocator, 0),
+ unhandled_core_intervals_(allocator, 0),
+ unhandled_fp_intervals_(allocator, 0),
+ unhandled_(nullptr),
handled_(allocator, 0),
active_(allocator, 0),
inactive_(allocator, 0),
physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
+ temp_intervals_(allocator, 4),
spill_slots_(allocator, kDefaultNumberOfSpillSlots),
+ safepoints_(allocator, 0),
processing_core_registers_(false),
number_of_registers_(-1),
registers_array_(nullptr),
- blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())) {
+ blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())),
+ reserved_out_slots_(0) {
codegen->SetupBlockedRegisters(blocked_registers_);
physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
+ // Always reserve for the current method and the graph's max out registers.
+ // TODO: compute it instead.
+ reserved_out_slots_ = 1 + codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
}
bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
@@ -55,7 +63,6 @@ bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
!it.Done();
it.Advance()) {
HInstruction* current = it.Current();
- if (current->NeedsEnvironment()) return false;
if (current->GetType() == Primitive::kPrimLong && instruction_set != kX86_64) return false;
if (current->GetType() == Primitive::kPrimFloat) return false;
if (current->GetType() == Primitive::kPrimDouble) return false;
@@ -65,17 +72,14 @@ bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
}
static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
+ if (interval == nullptr) return false;
bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
&& (interval->GetType() != Primitive::kPrimFloat);
return processing_core_registers == is_core_register;
}
void RegisterAllocator::AllocateRegisters() {
- processing_core_registers_ = true;
- AllocateRegistersInternal();
- processing_core_registers_ = false;
AllocateRegistersInternal();
-
Resolve();
if (kIsDebugBuild) {
@@ -101,78 +105,120 @@ void RegisterAllocator::BlockRegister(Location location,
interval->AddRange(start, end);
}
-// TODO: make the register allocator understand instructions like HCondition
-// that may not need to be materialized. It doesn't need to allocate any
-// registers for it.
void RegisterAllocator::AllocateRegistersInternal() {
- number_of_registers_ = processing_core_registers_
- ? codegen_->GetNumberOfCoreRegisters()
- : codegen_->GetNumberOfFloatingPointRegisters();
+ // Iterate post-order, to ensure the list is sorted, and the last added interval
+ // is the one with the lowest start position.
+ for (HLinearPostOrderIterator it(liveness_); !it.Done(); it.Advance()) {
+ HBasicBlock* block = it.Current();
+ for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ ProcessInstruction(it.Current());
+ }
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ ProcessInstruction(it.Current());
+ }
+ }
+ number_of_registers_ = codegen_->GetNumberOfCoreRegisters();
registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
+ processing_core_registers_ = true;
+ unhandled_ = &unhandled_core_intervals_;
+ LinearScan();
- // Iterate post-order, to ensure the list is sorted, and the last added interval
- // is the one with the lowest start position.
- for (size_t i = liveness_.GetNumberOfSsaValues(); i > 0; --i) {
- HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i - 1);
- LiveInterval* current = instruction->GetLiveInterval();
- if (ShouldProcess(processing_core_registers_, current)) {
- DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
-
- LocationSummary* locations = instruction->GetLocations();
- if (locations->GetTempCount() != 0) {
- // Note that we already filtered out instructions requiring temporaries in
- // RegisterAllocator::CanAllocateRegistersFor.
- LOG(FATAL) << "Unimplemented";
- }
+ inactive_.Reset();
+ active_.Reset();
+ handled_.Reset();
- // Some instructions define their output in fixed register/stack slot. We need
- // to ensure we know these locations before doing register allocation. For a
- // given register, we create an interval that covers these locations. The register
- // will be unavailable at these locations when trying to allocate one for an
- // interval.
- //
- // The backwards walking ensures the ranges are ordered on increasing start positions.
- Location output = locations->Out();
- size_t position = instruction->GetLifetimePosition();
- if (output.IsRegister()) {
- // Shift the interval's start by one to account for the blocked register.
- current->SetFrom(position + 1);
- current->SetRegister(output.reg().RegId());
- BlockRegister(output, position, position + 1, instruction->GetType());
- } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
- current->SetSpillSlot(output.GetStackIndex());
- }
- for (size_t i = 0; i < instruction->InputCount(); ++i) {
- Location input = locations->InAt(i);
- if (input.IsRegister()) {
- BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
- }
- }
+ number_of_registers_ = codegen_->GetNumberOfFloatingPointRegisters();
+ registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
+ processing_core_registers_ = false;
+ unhandled_ = &unhandled_fp_intervals_;
+ // TODO: Enable FP register allocation.
+ DCHECK(unhandled_->IsEmpty());
+ LinearScan();
+}
- // Add the interval to the correct list.
- if (current->HasRegister()) {
- DCHECK(instruction->IsParameterValue());
- inactive_.Add(current);
- } else if (current->HasSpillSlot() || instruction->IsConstant()) {
- // Split before first register use.
- size_t first_register_use = current->FirstRegisterUse();
- if (first_register_use != kNoLifetime) {
- LiveInterval* split = Split(current, first_register_use - 1);
- // Don't add direclty to `unhandled_`, it needs to be sorted and the start
- // of this new interval might be after intervals already in the list.
- AddToUnhandled(split);
- } else {
- // Nothing to do, we won't allocate a register for this value.
- }
- } else {
- DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
- unhandled_.Add(current);
- }
+void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ size_t position = instruction->GetLifetimePosition();
+
+ if (locations == nullptr) return;
+
+ // Create synthesized intervals for temporaries.
+ for (size_t i = 0; i < locations->GetTempCount(); ++i) {
+ Location temp = locations->GetTemp(i);
+ if (temp.IsRegister()) {
+ BlockRegister(temp, position, position + 1, Primitive::kPrimInt);
+ } else {
+ LiveInterval* interval =
+ LiveInterval::MakeTempInterval(allocator_, instruction, Primitive::kPrimInt);
+ temp_intervals_.Add(interval);
+ interval->AddRange(position, position + 1);
+ unhandled_core_intervals_.Add(interval);
}
}
- LinearScan();
+ if (locations->CanCall()) {
+ codegen_->MarkNotLeaf();
+ safepoints_.Add(instruction);
+ // Block all registers.
+ for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
+ BlockRegister(Location::RegisterLocation(ManagedRegister(i)),
+ position,
+ position + 1,
+ Primitive::kPrimInt);
+ }
+ }
+
+ for (size_t i = 0; i < instruction->InputCount(); ++i) {
+ Location input = locations->InAt(i);
+ if (input.IsRegister()) {
+ BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
+ }
+ }
+
+ bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
+ && (instruction->GetType() != Primitive::kPrimFloat);
+ GrowableArray<LiveInterval*>& unhandled = core_register
+ ? unhandled_core_intervals_
+ : unhandled_fp_intervals_;
+
+ LiveInterval* current = instruction->GetLiveInterval();
+ if (current == nullptr) return;
+
+ DCHECK(unhandled.IsEmpty() || current->StartsBefore(unhandled.Peek()));
+ // Some instructions define their output in fixed register/stack slot. We need
+ // to ensure we know these locations before doing register allocation. For a
+ // given register, we create an interval that covers these locations. The register
+ // will be unavailable at these locations when trying to allocate one for an
+ // interval.
+ //
+ // The backwards walking ensures the ranges are ordered on increasing start positions.
+ Location output = locations->Out();
+ if (output.IsRegister()) {
+ // Shift the interval's start by one to account for the blocked register.
+ current->SetFrom(position + 1);
+ current->SetRegister(output.reg().RegId());
+ BlockRegister(output, position, position + 1, instruction->GetType());
+ } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
+ current->SetSpillSlot(output.GetStackIndex());
+ }
+
+ // If needed, add interval to the list of unhandled intervals.
+ if (current->HasSpillSlot() || instruction->IsConstant()) {
+ // Split before first register use.
+ size_t first_register_use = current->FirstRegisterUse();
+ if (first_register_use != kNoLifetime) {
+ LiveInterval* split = Split(current, first_register_use - 1);
+ // Don't add direclty to `unhandled`, it needs to be sorted and the start
+ // of this new interval might be after intervals already in the list.
+ AddSorted(&unhandled, split);
+ } else {
+ // Nothing to do, we won't allocate a register for this value.
+ }
+ } else {
+ DCHECK(unhandled.IsEmpty() || current->StartsBefore(unhandled.Peek()));
+ unhandled.Add(current);
+ }
}
class AllRangesIterator : public ValueObject {
@@ -220,12 +266,20 @@ bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
}
}
- return ValidateIntervals(intervals, spill_slots_.Size(), *codegen_, allocator_,
- processing_core_registers_, log_fatal_on_failure);
+ for (size_t i = 0, e = temp_intervals_.Size(); i < e; ++i) {
+ LiveInterval* temp = temp_intervals_.Get(i);
+ if (ShouldProcess(processing_core_registers_, temp)) {
+ intervals.Add(temp);
+ }
+ }
+
+ return ValidateIntervals(intervals, spill_slots_.Size(), reserved_out_slots_, *codegen_,
+ allocator_, processing_core_registers_, log_fatal_on_failure);
}
bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
size_t number_of_spill_slots,
+ size_t number_of_out_slots,
const CodeGenerator& codegen,
ArenaAllocator* allocator,
bool processing_core_registers,
@@ -249,8 +303,9 @@ bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& in
if (current->GetParent()->HasSpillSlot()
// Parameters have their own stack slot.
&& !(defined_by != nullptr && defined_by->IsParameterValue())) {
- BitVector* liveness_of_spill_slot = liveness_of_values.Get(
- number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize);
+ BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
+ + current->GetParent()->GetSpillSlot() / kVRegSize
+ - number_of_out_slots);
for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
if (liveness_of_spill_slot->IsBitSet(j)) {
if (log_fatal_on_failure) {
@@ -272,7 +327,11 @@ bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& in
if (liveness_of_register->IsBitSet(j)) {
if (log_fatal_on_failure) {
std::ostringstream message;
- message << "Register conflict at " << j << " for ";
+ message << "Register conflict at " << j << " ";
+ if (defined_by != nullptr) {
+ message << "(" << defined_by->DebugName() << ")";
+ }
+ message << "for ";
if (processing_core_registers) {
codegen.DumpCoreRegister(message, current->GetRegister());
} else {
@@ -309,10 +368,10 @@ void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interva
// By the book implementation of a linear scan register allocator.
void RegisterAllocator::LinearScan() {
- while (!unhandled_.IsEmpty()) {
+ while (!unhandled_->IsEmpty()) {
// (1) Remove interval with the lowest start position from unhandled.
- LiveInterval* current = unhandled_.Pop();
- DCHECK(!current->IsFixed() && !current->HasRegister() && !current->HasSpillSlot());
+ LiveInterval* current = unhandled_->Pop();
+ DCHECK(!current->IsFixed() && !current->HasSpillSlot());
size_t position = current->GetStart();
// (2) Remove currently active intervals that are dead at this position.
@@ -392,13 +451,19 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
free_until[interval->GetRegister()] = 0;
}
- // Pick the register that is free the longest.
int reg = -1;
- for (size_t i = 0; i < number_of_registers_; ++i) {
- if (IsBlocked(i)) continue;
- if (reg == -1 || free_until[i] > free_until[reg]) {
- reg = i;
- if (free_until[i] == kMaxLifetimePosition) break;
+ if (current->HasRegister()) {
+ // Some instructions have a fixed register output.
+ reg = current->GetRegister();
+ DCHECK_NE(free_until[reg], 0u);
+ } else {
+ // Pick the register that is free the longest.
+ for (size_t i = 0; i < number_of_registers_; ++i) {
+ if (IsBlocked(i)) continue;
+ if (reg == -1 || free_until[i] > free_until[reg]) {
+ reg = i;
+ if (free_until[i] == kMaxLifetimePosition) break;
+ }
}
}
@@ -414,7 +479,7 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveInterval* current) {
// the register is not available anymore.
LiveInterval* split = Split(current, free_until[reg]);
DCHECK(split != nullptr);
- AddToUnhandled(split);
+ AddSorted(unhandled_, split);
}
return true;
}
@@ -493,7 +558,7 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
// register, we split this interval just before its first register use.
AllocateSpillSlotFor(current);
LiveInterval* split = Split(current, first_register_use - 1);
- AddToUnhandled(split);
+ AddSorted(unhandled_, split);
return false;
} else {
// Use this register and spill the active and inactives interval that
@@ -507,7 +572,7 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
LiveInterval* split = Split(active, current->GetStart());
active_.DeleteAt(i);
handled_.Add(active);
- AddToUnhandled(split);
+ AddSorted(unhandled_, split);
break;
}
}
@@ -519,12 +584,12 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
if (next_intersection != kNoLifetime) {
if (inactive->IsFixed()) {
LiveInterval* split = Split(current, next_intersection);
- AddToUnhandled(split);
+ AddSorted(unhandled_, split);
} else {
LiveInterval* split = Split(inactive, current->GetStart());
inactive_.DeleteAt(i);
handled_.Add(inactive);
- AddToUnhandled(split);
+ AddSorted(unhandled_, split);
--i;
}
}
@@ -535,16 +600,16 @@ bool RegisterAllocator::AllocateBlockedReg(LiveInterval* current) {
}
}
-void RegisterAllocator::AddToUnhandled(LiveInterval* interval) {
+void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
size_t insert_at = 0;
- for (size_t i = unhandled_.Size(); i > 0; --i) {
- LiveInterval* current = unhandled_.Get(i - 1);
+ for (size_t i = array->Size(); i > 0; --i) {
+ LiveInterval* current = array->Get(i - 1);
if (current->StartsAfter(interval)) {
insert_at = i;
break;
}
}
- unhandled_.InsertAt(insert_at, interval);
+ array->InsertAt(insert_at, interval);
}
LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
@@ -624,7 +689,7 @@ void RegisterAllocator::AllocateTwoSpillSlots(LiveInterval* parent, size_t end)
spill_slots_.Put(slot + 1, end);
}
- parent->SetSpillSlot(slot * kVRegSize);
+ parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
}
void RegisterAllocator::AllocateOneSpillSlot(LiveInterval* parent, size_t end) {
@@ -643,7 +708,7 @@ void RegisterAllocator::AllocateOneSpillSlot(LiveInterval* parent, size_t end) {
spill_slots_.Put(slot, end);
}
- parent->SetSpillSlot(slot * kVRegSize);
+ parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
}
static Location ConvertToLocation(LiveInterval* interval) {
@@ -820,8 +885,10 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
// Walk over all uses covered by this interval, and update the location
// information.
while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
- if (!use->GetIsEnvironment()) {
- LocationSummary* locations = use->GetUser()->GetLocations();
+ LocationSummary* locations = use->GetUser()->GetLocations();
+ if (use->GetIsEnvironment()) {
+ locations->SetEnvironmentAt(use->GetInputIndex(), source);
+ } else {
Location expected_location = locations->InAt(use->GetInputIndex());
if (expected_location.IsUnallocated()) {
locations->SetInAt(use->GetInputIndex(), source);
@@ -841,6 +908,38 @@ void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
Location destination = ConvertToLocation(next_sibling);
InsertParallelMoveAt(current->GetEnd(), source, destination);
}
+
+ // At each safepoint, we record stack and register information.
+ for (size_t i = 0, e = safepoints_.Size(); i < e; ++i) {
+ HInstruction* safepoint = safepoints_.Get(i);
+ size_t position = safepoint->GetLifetimePosition();
+ LocationSummary* locations = safepoint->GetLocations();
+ if (!current->Covers(position)) continue;
+
+ if (current->GetType() == Primitive::kPrimNot) {
+ DCHECK(current->GetParent()->HasSpillSlot());
+ locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
+ }
+
+ switch (source.GetKind()) {
+ case Location::kRegister: {
+ locations->SetLiveRegister(source.reg().RegId());
+ if (current->GetType() == Primitive::kPrimNot) {
+ locations->SetRegisterBit(source.reg().RegId());
+ }
+ break;
+ }
+ case Location::kStackSlot: // Fall-through
+ case Location::kDoubleStackSlot: // Fall-through
+ case Location::kConstant: {
+ // Nothing to do.
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unexpected location for object";
+ }
+ }
+ }
current = next_sibling;
} while (current != nullptr);
DCHECK(use == nullptr);
@@ -907,7 +1006,7 @@ static Location FindLocationAt(LiveInterval* interval, size_t position) {
}
void RegisterAllocator::Resolve() {
- codegen_->ComputeFrameSize(spill_slots_.Size());
+ codegen_->ComputeFrameSize(spill_slots_.Size(), reserved_out_slots_);
// Adjust the Out Location of instructions.
// TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
@@ -978,6 +1077,20 @@ void RegisterAllocator::Resolve() {
}
}
}
+
+ // Assign temp locations.
+ HInstruction* current = nullptr;
+ size_t temp_index = 0;
+ for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
+ LiveInterval* temp = temp_intervals_.Get(i);
+ if (temp->GetDefinedBy() != current) {
+ temp_index = 0;
+ current = temp->GetDefinedBy();
+ }
+ LocationSummary* locations = current->GetLocations();
+ locations->SetTempAt(
+ temp_index++, Location::RegisterLocation(ManagedRegister(temp->GetRegister())));
+ }
}
} // namespace art
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index be1c7ec..f737491 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -59,6 +59,7 @@ class RegisterAllocator {
// Helper method for validation. Used by unit testing.
static bool ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
size_t number_of_spill_slots,
+ size_t number_of_out_slots,
const CodeGenerator& codegen,
ArenaAllocator* allocator,
bool processing_core_registers,
@@ -83,8 +84,8 @@ class RegisterAllocator {
bool AllocateBlockedReg(LiveInterval* interval);
void Resolve();
- // Add `interval` in the sorted list of unhandled intervals.
- void AddToUnhandled(LiveInterval* interval);
+ // Add `interval` in the given sorted list.
+ static void AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval);
// Split `interval` at the position `at`. The new interval starts at `at`.
LiveInterval* Split(LiveInterval* interval, size_t at);
@@ -115,6 +116,7 @@ class RegisterAllocator {
// Helper methods.
void AllocateRegistersInternal();
+ void ProcessInstruction(HInstruction* instruction);
bool ValidateInternal(bool log_fatal_on_failure) const;
void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
@@ -122,9 +124,17 @@ class RegisterAllocator {
CodeGenerator* const codegen_;
const SsaLivenessAnalysis& liveness_;
- // List of intervals that must be processed, ordered by start position. Last entry
- // is the interval that has the lowest start position.
- GrowableArray<LiveInterval*> unhandled_;
+ // List of intervals for core registers that must be processed, ordered by start
+ // position. Last entry is the interval that has the lowest start position.
+ // This list is initially populated before doing the linear scan.
+ GrowableArray<LiveInterval*> unhandled_core_intervals_;
+
+ // List of intervals for floating-point registers. Same comments as above.
+ GrowableArray<LiveInterval*> unhandled_fp_intervals_;
+
+ // Currently processed list of unhandled intervals. Either `unhandled_core_intervals_`
+ // or `unhandled_fp_intervals_`.
+ GrowableArray<LiveInterval*>* unhandled_;
// List of intervals that have been processed.
GrowableArray<LiveInterval*> handled_;
@@ -137,13 +147,20 @@ class RegisterAllocator {
// That is, they have a lifetime hole that spans the start of the new interval.
GrowableArray<LiveInterval*> inactive_;
- // Fixed intervals for physical registers. Such an interval covers the positions
+ // Fixed intervals for physical registers. Such intervals cover the positions
// where an instruction requires a specific register.
GrowableArray<LiveInterval*> physical_register_intervals_;
+ // Intervals for temporaries. Such intervals cover the positions
+ // where an instruction requires a temporary.
+ GrowableArray<LiveInterval*> temp_intervals_;
+
// The spill slots allocated for live intervals.
GrowableArray<size_t> spill_slots_;
+ // Instructions that need a safepoint.
+ GrowableArray<HInstruction*> safepoints_;
+
// True if processing core registers. False if processing floating
// point registers.
bool processing_core_registers_;
@@ -157,6 +174,9 @@ class RegisterAllocator {
// Blocked registers, as decided by the code generator.
bool* const blocked_registers_;
+ // Slots reserved for out arguments.
+ size_t reserved_out_slots_;
+
DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
};
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index bafe577..7539d44 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -66,11 +66,11 @@ TEST(RegisterAllocatorTest, ValidateIntervals) {
intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(1)->SetRegister(0);
ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Reset();
}
@@ -81,11 +81,11 @@ TEST(RegisterAllocatorTest, ValidateIntervals) {
static constexpr size_t ranges2[][2] = {{42, 43}};
intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(1)->SetRegister(0);
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Reset();
}
@@ -96,11 +96,11 @@ TEST(RegisterAllocatorTest, ValidateIntervals) {
static constexpr size_t ranges2[][2] = {{42, 43}};
intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(1)->SetRegister(0);
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Reset();
}
@@ -111,11 +111,11 @@ TEST(RegisterAllocatorTest, ValidateIntervals) {
static constexpr size_t ranges2[][2] = {{42, 47}};
intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(1)->SetRegister(0);
ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Reset();
}
@@ -127,16 +127,16 @@ TEST(RegisterAllocatorTest, ValidateIntervals) {
static constexpr size_t ranges2[][2] = {{42, 47}};
intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(1)->SetRegister(0);
// Sibling of the first interval has no register allocated to it.
ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
intervals.Get(0)->GetNextSibling()->SetRegister(0);
ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
- intervals, 0, *codegen, &allocator, true, false));
+ intervals, 0, 0, *codegen, &allocator, true, false));
}
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 83035b5..33b1f1f 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -47,7 +47,7 @@ class BlockInfo : public ArenaObject {
};
/**
- * A live range contains the start and end of a range where an instruction
+ * A live range contains the start and end of a range where an instruction or a temporary
* is live.
*/
class LiveRange : public ArenaObject {
@@ -76,7 +76,7 @@ class LiveRange : public ArenaObject {
private:
size_t start_;
- size_t end_;
+ const size_t end_;
LiveRange* next_;
friend class LiveInterval;
@@ -133,7 +133,12 @@ class UsePosition : public ArenaObject {
*/
class LiveInterval : public ArenaObject {
public:
- LiveInterval(ArenaAllocator* allocator, Primitive::Type type, HInstruction* defined_by = nullptr)
+ LiveInterval(ArenaAllocator* allocator,
+ Primitive::Type type,
+ HInstruction* defined_by = nullptr,
+ bool is_fixed = false,
+ int reg = kNoRegister,
+ bool is_temp = false)
: allocator_(allocator),
first_range_(nullptr),
last_range_(nullptr),
@@ -141,16 +146,20 @@ class LiveInterval : public ArenaObject {
type_(type),
next_sibling_(nullptr),
parent_(this),
- register_(kNoRegister),
+ register_(reg),
spill_slot_(kNoSpillSlot),
- is_fixed_(false),
+ is_fixed_(is_fixed),
+ is_temp_(is_temp),
defined_by_(defined_by) {}
static LiveInterval* MakeFixedInterval(ArenaAllocator* allocator, int reg, Primitive::Type type) {
- LiveInterval* interval = new (allocator) LiveInterval(allocator, type);
- interval->SetRegister(reg);
- interval->is_fixed_ = true;
- return interval;
+ return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
+ }
+
+ static LiveInterval* MakeTempInterval(ArenaAllocator* allocator,
+ HInstruction* defined_by,
+ Primitive::Type type) {
+ return new (allocator) LiveInterval(allocator, type, defined_by, false, kNoRegister, true);
}
bool IsFixed() const { return is_fixed_; }
@@ -192,8 +201,10 @@ class LiveInterval : public ArenaObject {
} else if (first_range_->GetStart() == end) {
// There is a use in the following block.
first_range_->start_ = start;
+ } else if (first_range_->GetStart() == start && first_range_->GetEnd() == end) {
+ DCHECK(is_fixed_);
} else {
- DCHECK(first_range_->GetStart() > end);
+ DCHECK_GT(first_range_->GetStart(), end);
// There is a hole in the interval. Create a new range.
first_range_ = new (allocator_) LiveRange(start, end, first_range_);
}
@@ -215,7 +226,11 @@ class LiveInterval : public ArenaObject {
}
bool HasSpillSlot() const { return spill_slot_ != kNoSpillSlot; }
- void SetSpillSlot(int slot) { spill_slot_ = slot; }
+ void SetSpillSlot(int slot) {
+ DCHECK(!is_fixed_);
+ DCHECK(!is_temp_);
+ spill_slot_ = slot;
+ }
int GetSpillSlot() const { return spill_slot_; }
void SetFrom(size_t from) {
@@ -243,6 +258,9 @@ class LiveInterval : public ArenaObject {
}
bool Covers(size_t position) const {
+ if (IsDeadAt(position)) {
+ return false;
+ }
LiveRange* current = first_range_;
while (current != nullptr) {
if (position >= current->GetStart() && position < current->GetEnd()) {
@@ -288,6 +306,9 @@ class LiveInterval : public ArenaObject {
}
size_t FirstRegisterUseAfter(size_t position) const {
+ if (is_temp_) {
+ return position == GetStart() ? position : kNoLifetime;
+ }
if (position == GetStart() && defined_by_ != nullptr) {
LocationSummary* locations = defined_by_->GetLocations();
Location location = locations->Out();
@@ -342,6 +363,7 @@ class LiveInterval : public ArenaObject {
* [position ... end)
*/
LiveInterval* SplitAt(size_t position) {
+ DCHECK(!is_temp_);
DCHECK(!is_fixed_);
DCHECK_GT(position, GetStart());
@@ -453,7 +475,10 @@ class LiveInterval : public ArenaObject {
int spill_slot_;
// Whether the interval is for a fixed register.
- bool is_fixed_;
+ const bool is_fixed_;
+
+ // Whether the interval is for a temporary.
+ const bool is_temp_;
// The instruction represented by this interval.
HInstruction* const defined_by_;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index a079954..65675dc 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -26,6 +26,8 @@ void SsaDeadPhiElimination::Run() {
HPhi* phi = it.Current()->AsPhi();
if (phi->HasEnvironmentUses()) {
// TODO: Do we want to keep that phi alive?
+ worklist_.Add(phi);
+ phi->SetLive();
continue;
}
for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
@@ -105,7 +107,7 @@ void SsaRedundantPhiElimination::Run() {
for (size_t i = 1; i < phi->InputCount(); ++i) {
HInstruction* input = phi->InputAt(i);
- // For a loop phi, If the input is the phi, the phi is still candidate for
+ // For a loop phi, if the input is the phi, the phi is still candidate for
// elimination.
if (input != candidate && input != phi) {
candidate = nullptr;
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 5e1329e..0ea11ad 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -26,9 +26,9 @@
namespace art {
/**
- * Collects and builds a CodeInfo for a method.
+ * Collects and builds stack maps for a method. All the stack maps
+ * for a method are placed in a CodeInfo object.
*/
-template<typename T>
class StackMapStream : public ValueObject {
public:
explicit StackMapStream(ArenaAllocator* allocator)
@@ -47,7 +47,7 @@ class StackMapStream : public ValueObject {
// See runtime/stack_map.h to know what these fields contain.
struct StackMapEntry {
uint32_t dex_pc;
- T native_pc;
+ uint32_t native_pc_offset;
uint32_t register_mask;
BitVector* sp_mask;
uint32_t num_dex_registers;
@@ -66,14 +66,14 @@ class StackMapStream : public ValueObject {
};
void AddStackMapEntry(uint32_t dex_pc,
- T native_pc,
+ uint32_t native_pc_offset,
uint32_t register_mask,
BitVector* sp_mask,
uint32_t num_dex_registers,
uint8_t inlining_depth) {
StackMapEntry entry;
entry.dex_pc = dex_pc;
- entry.native_pc = native_pc;
+ entry.native_pc_offset = native_pc_offset;
entry.register_mask = register_mask;
entry.sp_mask = sp_mask;
entry.num_dex_registers = num_dex_registers;
@@ -82,7 +82,9 @@ class StackMapStream : public ValueObject {
entry.inline_infos_start_index = inline_infos_.Size();
stack_maps_.Add(entry);
- stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
+ if (sp_mask != nullptr) {
+ stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
+ }
if (inlining_depth > 0) {
number_of_stack_maps_with_inline_info_++;
}
@@ -102,14 +104,14 @@ class StackMapStream : public ValueObject {
}
size_t ComputeNeededSize() const {
- return CodeInfo<T>::kFixedSize
+ return CodeInfo::kFixedSize
+ ComputeStackMapSize()
+ ComputeDexRegisterMapSize()
+ ComputeInlineInfoSize();
}
size_t ComputeStackMapSize() const {
- return stack_maps_.Size() * (StackMap<T>::kFixedSize + StackMaskEncodingSize(stack_mask_max_));
+ return stack_maps_.Size() * (StackMap::kFixedSize + StackMaskEncodingSize(stack_mask_max_));
}
size_t ComputeDexRegisterMapSize() const {
@@ -130,11 +132,12 @@ class StackMapStream : public ValueObject {
}
size_t ComputeDexRegisterMapStart() const {
- return CodeInfo<T>::kFixedSize + ComputeStackMapSize();
+ return CodeInfo::kFixedSize + ComputeStackMapSize();
}
void FillIn(MemoryRegion region) {
- CodeInfo<T> code_info(region);
+ CodeInfo code_info(region);
+ code_info.SetOverallSize(region.size());
size_t stack_mask_size = StackMaskEncodingSize(stack_mask_max_);
uint8_t* memory_start = region.start();
@@ -153,13 +156,15 @@ class StackMapStream : public ValueObject {
uintptr_t next_dex_register_map_offset = 0;
uintptr_t next_inline_info_offset = 0;
for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
- StackMap<T> stack_map = code_info.GetStackMapAt(i);
+ StackMap stack_map = code_info.GetStackMapAt(i);
StackMapEntry entry = stack_maps_.Get(i);
stack_map.SetDexPc(entry.dex_pc);
- stack_map.SetNativePc(entry.native_pc);
+ stack_map.SetNativePcOffset(entry.native_pc_offset);
stack_map.SetRegisterMask(entry.register_mask);
- stack_map.SetStackMask(*entry.sp_mask);
+ if (entry.sp_mask != nullptr) {
+ stack_map.SetStackMask(*entry.sp_mask);
+ }
// Set the register map.
MemoryRegion region = dex_register_maps_region.Subregion(
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index a70259e..5ee6ae0 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -34,7 +34,7 @@ bool SameBits(MemoryRegion region, const BitVector& bit_vector) {
TEST(StackMapTest, Test1) {
ArenaPool pool;
ArenaAllocator arena(&pool);
- StackMapStream<size_t> stream(&arena);
+ StackMapStream stream(&arena);
ArenaBitVector sp_mask(&arena, 0, false);
stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, 2, 0);
@@ -46,15 +46,15 @@ TEST(StackMapTest, Test1) {
MemoryRegion region(memory, size);
stream.FillIn(region);
- CodeInfo<size_t> code_info(region);
+ CodeInfo code_info(region);
ASSERT_EQ(0u, code_info.GetStackMaskSize());
ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
- StackMap<size_t> stack_map = code_info.GetStackMapAt(0);
+ StackMap stack_map = code_info.GetStackMapAt(0);
ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
- ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(64)));
+ ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
ASSERT_EQ(0u, stack_map.GetDexPc());
- ASSERT_EQ(64u, stack_map.GetNativePc());
+ ASSERT_EQ(64u, stack_map.GetNativePcOffset());
ASSERT_EQ(0x3u, stack_map.GetRegisterMask());
ASSERT_FALSE(stack_map.HasInlineInfo());
@@ -71,7 +71,7 @@ TEST(StackMapTest, Test1) {
TEST(StackMapTest, Test2) {
ArenaPool pool;
ArenaAllocator arena(&pool);
- StackMapStream<size_t> stream(&arena);
+ StackMapStream stream(&arena);
ArenaBitVector sp_mask1(&arena, 0, true);
sp_mask1.SetBit(2);
@@ -93,15 +93,15 @@ TEST(StackMapTest, Test2) {
MemoryRegion region(memory, size);
stream.FillIn(region);
- CodeInfo<size_t> code_info(region);
+ CodeInfo code_info(region);
ASSERT_EQ(1u, code_info.GetStackMaskSize());
ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
- StackMap<size_t> stack_map = code_info.GetStackMapAt(0);
+ StackMap stack_map = code_info.GetStackMapAt(0);
ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
- ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(64)));
+ ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
ASSERT_EQ(0u, stack_map.GetDexPc());
- ASSERT_EQ(64u, stack_map.GetNativePc());
+ ASSERT_EQ(64u, stack_map.GetNativePcOffset());
ASSERT_EQ(0x3u, stack_map.GetRegisterMask());
MemoryRegion stack_mask = stack_map.GetStackMask();
@@ -120,9 +120,9 @@ TEST(StackMapTest, Test2) {
stack_map = code_info.GetStackMapAt(1);
ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u)));
- ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePc(128u)));
+ ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u)));
ASSERT_EQ(1u, stack_map.GetDexPc());
- ASSERT_EQ(128u, stack_map.GetNativePc());
+ ASSERT_EQ(128u, stack_map.GetNativePcOffset());
ASSERT_EQ(0xFFu, stack_map.GetRegisterMask());
stack_mask = stack_map.GetStackMask();
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index fff42f6..4cdf618 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -386,7 +386,7 @@ class OatDumper {
GetQuickToInterpreterBridgeOffset);
#undef DUMP_OAT_HEADER_OFFSET
- os << "IMAGE PATCH DELTA:\n" << oat_header.GetImagePatchDelta();
+ os << "IMAGE PATCH DELTA:\n" << oat_header.GetImagePatchDelta() << "\n\n";
os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
@@ -616,7 +616,11 @@ class OatDumper {
DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
*indent2_os << StringPrintf("\nvmap_table: %p (offset=0x%08x)\n",
oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
- DumpVmap(*indent2_os, oat_method);
+
+ if (oat_method.GetNativeGcMap() != nullptr) {
+ // The native GC map is null for methods compiled with the optimizing compiler.
+ DumpVmap(*indent2_os, oat_method);
+ }
DumpVregLocations(*indent2_os, oat_method, code_item);
*indent2_os << StringPrintf("mapping_table: %p (offset=0x%08x)\n",
oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index c50c703..ae17070 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -271,6 +271,9 @@ inline const uint8_t* ArtMethod::GetVmapTable() {
}
inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer) {
+ if (IsOptimized()) {
+ LOG(FATAL) << "Unimplemented vmap table for optimized compiler";
+ }
DCHECK(code_pointer != nullptr);
DCHECK(code_pointer == GetQuickOatCodePointer());
uint32_t offset =
@@ -281,6 +284,17 @@ inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer) {
return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
}
+inline StackMap ArtMethod::GetStackMap(uint32_t native_pc_offset) {
+ DCHECK(IsOptimized());
+ const void* code_pointer = GetQuickOatCodePointer();
+ DCHECK(code_pointer != nullptr);
+ uint32_t offset =
+ reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
+ const void* data = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset);
+ CodeInfo code_info(data);
+ return code_info.GetStackMapForNativePcOffset(native_pc_offset);
+}
+
inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) {
DCHECK(!Runtime::Current()->IsStarted());
SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index ebd5bd5..d37aa57 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -25,6 +25,7 @@
#include "object_callbacks.h"
#include "quick/quick_method_frame_info.h"
#include "read_barrier_option.h"
+#include "stack_map.h"
namespace art {
@@ -150,6 +151,13 @@ class MANAGED ArtMethod FINAL : public Object {
SetAccessFlags(GetAccessFlags() | kAccPreverified);
}
+ bool IsOptimized() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Temporary solution for detecting if a method has been optimized: the compiler
+ // does not create a GC map. Instead, the vmap table contains the stack map
+ // (as in stack_map.h).
+ return (GetEntryPointFromQuickCompiledCode() != nullptr) && (GetNativeGcMap() == nullptr);
+ }
+
bool IsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return (GetAccessFlags() & kAccPortableCompiled) != 0;
}
@@ -340,6 +348,8 @@ class MANAGED ArtMethod FINAL : public Object {
const uint8_t* GetVmapTable(const void* code_pointer)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ StackMap GetStackMap(uint32_t native_pc_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
const uint8_t* GetNativeGcMap() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_));
}
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 2d0060e..b8b10d2 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -115,18 +115,22 @@ uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const {
mirror::Object* StackVisitor::GetThisObject() const {
mirror::ArtMethod* m = GetMethod();
if (m->IsStatic()) {
- return NULL;
+ return nullptr;
} else if (m->IsNative()) {
- if (cur_quick_frame_ != NULL) {
+ if (cur_quick_frame_ != nullptr) {
HandleScope* hs = reinterpret_cast<HandleScope*>(
reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffsetInBytes());
return hs->GetReference(0);
} else {
return cur_shadow_frame_->GetVRegReference(0);
}
+ } else if (m->IsOptimized()) {
+ // TODO: Implement, currently only used for exceptions when jdwp is enabled.
+ LOG(WARNING) << "StackVisitor::GetThisObject is unimplemented with the optimizing compiler";
+ return nullptr;
} else {
const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == NULL) {
+ if (code_item == nullptr) {
UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
<< PrettyMethod(m);
return nullptr;
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 7d3a48f..9b49d31 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -64,9 +64,9 @@ class InlineInfo {
MemoryRegion region_;
- template<typename T> friend class CodeInfo;
- template<typename T> friend class StackMap;
- template<typename T> friend class StackMapStream;
+ friend class CodeInfo;
+ friend class StackMap;
+ friend class StackMapStream;
};
/**
@@ -77,13 +77,15 @@ class InlineInfo {
* The location_kind for a Dex register can either be:
* - Constant: register_value holds the constant,
* - Stack: register_value holds the stack offset,
- * - Register: register_value holds the register number.
+ * - Register: register_value holds the physical register number.
+ * - None: the register has no location yet, meaning it has not been set.
*/
class DexRegisterMap {
public:
explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
enum LocationKind {
+ kNone,
kInStack,
kInRegister,
kConstant
@@ -114,8 +116,8 @@ class DexRegisterMap {
MemoryRegion region_;
- template <typename T> friend class CodeInfo;
- template <typename T> friend class StackMapStream;
+ friend class CodeInfo;
+ friend class StackMapStream;
};
/**
@@ -127,12 +129,11 @@ class DexRegisterMap {
* - Knowing the values of dex registers.
*
* The information is of the form:
- * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
+ * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
*
* Note that register_mask is fixed size, but stack_mask is variable size, depending on the
* stack size of a method.
*/
-template <typename T>
class StackMap {
public:
explicit StackMap(MemoryRegion region) : region_(region) {}
@@ -145,12 +146,12 @@ class StackMap {
region_.Store<uint32_t>(kDexPcOffset, dex_pc);
}
- T GetNativePc() const {
- return region_.Load<T>(kNativePcOffset);
+ uint32_t GetNativePcOffset() const {
+ return region_.Load<uint32_t>(kNativePcOffsetOffset);
}
- void SetNativePc(T native_pc) {
- return region_.Store<T>(kNativePcOffset, native_pc);
+ void SetNativePcOffset(uint32_t native_pc_offset) {
+ return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
}
uint32_t GetDexRegisterMapOffset() const {
@@ -199,8 +200,8 @@ class StackMap {
private:
static constexpr int kDexPcOffset = 0;
- static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t);
- static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T);
+ static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
+ static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
static constexpr int kInlineDescriptorOffsetOffset =
kDexRegisterMapOffsetOffset + sizeof(uint32_t);
static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
@@ -211,24 +212,36 @@ class StackMap {
MemoryRegion region_;
- template <typename U> friend class CodeInfo;
- template <typename U> friend class StackMapStream;
+ friend class CodeInfo;
+ friend class StackMapStream;
};
/**
* Wrapper around all compiler information collected for a method.
* The information is of the form:
- * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
+ * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
*/
-template <typename T>
class CodeInfo {
public:
explicit CodeInfo(MemoryRegion region) : region_(region) {}
- StackMap<T> GetStackMapAt(size_t i) const {
+ explicit CodeInfo(const void* data) {
+ uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
+ region_ = MemoryRegion(const_cast<void*>(data), size);
+ }
+
+ StackMap GetStackMapAt(size_t i) const {
size_t size = StackMapSize();
- return StackMap<T>(GetStackMaps().Subregion(i * size, size));
+ return StackMap(GetStackMaps().Subregion(i * size, size));
+ }
+
+ uint32_t GetOverallSize() const {
+ return region_.Load<uint32_t>(kOverallSizeOffset);
+ }
+
+ void SetOverallSize(uint32_t size) {
+ region_.Store<uint32_t>(kOverallSizeOffset, size);
}
uint32_t GetStackMaskSize() const {
@@ -248,47 +261,48 @@ class CodeInfo {
}
size_t StackMapSize() const {
- return StackMap<T>::kFixedSize + GetStackMaskSize();
+ return StackMap::kFixedSize + GetStackMaskSize();
}
- DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) {
+ DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
uint32_t offset = stack_map.GetDexRegisterMapOffset();
return DexRegisterMap(region_.Subregion(offset,
DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
}
- InlineInfo GetInlineInfoOf(StackMap<T> stack_map) {
+ InlineInfo GetInlineInfoOf(StackMap stack_map) {
uint32_t offset = stack_map.GetInlineDescriptorOffset();
uint8_t depth = region_.Load<uint8_t>(offset);
return InlineInfo(region_.Subregion(offset,
InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
}
- StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) {
+ StackMap GetStackMapForDexPc(uint32_t dex_pc) {
for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
- StackMap<T> stack_map = GetStackMapAt(i);
+ StackMap stack_map = GetStackMapAt(i);
if (stack_map.GetDexPc() == dex_pc) {
return stack_map;
}
}
LOG(FATAL) << "Unreachable";
- return StackMap<T>(MemoryRegion());
+ return StackMap(MemoryRegion());
}
- StackMap<T> GetStackMapForNativePc(T native_pc) {
+ StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
// TODO: stack maps are sorted by native pc, we can do a binary search.
for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
- StackMap<T> stack_map = GetStackMapAt(i);
- if (stack_map.GetNativePc() == native_pc) {
+ StackMap stack_map = GetStackMapAt(i);
+ if (stack_map.GetNativePcOffset() == native_pc_offset) {
return stack_map;
}
}
LOG(FATAL) << "Unreachable";
- return StackMap<T>(MemoryRegion());
+ return StackMap(MemoryRegion());
}
private:
- static constexpr int kNumberOfStackMapsOffset = 0;
+ static constexpr int kOverallSizeOffset = 0;
+ static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
@@ -299,7 +313,7 @@ class CodeInfo {
}
MemoryRegion region_;
- template<typename U> friend class StackMapStream;
+ friend class StackMapStream;
};
} // namespace art
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e323473..6e3e9c1 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2070,48 +2070,72 @@ class ReferenceMapVisitor : public StackVisitor {
// Process register map (which native and runtime methods don't have)
if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
- const uint8_t* native_gc_map = m->GetNativeGcMap();
- CHECK(native_gc_map != nullptr) << PrettyMethod(m);
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be nullptr or how would we compile its instructions?
- NativePcOffsetToReferenceMap map(native_gc_map);
- size_t num_regs = std::min(map.RegWidth() * 8,
- static_cast<size_t>(code_item->registers_size_));
- if (num_regs > 0) {
+ if (m->IsOptimized()) {
Runtime* runtime = Runtime::Current();
const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
- const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
- DCHECK(reg_bitmap != nullptr);
- const void* code_pointer = mirror::ArtMethod::EntryPointToCodePointer(entry_point);
- const VmapTable vmap_table(m->GetVmapTable(code_pointer));
- QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
- // For all dex registers in the bitmap
- StackReference<mirror::ArtMethod>* cur_quick_frame = GetCurrentQuickFrame();
- DCHECK(cur_quick_frame != nullptr);
- for (size_t reg = 0; reg < num_regs; ++reg) {
- // Does this register hold a reference?
- if (TestBitmap(reg, reg_bitmap)) {
- uint32_t vmap_offset;
- if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) {
- int vmap_reg = vmap_table.ComputeRegister(frame_info.CoreSpillMask(), vmap_offset,
- kReferenceVReg);
- // This is sound as spilled GPRs will be word sized (ie 32 or 64bit).
- mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(vmap_reg));
- if (*ref_addr != nullptr) {
- visitor_(ref_addr, reg, this);
+ StackMap map = m->GetStackMap(native_pc_offset);
+ MemoryRegion mask = map.GetStackMask();
+ for (size_t i = 0; i < mask.size_in_bits(); ++i) {
+ if (mask.LoadBit(i)) {
+ StackReference<mirror::Object>* ref_addr =
+ reinterpret_cast<StackReference<mirror::Object>*>(cur_quick_frame) + i;
+ mirror::Object* ref = ref_addr->AsMirrorPtr();
+ if (ref != nullptr) {
+ mirror::Object* new_ref = ref;
+ visitor_(&new_ref, -1, this);
+ if (ref != new_ref) {
+ ref_addr->Assign(new_ref);
}
- } else {
- StackReference<mirror::Object>* ref_addr =
- reinterpret_cast<StackReference<mirror::Object>*>(
- GetVRegAddr(cur_quick_frame, code_item, frame_info.CoreSpillMask(),
- frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), reg));
- mirror::Object* ref = ref_addr->AsMirrorPtr();
- if (ref != nullptr) {
- mirror::Object* new_ref = ref;
- visitor_(&new_ref, reg, this);
- if (ref != new_ref) {
- ref_addr->Assign(new_ref);
+ }
+ }
+ }
+ } else {
+ const uint8_t* native_gc_map = m->GetNativeGcMap();
+ CHECK(native_gc_map != nullptr) << PrettyMethod(m);
+ const DexFile::CodeItem* code_item = m->GetCodeItem();
+ // Can't be nullptr or how would we compile its instructions?
+ DCHECK(code_item != nullptr) << PrettyMethod(m);
+ NativePcOffsetToReferenceMap map(native_gc_map);
+ size_t num_regs = std::min(map.RegWidth() * 8,
+ static_cast<size_t>(code_item->registers_size_));
+ if (num_regs > 0) {
+ Runtime* runtime = Runtime::Current();
+ const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
+ uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+ const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
+ DCHECK(reg_bitmap != nullptr);
+ const void* code_pointer = mirror::ArtMethod::EntryPointToCodePointer(entry_point);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+ QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+ // For all dex registers in the bitmap
+ StackReference<mirror::ArtMethod>* cur_quick_frame = GetCurrentQuickFrame();
+ DCHECK(cur_quick_frame != nullptr);
+ for (size_t reg = 0; reg < num_regs; ++reg) {
+ // Does this register hold a reference?
+ if (TestBitmap(reg, reg_bitmap)) {
+ uint32_t vmap_offset;
+ if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) {
+ int vmap_reg = vmap_table.ComputeRegister(frame_info.CoreSpillMask(), vmap_offset,
+ kReferenceVReg);
+ // This is sound as spilled GPRs will be word sized (ie 32 or 64bit).
+ mirror::Object** ref_addr =
+ reinterpret_cast<mirror::Object**>(GetGPRAddress(vmap_reg));
+ if (*ref_addr != nullptr) {
+ visitor_(ref_addr, reg, this);
+ }
+ } else {
+ StackReference<mirror::Object>* ref_addr =
+ reinterpret_cast<StackReference<mirror::Object>*>(
+ GetVRegAddr(cur_quick_frame, code_item, frame_info.CoreSpillMask(),
+ frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), reg));
+ mirror::Object* ref = ref_addr->AsMirrorPtr();
+ if (ref != nullptr) {
+ mirror::Object* new_ref = ref;
+ visitor_(&new_ref, reg, this);
+ if (ref != new_ref) {
+ ref_addr->Assign(new_ref);
+ }
}
}
}
diff --git a/test/407-arrays/src/Main.java b/test/407-arrays/src/Main.java
index 5d27e6d..b5e95b0 100644
--- a/test/407-arrays/src/Main.java
+++ b/test/407-arrays/src/Main.java
@@ -57,7 +57,7 @@ public class Main extends TestCase {
int[] ints, Object[] objects, long[] longs, int index) {
bools[0] = true;
assertEquals(true, bools[0]);
- bools[1] = true;
+ bools[index] = true;
assertEquals(true, bools[index]);
bytes[0] = -4;