DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing")
DEFINE_bool(use_inlining, true, "use function inlining")
DEFINE_bool(use_escape_analysis, false, "use hydrogen escape analysis")
+DEFINE_bool(use_allocation_folding, false, "use allocation folding")
DEFINE_int(max_inlined_source_size, 600,
"maximum source size in bytes considered for a single inlining")
DEFINE_int(max_inlined_nodes, 196,
DEFINE_bool(trace_gvn, false, "trace global value numbering")
DEFINE_bool(trace_representation, false, "trace representation types")
DEFINE_bool(trace_escape_analysis, false, "trace hydrogen escape analysis")
+DEFINE_bool(trace_allocation_folding, false, "trace allocation folding")
DEFINE_bool(trace_track_allocation_sites, false,
"trace the tracking of allocation sites")
DEFINE_bool(trace_migration, false, "trace object migration")
}
// Go through all instructions of the current block.
- HInstruction* instr = block->first();
- while (instr != NULL) {
- HInstruction* next = instr->next();
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+ HInstruction* instr = it.Current();
+ if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) {
+ for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
+ HValue* other = dominators->at(i);
+ GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
+ GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i);
+ if (instr->DependsOnFlags().Contains(depends_on_flag) &&
+ (other != NULL)) {
+ TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
+ i,
+ instr->id(),
+ instr->Mnemonic(),
+ other->id(),
+ other->Mnemonic());
+ instr->HandleSideEffectDominator(changes_flag, other);
+ }
+ }
+ }
+ // Instruction was unlinked during graph traversal.
+ if (!instr->IsLinked()) continue;
+
GVNFlagSet flags = instr->ChangesFlags();
if (!flags.IsEmpty()) {
// Clear all instructions in the map that are affected by side effects.
map->Add(instr, zone());
}
}
- if (instr->IsLinked() &&
- instr->CheckFlag(HValue::kTrackSideEffectDominators)) {
- for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
- HValue* other = dominators->at(i);
- GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
- GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i);
- if (instr->DependsOnFlags().Contains(depends_on_flag) &&
- (other != NULL)) {
- TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n",
- i,
- instr->id(),
- instr->Mnemonic(),
- other->id(),
- other->Mnemonic());
- instr->SetSideEffectDominator(changes_flag, other);
- }
- }
- }
- instr = next;
}
HBasicBlock* dominator_block;
}
-void HCheckMaps::SetSideEffectDominator(GVNFlag side_effect,
- HValue* dominator) {
+void HCheckMaps::HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator) {
ASSERT(side_effect == kChangesMaps);
// TODO(mstarzinger): For now we specialize on HStoreNamedField, but once
// type information is rich enough we should generalize this to any HType
}
+void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator) {
+ ASSERT(side_effect == kChangesNewSpacePromotion);
+ // Try to fold allocations together with their dominating allocations.
+ if (!FLAG_use_allocation_folding || !dominator->IsAllocate()) {
+ return;
+ }
+ HAllocate* dominator_allocate_instr = HAllocate::cast(dominator);
+ HValue* dominator_size = dominator_allocate_instr->size();
+ HValue* current_size = size();
+ // We can just fold allocations that are guaranteed in new space.
+ // TODO(hpayer): Support double aligned allocations.
+ // TODO(hpayer): Add support for non-constant allocation in dominator.
+ if (!GuaranteedInNewSpace() || MustAllocateDoubleAligned() ||
+ !current_size->IsInteger32Constant() ||
+ !dominator_allocate_instr->GuaranteedInNewSpace() ||
+ dominator_allocate_instr->MustAllocateDoubleAligned() ||
+ !dominator_size->IsInteger32Constant()) {
+ return;
+ }
+
+ // First update the size of the dominator allocate instruction.
+ int32_t dominator_size_constant =
+ HConstant::cast(dominator_size)->GetInteger32Constant();
+ int32_t current_size_constant =
+ HConstant::cast(current_size)->GetInteger32Constant();
+ HBasicBlock* block = dominator->block();
+ Zone* zone = block->zone();
+ HInstruction* new_dominator_size = new(zone) HConstant(
+ dominator_size_constant + current_size_constant);
+ new_dominator_size->InsertBefore(dominator_allocate_instr);
+ dominator_allocate_instr->UpdateSize(new_dominator_size);
+
+ // TODO(hpayer): Remove filler map but make sure new space is valid.
+ HInstruction* free_space_instr =
+ new(zone) HInnerAllocatedObject(dominator_allocate_instr,
+ dominator_size_constant,
+ type());
+ free_space_instr->InsertAfter(dominator_allocate_instr);
+ HConstant* filler_map = new(zone) HConstant(
+ isolate()->factory()->free_space_map(),
+ UniqueValueId(isolate()->heap()->free_space_map()),
+ Representation::Tagged(),
+ HType::Tagged(),
+ false,
+ true,
+ false,
+ false);
+ filler_map->InsertAfter(free_space_instr);
+
+ HInstruction* store_map = new(zone) HStoreNamedField(
+ free_space_instr, HObjectAccess::ForMap(), filler_map);
+ store_map->SetFlag(HValue::kHasNoObservableSideEffects);
+ store_map->InsertAfter(filler_map);
+
+ HInstruction* free_space_size = new(zone) HConstant(current_size_constant);
+ free_space_size->InsertAfter(store_map);
+ HObjectAccess access =
+ HObjectAccess::ForJSObjectOffset(FreeSpace::kSizeOffset);
+ HInstruction* store_size = new(zone) HStoreNamedField(
+ free_space_instr, access, free_space_size);
+ store_size->SetFlag(HValue::kHasNoObservableSideEffects);
+ store_size->InsertAfter(free_space_size);
+
+ // After that replace the dominated allocate instruction.
+ HInstruction* dominated_allocate_instr =
+ new(zone) HInnerAllocatedObject(dominator_allocate_instr,
+ dominator_size_constant,
+ type());
+ dominated_allocate_instr->InsertBefore(this);
+ DeleteAndReplaceWith(dominated_allocate_instr);
+ if (FLAG_trace_allocation_folding) {
+ PrintF("#%d (%s) folded into #%d (%s)\n",
+ id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
+ }
+}
+
+
void HAllocate::PrintDataTo(StringStream* stream) {
size()->PrintNameTo(stream);
if (!GuaranteedInNewSpace()) stream->Add(" (pretenure)");
// occurrences of the instruction are indeed the same.
kUseGVN,
// Track instructions that are dominating side effects. If an instruction
- // sets this flag, it must implement SetSideEffectDominator() and should
+ // sets this flag, it must implement HandleSideEffectDominator() and should
// indicate which side effects to track by setting GVN flags.
kTrackSideEffectDominators,
kCanOverflow,
// This function must be overridden for instructions which have the
// kTrackSideEffectDominators flag set, to track instructions that are
// dominating side effects.
- virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ virtual void HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator) {
UNREACHABLE();
}
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
- virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator);
+ virtual void HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator);
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+
virtual Handle<Map> GetMonomorphicJSObjectMap() {
ASSERT(!constructor_initial_map_.is_null());
return constructor_initial_map_;
}
+
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
SetOperandAt(0, context);
SetOperandAt(1, size);
set_representation(Representation::Tagged());
+ SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kChangesNewSpacePromotion);
+ SetGVNFlag(kDependsOnNewSpacePromotion);
}
static Flags DefaultFlags() {
HValue* context() { return OperandAt(0); }
HValue* size() { return OperandAt(1); }
+ HType type() { return type_; }
virtual Representation RequiredInputRepresentation(int index) {
if (index == 0) {
return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
}
+ void UpdateSize(HValue* size) {
+ SetOperandAt(1, size);
+ }
+
+ virtual void HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator);
+
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(Allocate)
class HInnerAllocatedObject: public HTemplateInstruction<1> {
public:
- HInnerAllocatedObject(HValue* value, int offset)
- : offset_(offset) {
+ HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged())
+ : offset_(offset),
+ type_(type) {
ASSERT(value->IsAllocate());
SetOperandAt(0, value);
set_representation(Representation::Tagged());
return Representation::Tagged();
}
+ virtual HType CalculateInferredType() { return type_; }
+
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
private:
int offset_;
+ HType type_;
};
}
return Representation::Tagged();
}
- virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ virtual void HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
new_space_dominator_ = dominator;
}
return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
}
- virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ virtual void HandleSideEffectDominator(GVNFlag side_effect,
+ HValue* dominator) {
ASSERT(side_effect == kChangesNewSpacePromotion);
new_space_dominator_ = dominator;
}
class HInstructionIterator BASE_EMBEDDED {
public:
- explicit HInstructionIterator(HBasicBlock* block) : instr_(block->first()) { }
+ explicit HInstructionIterator(HBasicBlock* block)
+ : instr_(block->first()) {
+ next_ = Done() ? NULL : instr_->next();
+ }
- bool Done() { return instr_ == NULL; }
- HInstruction* Current() { return instr_; }
- void Advance() { instr_ = instr_->next(); }
+ inline bool Done() const { return instr_ == NULL; }
+ inline HInstruction* Current() { return instr_; }
+ inline void Advance() {
+ instr_ = next_;
+ next_ = Done() ? NULL : instr_->next();
+ }
private:
HInstruction* instr_;
+ HInstruction* next_;
};