OSDN Git Service

Runtime support for the new stack maps for the opt compiler.
authorNicolas Geoffray <ngeoffray@google.com>
Tue, 2 Sep 2014 14:17:15 +0000 (15:17 +0100)
committerNicolas Geoffray <ngeoffray@google.com>
Mon, 8 Sep 2014 11:15:07 +0000 (12:15 +0100)
Now most of the methods supported by the compiler can be optimized,
instead of using the baseline.

Change-Id: I80ab36a34913fa4e7dd576c7bf55af63594dc1fa

28 files changed:
compiler/compiled_method.cc
compiler/compiled_method.h
compiler/oat_writer.cc
compiler/optimizing/builder.cc
compiler/optimizing/code_generator.cc
compiler/optimizing/code_generator.h
compiler/optimizing/code_generator_arm.cc
compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/locations.cc
compiler/optimizing/locations.h
compiler/optimizing/nodes.cc
compiler/optimizing/nodes.h
compiler/optimizing/optimizing_compiler.cc
compiler/optimizing/register_allocator.cc
compiler/optimizing/register_allocator.h
compiler/optimizing/register_allocator_test.cc
compiler/optimizing/ssa_liveness_analysis.h
compiler/optimizing/ssa_phi_elimination.cc
compiler/optimizing/stack_map_stream.h
compiler/optimizing/stack_map_test.cc
oatdump/oatdump.cc
runtime/mirror/art_method-inl.h
runtime/mirror/art_method.h
runtime/stack.cc
runtime/stack_map.h
runtime/thread.cc
test/407-arrays/src/Main.java

index f9a78be..ba5bd30 100644 (file)
@@ -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,
index 36f4745..3e34144 100644 (file)
@@ -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 {
index 680ce0a..c5d1478 100644 (file)
@@ -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_);
index 43e6b83..ecd6802 100644 (file)
@@ -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;
   }
index 7269fff..7731e6e 100644 (file)
@@ -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
index 12337c9..a83d703 100644 (file)
@@ -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);
 };
 
index 2c954a0..e72e39b 100644 (file)
@@ -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();
index 35b8116..6602d3f 100644 (file)
@@ -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();
index c4571ca..b2d81e3 100644 (file)
@@ -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();
index 468cfb7..fce97bd 100644 (file)
 
 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);
+  }
 }
 
 
index aaddb09..041e85b 100644 (file)
@@ -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);
 };
index 490d345..f07029d 100644 (file)
@@ -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);
index bb699e4..ea0cacc 100644 (file)
@@ -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);
 };
index 3461276..75f4155 100644 (file)
@@ -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,
index da13b1e..54888ba 100644 (file)
@@ -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
index be1c7ec..f737491 100644 (file)
@@ -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);
 };
 
index bafe577..7539d44 100644 (file)
@@ -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));
   }
 }
 
index 83035b5..33b1f1f 100644 (file)
@@ -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_;
index a079954..65675dc 100644 (file)
@@ -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;
index 5e1329e..0ea11ad 100644 (file)
@@ -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(
index a70259e..5ee6ae0 100644 (file)
@@ -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();
index fff42f6..4cdf618 100644 (file)
@@ -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());
index c50c703..ae17070 100644 (file)
@@ -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));
index ebd5bd5..d37aa57 100644 (file)
@@ -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_));
   }
index 2d0060e..b8b10d2 100644 (file)
@@ -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;
index 7d3a48f..9b49d31 100644 (file)
@@ -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
index e323473..6e3e9c1 100644 (file)
@@ -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);
+                  }
                 }
               }
             }
index 5d27e6d..b5e95b0 100644 (file)
@@ -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;