| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index ba0fcab3114ca4628d3b354b172c74e4b1a4c73f..60730ab6c17bb399ea9e52b3838768b51bdcabe9 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -2388,26 +2388,15 @@ HInstruction* HGraphBuilder::AddElementAccess(
|
| }
|
|
|
|
|
| -HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
|
| - HValue* dependency) {
|
| +HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) {
|
| return Add<HLoadNamedField>(
|
| - object, dependency, HObjectAccess::ForElementsPointer());
|
| + object, static_cast<HValue*>(NULL), HObjectAccess::ForElementsPointer());
|
| }
|
|
|
|
|
| -HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(
|
| - HValue* array,
|
| - HValue* dependency) {
|
| +HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) {
|
| return Add<HLoadNamedField>(
|
| - array, dependency, HObjectAccess::ForFixedArrayLength());
|
| -}
|
| -
|
| -
|
| -HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array,
|
| - ElementsKind kind,
|
| - HValue* dependency) {
|
| - return Add<HLoadNamedField>(
|
| - array, dependency, HObjectAccess::ForArrayLength(kind));
|
| + object, static_cast<HValue*>(NULL), HObjectAccess::ForFixedArrayLength());
|
| }
|
|
|
|
|
| @@ -2440,8 +2429,9 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
|
| HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
|
| new_kind, new_capacity);
|
|
|
| - BuildCopyElements(object, elements, kind, new_elements,
|
| - new_kind, length, new_capacity);
|
| + BuildCopyElements(elements, kind,
|
| + new_elements, new_kind,
|
| + length, new_capacity);
|
|
|
| Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
| new_elements);
|
| @@ -2454,8 +2444,8 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
| ElementsKind elements_kind,
|
| HValue* from,
|
| HValue* to) {
|
| - // Fast elements kinds need to be initialized in case statements below cause a
|
| - // garbage collection.
|
| + // 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();
|
| @@ -2463,10 +2453,6 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
| ? Add<HConstant>(factory->the_hole_value())
|
| : Add<HConstant>(nan_double);
|
|
|
| - if (to == NULL) {
|
| - to = AddLoadFixedArrayLength(elements);
|
| - }
|
| -
|
| // Special loop unfolding case
|
| static const int kLoopUnfoldLimit = 8;
|
| STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit);
|
| @@ -2492,144 +2478,104 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
|
| Add<HStoreKeyed>(elements, key, hole, elements_kind);
|
| }
|
| } else {
|
| - // Carefully loop backwards so that the "from" remains live through the loop
|
| - // rather than the to. This often corresponds to keeping length live rather
|
| - // then capacity, which helps register allocation, since length is used more
|
| - // other than capacity after filling with holes.
|
| - LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
|
| -
|
| - HValue* key = builder.BeginBody(to, from, Token::GT);
|
| + LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
|
|
|
| - HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
|
| - adjusted_key->ClearFlag(HValue::kCanOverflow);
|
| + HValue* key = builder.BeginBody(from, to, Token::LT);
|
|
|
| - Add<HStoreKeyed>(elements, adjusted_key, hole, elements_kind);
|
| + Add<HStoreKeyed>(elements, key, hole, elements_kind);
|
|
|
| builder.EndBody();
|
| }
|
| }
|
|
|
|
|
| -void HGraphBuilder::BuildCopyElements(HValue* array,
|
| - HValue* from_elements,
|
| +void HGraphBuilder::BuildCopyElements(HValue* from_elements,
|
| ElementsKind from_elements_kind,
|
| HValue* to_elements,
|
| ElementsKind to_elements_kind,
|
| HValue* length,
|
| HValue* capacity) {
|
| - int constant_capacity = -1;
|
| - if (capacity != NULL &&
|
| - capacity->IsConstant() &&
|
| - HConstant::cast(capacity)->HasInteger32Value()) {
|
| - int constant_candidate = HConstant::cast(capacity)->Integer32Value();
|
| - if (constant_candidate <=
|
| - FastCloneShallowArrayStub::kMaximumInlinedCloneLength) {
|
| - constant_capacity = constant_candidate;
|
| - }
|
| - }
|
| -
|
| - if (constant_capacity != -1) {
|
| - // Unroll the loop for small elements kinds.
|
| - for (int i = 0; i < constant_capacity; i++) {
|
| - HValue* key_constant = Add<HConstant>(i);
|
| - HInstruction* value = Add<HLoadKeyed>(from_elements, key_constant,
|
| - static_cast<HValue*>(NULL),
|
| - from_elements_kind);
|
| - Add<HStoreKeyed>(to_elements, key_constant, value, to_elements_kind);
|
| - }
|
| - } else {
|
| - bool pre_fill_with_holes =
|
| + bool pre_fill_with_holes =
|
| IsFastDoubleElementsKind(from_elements_kind) &&
|
| IsFastObjectElementsKind(to_elements_kind);
|
|
|
| - if (pre_fill_with_holes) {
|
| - // If the copy might trigger a GC, make sure that the FixedArray is
|
| - // pre-initialized with holes to make sure that it's always in a
|
| - // consistent state.
|
| - BuildFillElementsWithHole(to_elements, to_elements_kind,
|
| - graph()->GetConstant0(), NULL);
|
| - } else if (capacity == NULL || !length->Equals(capacity)) {
|
| - BuildFillElementsWithHole(to_elements, to_elements_kind,
|
| - length, NULL);
|
| - }
|
| -
|
| - if (capacity == NULL) {
|
| - capacity = AddLoadFixedArrayLength(to_elements);
|
| - }
|
| -
|
| - LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
|
| + if (pre_fill_with_holes) {
|
| + // If the copy might trigger a GC, make sure that the FixedArray is
|
| + // pre-initialized with holes to make sure that it's always in a consistent
|
| + // state.
|
| + BuildFillElementsWithHole(to_elements, to_elements_kind,
|
| + graph()->GetConstant0(), capacity);
|
| + }
|
|
|
| - HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
|
| - Token::GT);
|
| + LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
|
|
|
| - key = AddUncasted<HSub>(key, graph()->GetConstant1());
|
| - key->ClearFlag(HValue::kCanOverflow);
|
| + HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT);
|
|
|
| - HValue* element = Add<HLoadKeyed>(from_elements, key,
|
| - static_cast<HValue*>(NULL),
|
| - from_elements_kind,
|
| - ALLOW_RETURN_HOLE);
|
| + HValue* element = Add<HLoadKeyed>(from_elements, key,
|
| + static_cast<HValue*>(NULL),
|
| + from_elements_kind,
|
| + ALLOW_RETURN_HOLE);
|
|
|
| - ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
|
| - IsFastSmiElementsKind(to_elements_kind))
|
| + ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
|
| + IsFastSmiElementsKind(to_elements_kind))
|
| ? FAST_HOLEY_ELEMENTS : to_elements_kind;
|
|
|
| - if (IsHoleyElementsKind(from_elements_kind) &&
|
| - from_elements_kind != to_elements_kind) {
|
| - IfBuilder if_hole(this);
|
| - if_hole.If<HCompareHoleAndBranch>(element);
|
| - if_hole.Then();
|
| - HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
|
| + if (IsHoleyElementsKind(from_elements_kind) &&
|
| + from_elements_kind != to_elements_kind) {
|
| + IfBuilder if_hole(this);
|
| + if_hole.If<HCompareHoleAndBranch>(element);
|
| + if_hole.Then();
|
| + HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
|
| ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double())
|
| : graph()->GetConstantHole();
|
| - Add<HStoreKeyed>(to_elements, key, hole_constant, kind);
|
| - if_hole.Else();
|
| - HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
|
| - store->SetFlag(HValue::kAllowUndefinedAsNaN);
|
| - if_hole.End();
|
| - } else {
|
| - HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
|
| - store->SetFlag(HValue::kAllowUndefinedAsNaN);
|
| - }
|
| -
|
| - builder.EndBody();
|
| + Add<HStoreKeyed>(to_elements, key, hole_constant, kind);
|
| + if_hole.Else();
|
| + HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
|
| + store->SetFlag(HValue::kAllowUndefinedAsNaN);
|
| + if_hole.End();
|
| + } else {
|
| + HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
|
| + store->SetFlag(HValue::kAllowUndefinedAsNaN);
|
| }
|
|
|
| - Counters* counters = isolate()->counters();
|
| - AddIncrementCounter(counters->inlined_copied_elements());
|
| + builder.EndBody();
|
| +
|
| + if (!pre_fill_with_holes && length != capacity) {
|
| + // Fill unused capacity with the hole.
|
| + BuildFillElementsWithHole(to_elements, to_elements_kind,
|
| + key, capacity);
|
| + }
|
| }
|
|
|
| -HValue* HGraphBuilder::BuildCloneShallowArrayCommon(
|
| - HValue* boilerplate,
|
| - HValue* allocation_site,
|
| - HValue* extra_size,
|
| - HValue** return_elements,
|
| - AllocationSiteMode mode) {
|
| +
|
| +HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
|
| + HValue* allocation_site,
|
| + AllocationSiteMode mode,
|
| + ElementsKind kind,
|
| + int length) {
|
| + NoObservableSideEffectsScope no_effects(this);
|
| +
|
| // All sizes here are multiples of kPointerSize.
|
| - int array_size = JSArray::kSize;
|
| + int 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);
|
| + size += AllocationMemento::kSize;
|
| }
|
|
|
| + HValue* size_in_bytes = Add<HConstant>(size);
|
| 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);
|
| + for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
|
| + if ((i != JSArray::kElementsOffset) || (length == 0)) {
|
| + HObjectAccess access = HObjectAccess::ForJSArrayOffset(i);
|
| + Add<HStoreNamedField>(
|
| + object, access, Add<HLoadNamedField>(
|
| + boilerplate, static_cast<HValue*>(NULL), access));
|
| + }
|
| + }
|
|
|
| // Create an allocation site info if requested.
|
| if (mode == TRACK_ALLOCATION_SITE) {
|
| @@ -2637,102 +2583,54 @@ HValue* HGraphBuilder::BuildCloneShallowArrayCommon(
|
| object, Add<HConstant>(JSArray::kSize), allocation_site);
|
| }
|
|
|
| - if (extra_size != NULL) {
|
| - HValue* elements = Add<HInnerAllocatedObject>(object,
|
| - Add<HConstant>(array_size));
|
| - if (return_elements != NULL) *return_elements = elements;
|
| + if (length > 0) {
|
| + // We have to initialize the elements pointer if allocation folding is
|
| + // turned off.
|
| + if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
|
| + HConstant* empty_fixed_array = Add<HConstant>(
|
| + isolate()->factory()->empty_fixed_array());
|
| + Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
| + empty_fixed_array, INITIALIZING_STORE);
|
| + }
|
| +
|
| + HValue* boilerplate_elements = AddLoadElements(boilerplate);
|
| + HValue* object_elements;
|
| + if (IsFastDoubleElementsKind(kind)) {
|
| + HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length));
|
| + object_elements = Add<HAllocate>(elems_size, HType::Tagged(),
|
| + NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE);
|
| + } else {
|
| + HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length));
|
| + object_elements = Add<HAllocate>(elems_size, HType::Tagged(),
|
| + NOT_TENURED, FIXED_ARRAY_TYPE);
|
| + }
|
| + Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
|
| + object_elements);
|
| +
|
| + // Copy the elements array header.
|
| + for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
|
| + HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
|
| + Add<HStoreNamedField>(
|
| + object_elements, access, Add<HLoadNamedField>(
|
| + boilerplate_elements, static_cast<HValue*>(NULL), access));
|
| + }
|
| +
|
| + // Copy the elements array contents.
|
| + // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold
|
| + // copying loops with constant length up to a given boundary and use this
|
| + // helper here instead.
|
| + for (int i = 0; i < length; i++) {
|
| + HValue* key_constant = Add<HConstant>(i);
|
| + HInstruction* value = Add<HLoadKeyed>(boilerplate_elements, key_constant,
|
| + static_cast<HValue*>(NULL), kind);
|
| + Add<HStoreKeyed>(object_elements, key_constant, value, kind);
|
| + }
|
| }
|
|
|
| return object;
|
| }
|
|
|
|
|
| -HValue* HGraphBuilder::BuildCloneShallowArrayCow(HValue* boilerplate,
|
| - HValue* allocation_site,
|
| - AllocationSiteMode mode,
|
| - ElementsKind kind) {
|
| - HValue* result = BuildCloneShallowArrayCommon(boilerplate,
|
| - allocation_site, NULL, NULL, mode);
|
| -
|
| - HValue* elements = AddLoadElements(boilerplate);
|
| - HObjectAccess access = HObjectAccess::ForElementsPointer();
|
| - Add<HStoreNamedField>(result, access, elements, INITIALIZING_STORE);
|
| -
|
| - HValue* length = AddLoadArrayLength(boilerplate, kind);
|
| - access = HObjectAccess::ForArrayLength(kind);
|
| - Add<HStoreNamedField>(result, access, length, INITIALIZING_STORE);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -
|
| -HValue* HGraphBuilder::BuildCloneShallowArrayEmpty(HValue* boilerplate,
|
| - HValue* allocation_site,
|
| - AllocationSiteMode mode) {
|
| - HValue* result = BuildCloneShallowArrayCommon(boilerplate,
|
| - allocation_site, NULL, NULL, mode);
|
| -
|
| - HObjectAccess access = HObjectAccess::ForArrayLength(FAST_ELEMENTS);
|
| - 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;
|
| -}
|
| -
|
| -
|
| -HValue* HGraphBuilder::BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
|
| - HValue* allocation_site,
|
| - AllocationSiteMode mode,
|
| - ElementsKind kind) {
|
| - int elements_kind_size = IsFastDoubleElementsKind(kind)
|
| - ? kDoubleSize : kPointerSize;
|
| -
|
| - HValue* boilerplate_elements = AddLoadElements(boilerplate);
|
| - HValue* capacity = AddLoadFixedArrayLength(boilerplate_elements);
|
| - HValue* extra = AddUncasted<HMul>(capacity,
|
| - Add<HConstant>(elements_kind_size));
|
| - extra->ClearFlag(HValue::kCanOverflow);
|
| - extra = AddUncasted<HAdd>(extra, Add<HConstant>(FixedArray::kHeaderSize));
|
| - extra->ClearFlag(HValue::kCanOverflow);
|
| - HValue* elements = NULL;
|
| - 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
|
| - // machines with low register counts. Force a reload of the boilerplate
|
| - // elements here to free up a register for the allocation to avoid unnecessary
|
| - // spillage.
|
| - boilerplate_elements = AddLoadElements(boilerplate);
|
| - boilerplate_elements->SetFlag(HValue::kCantBeReplaced);
|
| -
|
| - // Copy the elements array header.
|
| - for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
|
| - HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
|
| - Add<HStoreNamedField>(elements, access,
|
| - Add<HLoadNamedField>(boilerplate_elements,
|
| - static_cast<HValue*>(NULL), access),
|
| - INITIALIZING_STORE);
|
| - }
|
| -
|
| - // And the result of the length
|
| - HValue* length = Add<HLoadNamedField>(boilerplate, static_cast<HValue*>(NULL),
|
| - HObjectAccess::ForArrayLength(kind));
|
| - Add<HStoreNamedField>(result, HObjectAccess::ForArrayLength(kind),
|
| - length, INITIALIZING_STORE);
|
| -
|
| - BuildCopyElements(result, boilerplate_elements, kind, elements,
|
| - kind, length, NULL);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -
|
| void HGraphBuilder::BuildCompareNil(
|
| HValue* value,
|
| Type* type,
|
|
|