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
This commit is contained in:
parent
eac091277f
commit
4473edd7f1
@ -724,6 +724,7 @@ HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
|
|||||||
? JSArrayBuilder::FILL_WITH_HOLE
|
? JSArrayBuilder::FILL_WITH_HOLE
|
||||||
: JSArrayBuilder::DONT_FILL_WITH_HOLE;
|
: JSArrayBuilder::DONT_FILL_WITH_HOLE;
|
||||||
HValue* new_object = array_builder->AllocateArray(checked_length,
|
HValue* new_object = array_builder->AllocateArray(checked_length,
|
||||||
|
max_alloc_length,
|
||||||
checked_length,
|
checked_length,
|
||||||
fill_mode);
|
fill_mode);
|
||||||
HValue* elements = array_builder->GetElementsLocation();
|
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
|
#ifdef DEBUG
|
||||||
void HInstruction::Verify() {
|
void HInstruction::Verify() {
|
||||||
// Verify that input operands are defined before use.
|
// Verify that input operands are defined before use.
|
||||||
@ -3746,10 +3761,10 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
|
|||||||
HValue* current_size = size();
|
HValue* current_size = size();
|
||||||
|
|
||||||
// TODO(hpayer): Add support for non-constant allocation in dominator.
|
// TODO(hpayer): Add support for non-constant allocation in dominator.
|
||||||
if (!current_size->IsInteger32Constant() ||
|
if (!dominator_size->IsInteger32Constant()) {
|
||||||
!dominator_size->IsInteger32Constant()) {
|
|
||||||
if (FLAG_trace_allocation_folding) {
|
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());
|
id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -3760,6 +3775,32 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
|
|||||||
return false;
|
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() &&
|
ASSERT((IsNewSpaceAllocation() &&
|
||||||
dominator_allocate->IsNewSpaceAllocation()) ||
|
dominator_allocate->IsNewSpaceAllocation()) ||
|
||||||
(IsOldDataSpaceAllocation() &&
|
(IsOldDataSpaceAllocation() &&
|
||||||
@ -3772,20 +3813,16 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
|
|||||||
int32_t original_object_size =
|
int32_t original_object_size =
|
||||||
HConstant::cast(dominator_size)->GetInteger32Constant();
|
HConstant::cast(dominator_size)->GetInteger32Constant();
|
||||||
int32_t dominator_size_constant = original_object_size;
|
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 (MustAllocateDoubleAligned()) {
|
||||||
if (!dominator_allocate->MustAllocateDoubleAligned()) {
|
|
||||||
dominator_allocate->MakeDoubleAligned();
|
|
||||||
}
|
|
||||||
if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
|
if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
|
||||||
dominator_size_constant += kDoubleSize / 2;
|
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
|
// Since we clear the first word after folded memory, we cannot use the
|
||||||
// whole Page::kMaxRegularHeapObjectSize memory.
|
// whole Page::kMaxRegularHeapObjectSize memory.
|
||||||
if (new_dominator_size > Page::kMaxRegularHeapObjectSize - kPointerSize) {
|
if (new_dominator_size > Page::kMaxRegularHeapObjectSize - kPointerSize) {
|
||||||
@ -3797,13 +3834,41 @@ bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HInstruction* new_dominator_size_constant = HConstant::CreateAndInsertBefore(
|
HInstruction* new_dominator_size_value;
|
||||||
zone,
|
|
||||||
context(),
|
if (current_size->IsInteger32Constant()) {
|
||||||
new_dominator_size,
|
new_dominator_size_value =
|
||||||
Representation::None(),
|
HConstant::CreateAndInsertBefore(zone,
|
||||||
dominator_allocate);
|
context(),
|
||||||
dominator_allocate->UpdateSize(new_dominator_size_constant);
|
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;
|
bool keep_new_space_iterable = FLAG_log_gc || FLAG_heap_stats;
|
||||||
#ifdef VERIFY_HEAP
|
#ifdef VERIFY_HEAP
|
||||||
|
@ -1158,6 +1158,7 @@ class HInstruction : public HValue {
|
|||||||
position_.set_operand_position(index, pos);
|
position_.set_operand_position(index, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Dominates(HInstruction* other);
|
||||||
bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
|
bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
|
||||||
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
|
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
|
||||||
|
|
||||||
@ -5458,6 +5459,13 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
|
|||||||
HValue* context() { return OperandAt(0); }
|
HValue* context() { return OperandAt(0); }
|
||||||
HValue* size() { return OperandAt(1); }
|
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 {
|
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return Representation::Tagged();
|
return Representation::Tagged();
|
||||||
@ -5533,9 +5541,10 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
|
|||||||
: HTemplateInstruction<2>(type),
|
: HTemplateInstruction<2>(type),
|
||||||
flags_(ComputeFlags(pretenure_flag, instance_type)),
|
flags_(ComputeFlags(pretenure_flag, instance_type)),
|
||||||
dominating_allocate_(NULL),
|
dominating_allocate_(NULL),
|
||||||
filler_free_space_size_(NULL) {
|
filler_free_space_size_(NULL),
|
||||||
|
size_upper_bound_(NULL) {
|
||||||
SetOperandAt(0, context);
|
SetOperandAt(0, context);
|
||||||
SetOperandAt(1, size);
|
UpdateSize(size);
|
||||||
set_representation(Representation::Tagged());
|
set_representation(Representation::Tagged());
|
||||||
SetFlag(kTrackSideEffectDominators);
|
SetFlag(kTrackSideEffectDominators);
|
||||||
SetChangesFlag(kNewSpacePromotion);
|
SetChangesFlag(kNewSpacePromotion);
|
||||||
@ -5582,6 +5591,11 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
|
|||||||
|
|
||||||
void UpdateSize(HValue* size) {
|
void UpdateSize(HValue* size) {
|
||||||
SetOperandAt(1, size);
|
SetOperandAt(1, size);
|
||||||
|
if (size->IsInteger32Constant()) {
|
||||||
|
size_upper_bound_ = HConstant::cast(size);
|
||||||
|
} else {
|
||||||
|
size_upper_bound_ = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HAllocate* GetFoldableDominator(HAllocate* dominator);
|
HAllocate* GetFoldableDominator(HAllocate* dominator);
|
||||||
@ -5603,6 +5617,7 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
|
|||||||
Handle<Map> known_initial_map_;
|
Handle<Map> known_initial_map_;
|
||||||
HAllocate* dominating_allocate_;
|
HAllocate* dominating_allocate_;
|
||||||
HStoreNamedField* filler_free_space_size_;
|
HStoreNamedField* filler_free_space_size_;
|
||||||
|
HConstant* size_upper_bound_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
469
src/hydrogen.cc
469
src/hydrogen.cc
@ -1535,25 +1535,18 @@ HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
|
|||||||
HValue* index,
|
HValue* index,
|
||||||
HValue* input) {
|
HValue* input) {
|
||||||
NoObservableSideEffectsScope scope(this);
|
NoObservableSideEffectsScope scope(this);
|
||||||
|
HConstant* max_length = Add<HConstant>(JSObject::kInitialMaxFastElementArray);
|
||||||
|
Add<HBoundsCheck>(length, max_length);
|
||||||
|
|
||||||
// Compute the size of the RegExpResult followed by FixedArray with length.
|
// Generate size calculation code here in order to make it dominate
|
||||||
HValue* size = length;
|
// the JSRegExpResult allocation.
|
||||||
// Make sure size does not exceed max regular heap object size.
|
ElementsKind elements_kind = FAST_ELEMENTS;
|
||||||
const int kHeaderSize = JSRegExpResult::kSize + FixedArray::kHeaderSize;
|
HValue* size = BuildCalculateElementsSize(elements_kind, length);
|
||||||
const int kMaxLength =
|
|
||||||
(Page::kMaxRegularHeapObjectSize - kHeaderSize) >> kPointerSizeLog2;
|
|
||||||
Add<HBoundsCheck>(size, Add<HConstant>(kMaxLength));
|
|
||||||
|
|
||||||
size = AddUncasted<HShl>(size, Add<HConstant>(kPointerSizeLog2));
|
|
||||||
size = AddUncasted<HAdd>(size, Add<HConstant>(kHeaderSize));
|
|
||||||
|
|
||||||
// Allocate the JSRegExpResult and the FixedArray in one step.
|
// Allocate the JSRegExpResult and the FixedArray in one step.
|
||||||
HValue* result = Add<HAllocate>(
|
HValue* result = Add<HAllocate>(
|
||||||
size, HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
|
Add<HConstant>(JSRegExpResult::kSize), HType::JSArray(),
|
||||||
|
NOT_TENURED, JS_ARRAY_TYPE);
|
||||||
// Determine the elements FixedArray.
|
|
||||||
HValue* elements = Add<HInnerAllocatedObject>(
|
|
||||||
result, Add<HConstant>(JSRegExpResult::kSize), HType::HeapObject());
|
|
||||||
|
|
||||||
// Initialize the JSRegExpResult header.
|
// Initialize the JSRegExpResult header.
|
||||||
HValue* global_object = Add<HLoadNamedField>(
|
HValue* global_object = Add<HLoadNamedField>(
|
||||||
@ -1567,12 +1560,14 @@ HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
|
|||||||
Add<HLoadNamedField>(
|
Add<HLoadNamedField>(
|
||||||
native_context, static_cast<HValue*>(NULL),
|
native_context, static_cast<HValue*>(NULL),
|
||||||
HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX)));
|
HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX)));
|
||||||
|
HConstant* empty_fixed_array =
|
||||||
|
Add<HConstant>(isolate()->factory()->empty_fixed_array());
|
||||||
Add<HStoreNamedField>(
|
Add<HStoreNamedField>(
|
||||||
result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset),
|
result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset),
|
||||||
Add<HConstant>(isolate()->factory()->empty_fixed_array()));
|
empty_fixed_array);
|
||||||
Add<HStoreNamedField>(
|
Add<HStoreNamedField>(
|
||||||
result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
|
result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
|
||||||
elements);
|
empty_fixed_array);
|
||||||
Add<HStoreNamedField>(
|
Add<HStoreNamedField>(
|
||||||
result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length);
|
result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length);
|
||||||
|
|
||||||
@ -1584,18 +1579,22 @@ HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
|
|||||||
result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset),
|
result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset),
|
||||||
input);
|
input);
|
||||||
|
|
||||||
// Initialize the elements header.
|
// Allocate and initialize the elements header.
|
||||||
AddStoreMapConstant(elements, isolate()->factory()->fixed_array_map());
|
HAllocate* elements = BuildAllocateElements(elements_kind, size);
|
||||||
Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), length);
|
BuildInitializeElementsHeader(elements, elements_kind, length);
|
||||||
|
|
||||||
|
HConstant* size_in_bytes_upper_bound = EstablishElementsAllocationSize(
|
||||||
|
elements_kind, max_length->Integer32Value());
|
||||||
|
elements->set_size_upper_bound(size_in_bytes_upper_bound);
|
||||||
|
|
||||||
|
Add<HStoreNamedField>(
|
||||||
|
result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
|
||||||
|
elements);
|
||||||
|
|
||||||
// Initialize the elements contents with undefined.
|
// Initialize the elements contents with undefined.
|
||||||
LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
|
BuildFillElementsWithValue(
|
||||||
index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
|
elements, elements_kind, graph()->GetConstant0(), length,
|
||||||
{
|
graph()->GetConstantUndefined());
|
||||||
Add<HStoreKeyed>(elements, index, graph()->GetConstantUndefined(),
|
|
||||||
FAST_ELEMENTS);
|
|
||||||
}
|
|
||||||
loop.EndBody();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2234,17 +2233,19 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::BuildAllocateArrayFromLength(
|
HValue* HGraphBuilder::BuildAllocateArrayFromLength(
|
||||||
JSArrayBuilder* array_builder,
|
JSArrayBuilder* array_builder,
|
||||||
HValue* length_argument) {
|
HValue* length_argument) {
|
||||||
if (length_argument->IsConstant() &&
|
if (length_argument->IsConstant() &&
|
||||||
HConstant::cast(length_argument)->HasSmiValue()) {
|
HConstant::cast(length_argument)->HasSmiValue()) {
|
||||||
int array_length = HConstant::cast(length_argument)->Integer32Value();
|
int array_length = HConstant::cast(length_argument)->Integer32Value();
|
||||||
HValue* new_object = array_length == 0
|
if (array_length == 0) {
|
||||||
? array_builder->AllocateEmptyArray()
|
return array_builder->AllocateEmptyArray();
|
||||||
: array_builder->AllocateArray(length_argument, length_argument);
|
} else {
|
||||||
return new_object;
|
return array_builder->AllocateArray(length_argument,
|
||||||
|
array_length,
|
||||||
|
length_argument);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HValue* constant_zero = graph()->GetConstant0();
|
HValue* constant_zero = graph()->GetConstant0();
|
||||||
@ -2274,32 +2275,61 @@ HValue* HGraphBuilder::BuildAllocateArrayFromLength(
|
|||||||
// Figure out total size
|
// Figure out total size
|
||||||
HValue* length = Pop();
|
HValue* length = Pop();
|
||||||
HValue* capacity = Pop();
|
HValue* capacity = Pop();
|
||||||
return array_builder->AllocateArray(capacity, length);
|
return array_builder->AllocateArray(capacity, max_alloc_length, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
|
HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind,
|
||||||
HValue* capacity) {
|
HValue* capacity) {
|
||||||
int elements_size;
|
int elements_size = IsFastDoubleElementsKind(kind)
|
||||||
InstanceType instance_type;
|
? kDoubleSize
|
||||||
|
: kPointerSize;
|
||||||
if (IsFastDoubleElementsKind(kind)) {
|
|
||||||
elements_size = kDoubleSize;
|
|
||||||
instance_type = FIXED_DOUBLE_ARRAY_TYPE;
|
|
||||||
} else {
|
|
||||||
elements_size = kPointerSize;
|
|
||||||
instance_type = FIXED_ARRAY_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HConstant* elements_size_value = Add<HConstant>(elements_size);
|
HConstant* elements_size_value = Add<HConstant>(elements_size);
|
||||||
HValue* mul = AddUncasted<HMul>(capacity, elements_size_value);
|
HInstruction* mul = HMul::NewImul(zone(), context(),
|
||||||
|
capacity->ActualValue(),
|
||||||
|
elements_size_value);
|
||||||
|
AddInstruction(mul);
|
||||||
mul->ClearFlag(HValue::kCanOverflow);
|
mul->ClearFlag(HValue::kCanOverflow);
|
||||||
|
|
||||||
|
STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
|
||||||
|
|
||||||
HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
|
HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
|
||||||
HValue* total_size = AddUncasted<HAdd>(mul, header_size);
|
HValue* total_size = AddUncasted<HAdd>(mul, header_size);
|
||||||
total_size->ClearFlag(HValue::kCanOverflow);
|
total_size->ClearFlag(HValue::kCanOverflow);
|
||||||
|
return total_size;
|
||||||
|
}
|
||||||
|
|
||||||
return Add<HAllocate>(total_size, HType::HeapObject(), NOT_TENURED,
|
|
||||||
|
HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) {
|
||||||
|
int base_size = JSArray::kSize;
|
||||||
|
if (mode == TRACK_ALLOCATION_SITE) {
|
||||||
|
base_size += AllocationMemento::kSize;
|
||||||
|
}
|
||||||
|
HConstant* size_in_bytes = Add<HConstant>(base_size);
|
||||||
|
return Add<HAllocate>(
|
||||||
|
size_in_bytes, HType::JSArray(), NOT_TENURED, JS_OBJECT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HConstant* HGraphBuilder::EstablishElementsAllocationSize(
|
||||||
|
ElementsKind kind,
|
||||||
|
int capacity) {
|
||||||
|
int base_size = IsFastDoubleElementsKind(kind)
|
||||||
|
? FixedDoubleArray::SizeFor(capacity)
|
||||||
|
: FixedArray::SizeFor(capacity);
|
||||||
|
|
||||||
|
return Add<HConstant>(base_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
|
||||||
|
HValue* size_in_bytes) {
|
||||||
|
InstanceType instance_type = IsFastDoubleElementsKind(kind)
|
||||||
|
? FIXED_DOUBLE_ARRAY_TYPE
|
||||||
|
: FIXED_ARRAY_TYPE;
|
||||||
|
|
||||||
|
return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED,
|
||||||
instance_type);
|
instance_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2324,43 +2354,39 @@ HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
|
|||||||
// The HForceRepresentation is to prevent possible deopt on int-smi
|
// The HForceRepresentation is to prevent possible deopt on int-smi
|
||||||
// conversion after allocation but before the new object fields are set.
|
// conversion after allocation but before the new object fields are set.
|
||||||
capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
|
capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
|
||||||
HValue* new_elements = BuildAllocateElements(kind, capacity);
|
HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
|
||||||
|
HValue* new_elements = BuildAllocateElements(kind, size_in_bytes);
|
||||||
BuildInitializeElementsHeader(new_elements, kind, capacity);
|
BuildInitializeElementsHeader(new_elements, kind, capacity);
|
||||||
return new_elements;
|
return new_elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
|
void HGraphBuilder::BuildJSArrayHeader(HValue* array,
|
||||||
HValue* array_map,
|
HValue* array_map,
|
||||||
AllocationSiteMode mode,
|
HValue* elements,
|
||||||
ElementsKind elements_kind,
|
AllocationSiteMode mode,
|
||||||
HValue* allocation_site_payload,
|
ElementsKind elements_kind,
|
||||||
HValue* length_field) {
|
HValue* allocation_site_payload,
|
||||||
|
HValue* length_field) {
|
||||||
Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
|
Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
|
||||||
|
|
||||||
HConstant* empty_fixed_array =
|
HConstant* empty_fixed_array =
|
||||||
Add<HConstant>(isolate()->factory()->empty_fixed_array());
|
Add<HConstant>(isolate()->factory()->empty_fixed_array());
|
||||||
|
|
||||||
HObjectAccess access = HObjectAccess::ForPropertiesPointer();
|
Add<HStoreNamedField>(
|
||||||
Add<HStoreNamedField>(array, access, empty_fixed_array);
|
array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array);
|
||||||
Add<HStoreNamedField>(array, HObjectAccess::ForArrayLength(elements_kind),
|
|
||||||
length_field);
|
Add<HStoreNamedField>(
|
||||||
|
array, HObjectAccess::ForElementsPointer(),
|
||||||
|
elements != NULL ? elements : empty_fixed_array);
|
||||||
|
|
||||||
|
Add<HStoreNamedField>(
|
||||||
|
array, HObjectAccess::ForArrayLength(elements_kind), length_field);
|
||||||
|
|
||||||
if (mode == TRACK_ALLOCATION_SITE) {
|
if (mode == TRACK_ALLOCATION_SITE) {
|
||||||
BuildCreateAllocationMemento(
|
BuildCreateAllocationMemento(
|
||||||
array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
|
array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
int elements_location = JSArray::kSize;
|
|
||||||
if (mode == TRACK_ALLOCATION_SITE) {
|
|
||||||
elements_location += AllocationMemento::kSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
|
|
||||||
array, Add<HConstant>(elements_location), HType::HeapObject());
|
|
||||||
Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
|
|
||||||
return elements;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2397,6 +2423,12 @@ HInstruction* HGraphBuilder::AddElementAccess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object,
|
||||||
|
HValue* dependency) {
|
||||||
|
return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
|
HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
|
||||||
HValue* dependency) {
|
HValue* dependency) {
|
||||||
return Add<HLoadNamedField>(
|
return Add<HLoadNamedField>(
|
||||||
@ -2449,7 +2481,7 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
|||||||
HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
|
HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
|
||||||
new_kind, new_capacity);
|
new_kind, new_capacity);
|
||||||
|
|
||||||
BuildCopyElements(object, elements, kind, new_elements,
|
BuildCopyElements(elements, kind, new_elements,
|
||||||
new_kind, length, new_capacity);
|
new_kind, length, new_capacity);
|
||||||
|
|
||||||
Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
||||||
@ -2459,19 +2491,11 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
|
||||||
ElementsKind elements_kind,
|
ElementsKind elements_kind,
|
||||||
HValue* from,
|
HValue* from,
|
||||||
HValue* to) {
|
HValue* to,
|
||||||
// Fast elements kinds need to be initialized in case statements below cause a
|
HValue* value) {
|
||||||
// garbage collection.
|
|
||||||
Factory* factory = isolate()->factory();
|
|
||||||
|
|
||||||
double nan_double = FixedDoubleArray::hole_nan_as_double();
|
|
||||||
HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
|
|
||||||
? Add<HConstant>(factory->the_hole_value())
|
|
||||||
: Add<HConstant>(nan_double);
|
|
||||||
|
|
||||||
if (to == NULL) {
|
if (to == NULL) {
|
||||||
to = AddLoadFixedArrayLength(elements);
|
to = AddLoadFixedArrayLength(elements);
|
||||||
}
|
}
|
||||||
@ -2498,7 +2522,7 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
|||||||
if (initial_capacity >= 0) {
|
if (initial_capacity >= 0) {
|
||||||
for (int i = 0; i < initial_capacity; i++) {
|
for (int i = 0; i < initial_capacity; i++) {
|
||||||
HInstruction* key = Add<HConstant>(i);
|
HInstruction* key = Add<HConstant>(i);
|
||||||
Add<HStoreKeyed>(elements, key, hole, elements_kind);
|
Add<HStoreKeyed>(elements, key, value, elements_kind);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Carefully loop backwards so that the "from" remains live through the loop
|
// Carefully loop backwards so that the "from" remains live through the loop
|
||||||
@ -2512,15 +2536,31 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
|||||||
HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
|
HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
|
||||||
adjusted_key->ClearFlag(HValue::kCanOverflow);
|
adjusted_key->ClearFlag(HValue::kCanOverflow);
|
||||||
|
|
||||||
Add<HStoreKeyed>(elements, adjusted_key, hole, elements_kind);
|
Add<HStoreKeyed>(elements, adjusted_key, value, elements_kind);
|
||||||
|
|
||||||
builder.EndBody();
|
builder.EndBody();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HGraphBuilder::BuildCopyElements(HValue* array,
|
void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
||||||
HValue* from_elements,
|
ElementsKind elements_kind,
|
||||||
|
HValue* from,
|
||||||
|
HValue* to) {
|
||||||
|
// Fast elements kinds need to be initialized in case statements below cause a
|
||||||
|
// garbage collection.
|
||||||
|
Factory* factory = isolate()->factory();
|
||||||
|
|
||||||
|
double nan_double = FixedDoubleArray::hole_nan_as_double();
|
||||||
|
HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
|
||||||
|
? Add<HConstant>(factory->the_hole_value())
|
||||||
|
: Add<HConstant>(nan_double);
|
||||||
|
|
||||||
|
BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HGraphBuilder::BuildCopyElements(HValue* from_elements,
|
||||||
ElementsKind from_elements_kind,
|
ElementsKind from_elements_kind,
|
||||||
HValue* to_elements,
|
HValue* to_elements,
|
||||||
ElementsKind to_elements_kind,
|
ElementsKind to_elements_kind,
|
||||||
@ -2607,88 +2647,43 @@ void HGraphBuilder::BuildCopyElements(HValue* array,
|
|||||||
AddIncrementCounter(counters->inlined_copied_elements());
|
AddIncrementCounter(counters->inlined_copied_elements());
|
||||||
}
|
}
|
||||||
|
|
||||||
HValue* HGraphBuilder::BuildCloneShallowArrayCommon(
|
|
||||||
HValue* boilerplate,
|
|
||||||
HValue* allocation_site,
|
|
||||||
HValue* extra_size,
|
|
||||||
HValue** return_elements,
|
|
||||||
AllocationSiteMode mode) {
|
|
||||||
// All sizes here are multiples of kPointerSize.
|
|
||||||
int array_size = JSArray::kSize;
|
|
||||||
if (mode == TRACK_ALLOCATION_SITE) {
|
|
||||||
array_size += AllocationMemento::kSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
HValue* size_in_bytes = Add<HConstant>(array_size);
|
|
||||||
if (extra_size != NULL) {
|
|
||||||
size_in_bytes = AddUncasted<HAdd>(extra_size, size_in_bytes);
|
|
||||||
size_in_bytes->ClearFlag(HValue::kCanOverflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
HInstruction* object = Add<HAllocate>(size_in_bytes,
|
|
||||||
HType::JSObject(),
|
|
||||||
NOT_TENURED,
|
|
||||||
JS_OBJECT_TYPE);
|
|
||||||
|
|
||||||
// Copy the JS array part.
|
|
||||||
HValue* map = Add<HLoadNamedField>(boilerplate,
|
|
||||||
static_cast<HValue*>(NULL), HObjectAccess::ForMap());
|
|
||||||
Add<HStoreNamedField>(object, HObjectAccess::ForPropertiesPointer(),
|
|
||||||
Add<HConstant>(isolate()->factory()->empty_fixed_array()),
|
|
||||||
INITIALIZING_STORE);
|
|
||||||
Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map,
|
|
||||||
INITIALIZING_STORE);
|
|
||||||
|
|
||||||
// Create an allocation site info if requested.
|
|
||||||
if (mode == TRACK_ALLOCATION_SITE) {
|
|
||||||
BuildCreateAllocationMemento(
|
|
||||||
object, Add<HConstant>(JSArray::kSize), allocation_site);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extra_size != NULL) {
|
|
||||||
HValue* elements = Add<HInnerAllocatedObject>(object,
|
|
||||||
Add<HConstant>(array_size), HType::HeapObject());
|
|
||||||
if (return_elements != NULL) *return_elements = elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::BuildCloneShallowArrayCow(HValue* boilerplate,
|
HValue* HGraphBuilder::BuildCloneShallowArrayCow(HValue* boilerplate,
|
||||||
HValue* allocation_site,
|
HValue* allocation_site,
|
||||||
AllocationSiteMode mode,
|
AllocationSiteMode mode,
|
||||||
ElementsKind kind) {
|
ElementsKind kind) {
|
||||||
HValue* result = BuildCloneShallowArrayCommon(boilerplate,
|
HAllocate* array = AllocateJSArrayObject(mode);
|
||||||
allocation_site, NULL, NULL, mode);
|
|
||||||
|
|
||||||
|
HValue* map = AddLoadMap(boilerplate);
|
||||||
HValue* elements = AddLoadElements(boilerplate);
|
HValue* elements = AddLoadElements(boilerplate);
|
||||||
HObjectAccess access = HObjectAccess::ForElementsPointer();
|
|
||||||
Add<HStoreNamedField>(result, access, elements, INITIALIZING_STORE);
|
|
||||||
|
|
||||||
HValue* length = AddLoadArrayLength(boilerplate, kind);
|
HValue* length = AddLoadArrayLength(boilerplate, kind);
|
||||||
access = HObjectAccess::ForArrayLength(kind);
|
|
||||||
Add<HStoreNamedField>(result, access, length, INITIALIZING_STORE);
|
|
||||||
|
|
||||||
return result;
|
BuildJSArrayHeader(array,
|
||||||
|
map,
|
||||||
|
elements,
|
||||||
|
mode,
|
||||||
|
FAST_ELEMENTS,
|
||||||
|
allocation_site,
|
||||||
|
length);
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::BuildCloneShallowArrayEmpty(HValue* boilerplate,
|
HValue* HGraphBuilder::BuildCloneShallowArrayEmpty(HValue* boilerplate,
|
||||||
HValue* allocation_site,
|
HValue* allocation_site,
|
||||||
AllocationSiteMode mode) {
|
AllocationSiteMode mode) {
|
||||||
HValue* result = BuildCloneShallowArrayCommon(boilerplate,
|
HAllocate* array = AllocateJSArrayObject(mode);
|
||||||
allocation_site, NULL, NULL, mode);
|
|
||||||
|
|
||||||
HObjectAccess access = HObjectAccess::ForArrayLength(FAST_ELEMENTS);
|
HValue* map = AddLoadMap(boilerplate);
|
||||||
Add<HStoreNamedField>(result, access, graph()->GetConstant0(),
|
|
||||||
INITIALIZING_STORE);
|
|
||||||
access = HObjectAccess::ForElementsPointer();
|
|
||||||
Add<HStoreNamedField>(result, access,
|
|
||||||
Add<HConstant>(isolate()->factory()->empty_fixed_array()),
|
|
||||||
INITIALIZING_STORE);
|
|
||||||
|
|
||||||
return result;
|
BuildJSArrayHeader(array,
|
||||||
|
map,
|
||||||
|
NULL, // set elements to empty fixed array
|
||||||
|
mode,
|
||||||
|
FAST_ELEMENTS,
|
||||||
|
allocation_site,
|
||||||
|
graph()->GetConstant0());
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2696,27 +2691,31 @@ HValue* HGraphBuilder::BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
|
|||||||
HValue* allocation_site,
|
HValue* allocation_site,
|
||||||
AllocationSiteMode mode,
|
AllocationSiteMode mode,
|
||||||
ElementsKind kind) {
|
ElementsKind kind) {
|
||||||
int elements_kind_size = IsFastDoubleElementsKind(kind)
|
|
||||||
? kDoubleSize : kPointerSize;
|
|
||||||
|
|
||||||
HValue* boilerplate_elements = AddLoadElements(boilerplate);
|
HValue* boilerplate_elements = AddLoadElements(boilerplate);
|
||||||
HValue* capacity = AddLoadFixedArrayLength(boilerplate_elements);
|
HValue* capacity = AddLoadFixedArrayLength(boilerplate_elements);
|
||||||
HValue* extra = AddUncasted<HMul>(capacity,
|
|
||||||
Add<HConstant>(elements_kind_size));
|
// Generate size calculation code here in order to make it dominate
|
||||||
extra->ClearFlag(HValue::kCanOverflow);
|
// the JSArray allocation.
|
||||||
extra = AddUncasted<HAdd>(extra, Add<HConstant>(FixedArray::kHeaderSize));
|
HValue* elements_size = BuildCalculateElementsSize(kind, capacity);
|
||||||
extra->ClearFlag(HValue::kCanOverflow);
|
|
||||||
|
// Create empty JSArray object for now, store elimination should remove
|
||||||
|
// redundant initialization of elements and length fields and at the same
|
||||||
|
// time the object will be fully prepared for GC if it happens during
|
||||||
|
// elements allocation.
|
||||||
|
HValue* result = BuildCloneShallowArrayEmpty(
|
||||||
|
boilerplate, allocation_site, mode);
|
||||||
|
|
||||||
|
HAllocate* elements = BuildAllocateElements(kind, elements_size);
|
||||||
|
|
||||||
// This function implicitly relies on the fact that the
|
// This function implicitly relies on the fact that the
|
||||||
// FastCloneShallowArrayStub is called only for literals shorter than
|
// FastCloneShallowArrayStub is called only for literals shorter than
|
||||||
// JSObject::kInitialMaxFastElementArray and therefore the size of the
|
// JSObject::kInitialMaxFastElementArray.
|
||||||
// resulting folded allocation will always be in allowed range.
|
|
||||||
// Can't add HBoundsCheck here because otherwise the stub will eager a frame.
|
// Can't add HBoundsCheck here because otherwise the stub will eager a frame.
|
||||||
|
HConstant* size_upper_bound = EstablishElementsAllocationSize(
|
||||||
|
kind, JSObject::kInitialMaxFastElementArray);
|
||||||
|
elements->set_size_upper_bound(size_upper_bound);
|
||||||
|
|
||||||
HValue* elements = NULL;
|
Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(), elements);
|
||||||
HValue* result = BuildCloneShallowArrayCommon(boilerplate,
|
|
||||||
allocation_site, extra, &elements, mode);
|
|
||||||
Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(),
|
|
||||||
elements, INITIALIZING_STORE);
|
|
||||||
|
|
||||||
// The allocation for the cloned array above causes register pressure on
|
// The allocation for the cloned array above causes register pressure on
|
||||||
// machines with low register counts. Force a reload of the boilerplate
|
// machines with low register counts. Force a reload of the boilerplate
|
||||||
@ -2730,19 +2729,15 @@ HValue* HGraphBuilder::BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
|
|||||||
HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
|
HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
|
||||||
Add<HStoreNamedField>(elements, access,
|
Add<HStoreNamedField>(elements, access,
|
||||||
Add<HLoadNamedField>(boilerplate_elements,
|
Add<HLoadNamedField>(boilerplate_elements,
|
||||||
static_cast<HValue*>(NULL), access),
|
static_cast<HValue*>(NULL), access));
|
||||||
INITIALIZING_STORE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the result of the length
|
// And the result of the length
|
||||||
HValue* length = Add<HLoadNamedField>(boilerplate, static_cast<HValue*>(NULL),
|
HValue* length = AddLoadArrayLength(boilerplate, kind);
|
||||||
HObjectAccess::ForArrayLength(kind));
|
Add<HStoreNamedField>(result, HObjectAccess::ForArrayLength(kind), length);
|
||||||
Add<HStoreNamedField>(result, HObjectAccess::ForArrayLength(kind),
|
|
||||||
length, INITIALIZING_STORE);
|
|
||||||
|
|
||||||
BuildCopyElements(result, boilerplate_elements, kind, elements,
|
BuildCopyElements(boilerplate_elements, kind, elements,
|
||||||
kind, length, NULL);
|
kind, length, NULL);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2937,67 +2932,47 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize(
|
HAllocate* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
|
||||||
HValue* length_node) {
|
|
||||||
ASSERT(length_node != NULL);
|
|
||||||
|
|
||||||
int base_size = JSArray::kSize;
|
|
||||||
if (mode_ == TRACK_ALLOCATION_SITE) {
|
|
||||||
base_size += AllocationMemento::kSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
|
|
||||||
base_size += FixedArray::kHeaderSize;
|
|
||||||
|
|
||||||
HInstruction* elements_size_value =
|
|
||||||
builder()->Add<HConstant>(elements_size());
|
|
||||||
HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(),
|
|
||||||
length_node, elements_size_value);
|
|
||||||
builder()->AddInstruction(mul);
|
|
||||||
HInstruction* base = builder()->Add<HConstant>(base_size);
|
|
||||||
HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(),
|
|
||||||
base, mul);
|
|
||||||
total_size->ClearFlag(HValue::kCanOverflow);
|
|
||||||
builder()->AddInstruction(total_size);
|
|
||||||
return total_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() {
|
|
||||||
int base_size = JSArray::kSize;
|
|
||||||
if (mode_ == TRACK_ALLOCATION_SITE) {
|
|
||||||
base_size += AllocationMemento::kSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_size += IsFastDoubleElementsKind(kind_)
|
|
||||||
? FixedDoubleArray::SizeFor(initial_capacity())
|
|
||||||
: FixedArray::SizeFor(initial_capacity());
|
|
||||||
|
|
||||||
return builder()->Add<HConstant>(base_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
|
|
||||||
HValue* size_in_bytes = EstablishEmptyArrayAllocationSize();
|
|
||||||
HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
|
HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
|
||||||
return AllocateArray(size_in_bytes,
|
return AllocateArray(capacity,
|
||||||
capacity,
|
capacity,
|
||||||
builder()->graph()->GetConstant0());
|
builder()->graph()->GetConstant0());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity,
|
HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
|
||||||
HValue* length_field,
|
HValue* capacity,
|
||||||
FillMode fill_mode) {
|
HConstant* capacity_upper_bound,
|
||||||
HValue* size_in_bytes = EstablishAllocationSize(capacity);
|
HValue* length_field,
|
||||||
return AllocateArray(size_in_bytes, capacity, length_field, fill_mode);
|
FillMode fill_mode) {
|
||||||
|
return AllocateArray(capacity,
|
||||||
|
capacity_upper_bound->GetInteger32Constant(),
|
||||||
|
length_field,
|
||||||
|
fill_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
|
HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
|
||||||
HValue* capacity,
|
HValue* capacity,
|
||||||
HValue* length_field,
|
int capacity_upper_bound,
|
||||||
FillMode fill_mode) {
|
HValue* length_field,
|
||||||
|
FillMode fill_mode) {
|
||||||
|
HConstant* elememts_size_upper_bound = capacity->IsInteger32Constant()
|
||||||
|
? HConstant::cast(capacity)
|
||||||
|
: builder()->EstablishElementsAllocationSize(kind_, capacity_upper_bound);
|
||||||
|
|
||||||
|
HAllocate* array = AllocateArray(capacity, length_field, fill_mode);
|
||||||
|
if (!elements_location_->has_size_upper_bound()) {
|
||||||
|
elements_location_->set_size_upper_bound(elememts_size_upper_bound);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
|
||||||
|
HValue* capacity,
|
||||||
|
HValue* length_field,
|
||||||
|
FillMode fill_mode) {
|
||||||
// These HForceRepresentations are because we store these as fields in the
|
// These HForceRepresentations are because we store these as fields in the
|
||||||
// objects we construct, and an int32-to-smi HChange could deopt. Accept
|
// objects we construct, and an int32-to-smi HChange could deopt. Accept
|
||||||
// the deopt possibility now, before allocation occurs.
|
// the deopt possibility now, before allocation occurs.
|
||||||
@ -3007,14 +2982,14 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
|
|||||||
length_field =
|
length_field =
|
||||||
builder()->AddUncasted<HForceRepresentation>(length_field,
|
builder()->AddUncasted<HForceRepresentation>(length_field,
|
||||||
Representation::Smi());
|
Representation::Smi());
|
||||||
// Allocate (dealing with failure appropriately)
|
|
||||||
HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
|
|
||||||
HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
|
|
||||||
|
|
||||||
// Folded array allocation should be aligned if it has fast double elements.
|
// Generate size calculation code here in order to make it dominate
|
||||||
if (IsFastDoubleElementsKind(kind_)) {
|
// the JSArray allocation.
|
||||||
new_object->MakeDoubleAligned();
|
HValue* elements_size =
|
||||||
}
|
builder()->BuildCalculateElementsSize(kind_, capacity);
|
||||||
|
|
||||||
|
// Allocate (dealing with failure appropriately)
|
||||||
|
HAllocate* array_object = builder()->AllocateJSArrayObject(mode_);
|
||||||
|
|
||||||
// Fill in the fields: map, properties, length
|
// Fill in the fields: map, properties, length
|
||||||
HValue* map;
|
HValue* map;
|
||||||
@ -3023,22 +2998,30 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
|
|||||||
} else {
|
} else {
|
||||||
map = EmitMapCode();
|
map = EmitMapCode();
|
||||||
}
|
}
|
||||||
elements_location_ = builder()->BuildJSArrayHeader(new_object,
|
|
||||||
map,
|
|
||||||
mode_,
|
|
||||||
kind_,
|
|
||||||
allocation_site_payload_,
|
|
||||||
length_field);
|
|
||||||
|
|
||||||
// Initialize the elements
|
builder()->BuildJSArrayHeader(array_object,
|
||||||
|
map,
|
||||||
|
NULL, // set elements to empty fixed array
|
||||||
|
mode_,
|
||||||
|
kind_,
|
||||||
|
allocation_site_payload_,
|
||||||
|
length_field);
|
||||||
|
|
||||||
|
// Allocate and initialize the elements
|
||||||
|
elements_location_ = builder()->BuildAllocateElements(kind_, elements_size);
|
||||||
|
|
||||||
builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
|
builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
|
||||||
|
|
||||||
|
// Set the elements
|
||||||
|
builder()->Add<HStoreNamedField>(
|
||||||
|
array_object, HObjectAccess::ForElementsPointer(), elements_location_);
|
||||||
|
|
||||||
if (fill_mode == FILL_WITH_HOLE) {
|
if (fill_mode == FILL_WITH_HOLE) {
|
||||||
builder()->BuildFillElementsWithHole(elements_location_, kind_,
|
builder()->BuildFillElementsWithHole(elements_location_, kind_,
|
||||||
graph()->GetConstant0(), capacity);
|
graph()->GetConstant0(), capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_object;
|
return array_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -10514,7 +10497,7 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
|||||||
HConstant* empty_fixed_array = Add<HConstant>(
|
HConstant* empty_fixed_array = Add<HConstant>(
|
||||||
isolate()->factory()->empty_fixed_array());
|
isolate()->factory()->empty_fixed_array());
|
||||||
Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
||||||
empty_fixed_array, INITIALIZING_STORE);
|
empty_fixed_array);
|
||||||
|
|
||||||
BuildEmitObjectHeader(boilerplate_object, object);
|
BuildEmitObjectHeader(boilerplate_object, object);
|
||||||
|
|
||||||
|
@ -1396,6 +1396,8 @@ class HGraphBuilder {
|
|||||||
return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
|
return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
|
||||||
Add<HConstant>(map));
|
Add<HConstant>(map));
|
||||||
}
|
}
|
||||||
|
HLoadNamedField* AddLoadMap(HValue* object,
|
||||||
|
HValue* dependency = NULL);
|
||||||
HLoadNamedField* AddLoadElements(HValue* object,
|
HLoadNamedField* AddLoadElements(HValue* object,
|
||||||
HValue* dependency = NULL);
|
HValue* dependency = NULL);
|
||||||
|
|
||||||
@ -1688,10 +1690,24 @@ class HGraphBuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ElementsKind kind() { return kind_; }
|
ElementsKind kind() { return kind_; }
|
||||||
|
HAllocate* elements_location() { return elements_location_; }
|
||||||
|
|
||||||
HValue* AllocateEmptyArray();
|
HAllocate* AllocateEmptyArray();
|
||||||
HValue* AllocateArray(HValue* capacity, HValue* length_field,
|
HAllocate* AllocateArray(HValue* capacity,
|
||||||
FillMode fill_mode = FILL_WITH_HOLE);
|
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* GetElementsLocation() { return elements_location_; }
|
||||||
HValue* EmitMapCode();
|
HValue* EmitMapCode();
|
||||||
|
|
||||||
@ -1708,25 +1724,23 @@ class HGraphBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HValue* EmitInternalMapCode();
|
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_;
|
HGraphBuilder* builder_;
|
||||||
ElementsKind kind_;
|
ElementsKind kind_;
|
||||||
AllocationSiteMode mode_;
|
AllocationSiteMode mode_;
|
||||||
HValue* allocation_site_payload_;
|
HValue* allocation_site_payload_;
|
||||||
HValue* constructor_function_;
|
HValue* constructor_function_;
|
||||||
HInnerAllocatedObject* elements_location_;
|
HAllocate* elements_location_;
|
||||||
};
|
};
|
||||||
|
|
||||||
HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
|
HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
|
||||||
HValue* length_argument);
|
HValue* length_argument);
|
||||||
|
HValue* BuildCalculateElementsSize(ElementsKind kind,
|
||||||
|
HValue* capacity);
|
||||||
|
HAllocate* AllocateJSArrayObject(AllocationSiteMode mode);
|
||||||
|
HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity);
|
||||||
|
|
||||||
HValue* BuildAllocateElements(ElementsKind kind,
|
HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes);
|
||||||
HValue* capacity);
|
|
||||||
|
|
||||||
void BuildInitializeElementsHeader(HValue* elements,
|
void BuildInitializeElementsHeader(HValue* elements,
|
||||||
ElementsKind kind,
|
ElementsKind kind,
|
||||||
@ -1735,16 +1749,17 @@ class HGraphBuilder {
|
|||||||
HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
|
HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
|
||||||
HValue* capacity);
|
HValue* capacity);
|
||||||
|
|
||||||
// array must have been allocated with enough room for
|
// |array| must have been allocated with enough room for
|
||||||
// 1) the JSArray, 2) a AllocationMemento if mode requires it,
|
// 1) the JSArray and 2) an AllocationMemento if mode requires it.
|
||||||
// 3) a FixedArray or FixedDoubleArray.
|
// If the |elements| value provided is NULL then the array elements storage
|
||||||
// A pointer to the Fixed(Double)Array is returned.
|
// is initialized with empty array.
|
||||||
HInnerAllocatedObject* BuildJSArrayHeader(HValue* array,
|
void BuildJSArrayHeader(HValue* array,
|
||||||
HValue* array_map,
|
HValue* array_map,
|
||||||
AllocationSiteMode mode,
|
HValue* elements,
|
||||||
ElementsKind elements_kind,
|
AllocationSiteMode mode,
|
||||||
HValue* allocation_site_payload,
|
ElementsKind elements_kind,
|
||||||
HValue* length_field);
|
HValue* allocation_site_payload,
|
||||||
|
HValue* length_field);
|
||||||
|
|
||||||
HValue* BuildGrowElementsCapacity(HValue* object,
|
HValue* BuildGrowElementsCapacity(HValue* object,
|
||||||
HValue* elements,
|
HValue* elements,
|
||||||
@ -1753,25 +1768,24 @@ class HGraphBuilder {
|
|||||||
HValue* length,
|
HValue* length,
|
||||||
HValue* new_capacity);
|
HValue* new_capacity);
|
||||||
|
|
||||||
|
void BuildFillElementsWithValue(HValue* elements,
|
||||||
|
ElementsKind elements_kind,
|
||||||
|
HValue* from,
|
||||||
|
HValue* to,
|
||||||
|
HValue* value);
|
||||||
|
|
||||||
void BuildFillElementsWithHole(HValue* elements,
|
void BuildFillElementsWithHole(HValue* elements,
|
||||||
ElementsKind elements_kind,
|
ElementsKind elements_kind,
|
||||||
HValue* from,
|
HValue* from,
|
||||||
HValue* to);
|
HValue* to);
|
||||||
|
|
||||||
void BuildCopyElements(HValue* array,
|
void BuildCopyElements(HValue* from_elements,
|
||||||
HValue* from_elements,
|
|
||||||
ElementsKind from_elements_kind,
|
ElementsKind from_elements_kind,
|
||||||
HValue* to_elements,
|
HValue* to_elements,
|
||||||
ElementsKind to_elements_kind,
|
ElementsKind to_elements_kind,
|
||||||
HValue* length,
|
HValue* length,
|
||||||
HValue* capacity);
|
HValue* capacity);
|
||||||
|
|
||||||
HValue* BuildCloneShallowArrayCommon(HValue* boilerplate,
|
|
||||||
HValue* allocation_site,
|
|
||||||
HValue* extra_size,
|
|
||||||
HValue** return_elements,
|
|
||||||
AllocationSiteMode mode);
|
|
||||||
|
|
||||||
HValue* BuildCloneShallowArrayCow(HValue* boilerplate,
|
HValue* BuildCloneShallowArrayCow(HValue* boilerplate,
|
||||||
HValue* allocation_site,
|
HValue* allocation_site,
|
||||||
AllocationSiteMode mode,
|
AllocationSiteMode mode,
|
||||||
|
Loading…
Reference in New Issue
Block a user