Commit 4473edd7 authored by ishell@chromium.org's avatar ishell@chromium.org

Implemented folding of constant size allocation followed by dynamic size allocation.

Manually folded allocations (JSArray, JSRegExpResult) are split into two separate allocations.

R=hpayer@chromium.org

Review URL: https://codereview.chromium.org/304153009

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21671 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent eac09127
......@@ -724,6 +724,7 @@ HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
? JSArrayBuilder::FILL_WITH_HOLE
: JSArrayBuilder::DONT_FILL_WITH_HOLE;
HValue* new_object = array_builder->AllocateArray(checked_length,
max_alloc_length,
checked_length,
fill_mode);
HValue* elements = array_builder->GetElementsLocation();
......
......@@ -724,6 +724,21 @@ void HInstruction::InsertAfter(HInstruction* previous) {
}
bool HInstruction::Dominates(HInstruction* other) {
if (block() != other->block()) {
return block()->Dominates(other->block());
}
// Both instructions are in the same basic block. This instruction
// should precede the other one in order to dominate it.
for (HInstruction* instr = next(); instr != NULL; instr = instr->next()) {
if (instr == other) {
return true;
}
}
return false;
}
#ifdef DEBUG
void HInstruction::Verify() {
// Verify that input operands are defined before use.
......@@ -3746,10 +3761,10 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
HValue* current_size = size();
// TODO(hpayer): Add support for non-constant allocation in dominator.
if (!current_size->IsInteger32Constant() ||
!dominator_size->IsInteger32Constant()) {
if (!dominator_size->IsInteger32Constant()) {
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) cannot fold into #%d (%s), dynamic allocation size\n",
PrintF("#%d (%s) cannot fold into #%d (%s), "
"dynamic allocation size in dominator\n",
id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
}
return false;
......@@ -3760,6 +3775,32 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
return false;
}
if (!has_size_upper_bound()) {
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) cannot fold into #%d (%s), "
"can't estimate total allocation size\n",
id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
}
return false;
}
if (!current_size->IsInteger32Constant()) {
// If it's not constant then it is a size_in_bytes calculation graph
// like this: (const_header_size + const_element_size * size).
ASSERT(current_size->IsInstruction());
HInstruction* current_instr = HInstruction::cast(current_size);
if (!current_instr->Dominates(dominator_allocate)) {
if (FLAG_trace_allocation_folding) {
PrintF("#%d (%s) cannot fold into #%d (%s), dynamic size "
"value does not dominate target allocation\n",
id(), Mnemonic(), dominator_allocate->id(),
dominator_allocate->Mnemonic());
}
return false;
}
}
ASSERT((IsNewSpaceAllocation() &&
dominator_allocate->IsNewSpaceAllocation()) ||
(IsOldDataSpaceAllocation() &&
......@@ -3772,20 +3813,16 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
int32_t original_object_size =
HConstant::cast(dominator_size)->GetInteger32Constant();
int32_t dominator_size_constant = original_object_size;
int32_t current_size_constant =
HConstant::cast(current_size)->GetInteger32Constant();
int32_t new_dominator_size = dominator_size_constant + current_size_constant;
if (MustAllocateDoubleAligned()) {
if (!dominator_allocate->MustAllocateDoubleAligned()) {
dominator_allocate->MakeDoubleAligned();
}
if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
dominator_size_constant += kDoubleSize / 2;
new_dominator_size += kDoubleSize / 2;
}
}
int32_t current_size_max_value = size_upper_bound()->GetInteger32Constant();
int32_t new_dominator_size = dominator_size_constant + current_size_max_value;
// Since we clear the first word after folded memory, we cannot use the
// whole Page::kMaxRegularHeapObjectSize memory.
if (new_dominator_size > Page::kMaxRegularHeapObjectSize - kPointerSize) {
......@@ -3797,13 +3834,41 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
return false;
}
HInstruction* new_dominator_size_constant = HConstant::CreateAndInsertBefore(
zone,
context(),
new_dominator_size,
Representation::None(),
dominator_allocate);
dominator_allocate->UpdateSize(new_dominator_size_constant);
HInstruction* new_dominator_size_value;
if (current_size->IsInteger32Constant()) {
new_dominator_size_value =
HConstant::CreateAndInsertBefore(zone,
context(),
new_dominator_size,
Representation::None(),
dominator_allocate);
} else {
HValue* new_dominator_size_constant =
HConstant::CreateAndInsertBefore(zone,
context(),
dominator_size_constant,
Representation::Integer32(),
dominator_allocate);
// Add old and new size together and insert.
current_size->ChangeRepresentation(Representation::Integer32());
new_dominator_size_value = HAdd::New(zone, context(),
new_dominator_size_constant, current_size);
new_dominator_size_value->ClearFlag(HValue::kCanOverflow);
new_dominator_size_value->ChangeRepresentation(Representation::Integer32());
new_dominator_size_value->InsertBefore(dominator_allocate);
}
dominator_allocate->UpdateSize(new_dominator_size_value);
if (MustAllocateDoubleAligned()) {
if (!dominator_allocate->MustAllocateDoubleAligned()) {
dominator_allocate->MakeDoubleAligned();
}
}
bool keep_new_space_iterable = FLAG_log_gc || FLAG_heap_stats;
#ifdef VERIFY_HEAP
......
......@@ -1158,6 +1158,7 @@ class HInstruction : public HValue {
position_.set_operand_position(index, pos);
}
bool Dominates(HInstruction* other);
bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
......@@ -5458,6 +5459,13 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
HValue* context() { return OperandAt(0); }
HValue* size() { return OperandAt(1); }
bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
HConstant* size_upper_bound() { return size_upper_bound_; }
void set_size_upper_bound(HConstant* value) {
ASSERT(size_upper_bound_ == NULL);
size_upper_bound_ = value;
}
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
if (index == 0) {
return Representation::Tagged();
......@@ -5533,9 +5541,10 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
: HTemplateInstruction<2>(type),
flags_(ComputeFlags(pretenure_flag, instance_type)),
dominating_allocate_(NULL),
filler_free_space_size_(NULL) {
filler_free_space_size_(NULL),
size_upper_bound_(NULL) {
SetOperandAt(0, context);
SetOperandAt(1, size);
UpdateSize(size);
set_representation(Representation::Tagged());
SetFlag(kTrackSideEffectDominators);
SetChangesFlag(kNewSpacePromotion);
......@@ -5582,6 +5591,11 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
void UpdateSize(HValue* size) {
SetOperandAt(1, size);
if (size->IsInteger32Constant()) {
size_upper_bound_ = HConstant::cast(size);
} else {
size_upper_bound_ = NULL;
}
}
HAllocate* GetFoldableDominator(HAllocate* dominator);
......@@ -5603,6 +5617,7 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
Handle<Map> known_initial_map_;
HAllocate* dominating_allocate_;
HStoreNamedField* filler_free_space_size_;
HConstant* size_upper_bound_;
};
......
This diff is collapsed.
......@@ -1396,6 +1396,8 @@ class HGraphBuilder {
return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
Add<HConstant>(map));
}
HLoadNamedField* AddLoadMap(HValue* object,
HValue* dependency = NULL);
HLoadNamedField* AddLoadElements(HValue* object,
HValue* dependency = NULL);
......@@ -1688,10 +1690,24 @@ class HGraphBuilder {
};
ElementsKind kind() { return kind_; }
HValue* AllocateEmptyArray();
HValue* AllocateArray(HValue* capacity, HValue* length_field,
FillMode fill_mode = FILL_WITH_HOLE);
HAllocate* elements_location() { return elements_location_; }
HAllocate* AllocateEmptyArray();
HAllocate* AllocateArray(HValue* capacity,
HValue* length_field,
FillMode fill_mode = FILL_WITH_HOLE);
// Use these allocators when capacity could be unknown at compile time
// but its limit is known. For constant |capacity| the value of
// |capacity_upper_bound| is ignored and the actual |capacity|
// value is used as an upper bound.
HAllocate* AllocateArray(HValue* capacity,
int capacity_upper_bound,
HValue* length_field,
FillMode fill_mode = FILL_WITH_HOLE);
HAllocate* AllocateArray(HValue* capacity,
HConstant* capacity_upper_bound,
HValue* length_field,
FillMode fill_mode = FILL_WITH_HOLE);
HValue* GetElementsLocation() { return elements_location_; }
HValue* EmitMapCode();
......@@ -1708,25 +1724,23 @@ class HGraphBuilder {
}
HValue* EmitInternalMapCode();
HValue* EstablishEmptyArrayAllocationSize();
HValue* EstablishAllocationSize(HValue* length_node);
HValue* AllocateArray(HValue* size_in_bytes, HValue* capacity,
HValue* length_field,
FillMode fill_mode = FILL_WITH_HOLE);
HGraphBuilder* builder_;
ElementsKind kind_;
AllocationSiteMode mode_;
HValue* allocation_site_payload_;
HValue* constructor_function_;
HInnerAllocatedObject* elements_location_;
HAllocate* elements_location_;
};
HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
HValue* length_argument);
HValue* BuildCalculateElementsSize(ElementsKind kind,
HValue* capacity);
HAllocate* AllocateJSArrayObject(AllocationSiteMode mode);
HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity);
HValue* BuildAllocateElements(ElementsKind kind,
HValue* capacity);
HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes);
void BuildInitializeElementsHeader(HValue* elements,
ElementsKind kind,
......@@ -1735,16 +1749,17 @@ class HGraphBuilder {
HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
HValue* capacity);
// array must have been allocated with enough room for
// 1) the JSArray, 2) a AllocationMemento if mode requires it,
// 3) a FixedArray or FixedDoubleArray.
// A pointer to the Fixed(Double)Array is returned.
HInnerAllocatedObject* BuildJSArrayHeader(HValue* array,
HValue* array_map,
AllocationSiteMode mode,
ElementsKind elements_kind,
HValue* allocation_site_payload,
HValue* length_field);
// |array| must have been allocated with enough room for
// 1) the JSArray and 2) an AllocationMemento if mode requires it.
// If the |elements| value provided is NULL then the array elements storage
// is initialized with empty array.
void BuildJSArrayHeader(HValue* array,
HValue* array_map,
HValue* elements,
AllocationSiteMode mode,
ElementsKind elements_kind,
HValue* allocation_site_payload,
HValue* length_field);
HValue* BuildGrowElementsCapacity(HValue* object,
HValue* elements,
......@@ -1753,25 +1768,24 @@ class HGraphBuilder {
HValue* length,
HValue* new_capacity);
void BuildFillElementsWithValue(HValue* elements,
ElementsKind elements_kind,
HValue* from,
HValue* to,
HValue* value);
void BuildFillElementsWithHole(HValue* elements,
ElementsKind elements_kind,
HValue* from,
HValue* to);
void BuildCopyElements(HValue* array,
HValue* from_elements,
void BuildCopyElements(HValue* from_elements,
ElementsKind from_elements_kind,
HValue* to_elements,
ElementsKind to_elements_kind,
HValue* length,
HValue* capacity);
HValue* BuildCloneShallowArrayCommon(HValue* boilerplate,
HValue* allocation_site,
HValue* extra_size,
HValue** return_elements,
AllocationSiteMode mode);
HValue* BuildCloneShallowArrayCow(HValue* boilerplate,
HValue* allocation_site,
AllocationSiteMode mode,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment