summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-builtin-reducer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-builtin-reducer.cc')
-rw-r--r--deps/v8/src/compiler/js-builtin-reducer.cc742
1 files changed, 80 insertions, 662 deletions
diff --git a/deps/v8/src/compiler/js-builtin-reducer.cc b/deps/v8/src/compiler/js-builtin-reducer.cc
index df6fdba3f0..7ff2bf6d5e 100644
--- a/deps/v8/src/compiler/js-builtin-reducer.cc
+++ b/deps/v8/src/compiler/js-builtin-reducer.cc
@@ -109,49 +109,22 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
namespace {
-MaybeHandle<Map> GetMapWitness(Node* node) {
+Maybe<InstanceType> GetInstanceTypeWitness(Node* node) {
ZoneHandleSet<Map> maps;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &maps);
- if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
- return maps[0];
- }
- return MaybeHandle<Map>();
-}
-// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
-bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
- DCHECK(!jsarray_map->is_dictionary_map());
- Isolate* isolate = jsarray_map->GetIsolate();
- Handle<Name> length_string = isolate->factory()->length_string();
- DescriptorArray* descriptors = jsarray_map->instance_descriptors();
- int number =
- descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
- DCHECK_NE(DescriptorArray::kNotFound, number);
- return descriptors->GetDetails(number).IsReadOnly();
-}
+ if (result == NodeProperties::kNoReceiverMaps || maps.size() == 0) {
+ return Nothing<InstanceType>();
+ }
-// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
-bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
- Isolate* const isolate = receiver_map->GetIsolate();
- if (!receiver_map->prototype()->IsJSArray()) return false;
- Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
- isolate);
- // Ensure that all prototypes of the {receiver} are stable.
- for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
- !it.IsAtEnd(); it.Advance()) {
- Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
- if (!current->map()->is_stable()) return false;
+ InstanceType first_type = maps[0]->instance_type();
+ for (const Handle<Map>& map : maps) {
+ if (map->instance_type() != first_type) return Nothing<InstanceType>();
}
- return receiver_map->instance_type() == JS_ARRAY_TYPE &&
- IsFastElementsKind(receiver_map->elements_kind()) &&
- !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
- (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
- isolate->IsNoElementsProtectorIntact() &&
- isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
- !IsReadOnlyLengthDescriptor(receiver_map);
+ return Just(first_type);
}
bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
@@ -189,7 +162,7 @@ bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
IterationKind kind) {
Handle<Map> receiver_map;
- if (GetMapWitness(node).ToHandle(&receiver_map)) {
+ if (NodeProperties::GetMapWitness(node).ToHandle(&receiver_map)) {
return ReduceArrayIterator(receiver_map, node, kind,
ArrayIteratorKind::kArray);
}
@@ -199,7 +172,7 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node,
IterationKind kind) {
Handle<Map> receiver_map;
- if (GetMapWitness(node).ToHandle(&receiver_map) &&
+ if (NodeProperties::GetMapWitness(node).ToHandle(&receiver_map) &&
receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) {
return ReduceArrayIterator(receiver_map, node, kind,
ArrayIteratorKind::kTypedArray);
@@ -313,8 +286,9 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
return Replace(value);
}
-Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
- Handle<Map> iterator_map, Node* node, IterationKind kind) {
+Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(InstanceType type,
+ Node* node,
+ IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
@@ -327,8 +301,8 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return NoChange();
}
- ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
- iterator_map->instance_type());
+ ElementsKind elements_kind =
+ JSArrayIterator::ElementsKindForInstanceType(type);
if (IsHoleyElementsKind(elements_kind)) {
if (!isolate()->IsNoElementsProtectorIntact()) {
@@ -484,15 +458,16 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return Replace(value);
}
-Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
- Handle<Map> iterator_map, Node* node, IterationKind kind) {
+Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(InstanceType type,
+ Node* node,
+ IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
- ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
- iterator_map->instance_type());
+ ElementsKind elements_kind =
+ JSArrayIterator::ElementsKindForInstanceType(type);
Node* array = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
@@ -725,65 +700,58 @@ Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) {
}
Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
- Handle<Map> receiver_map;
- if (GetMapWitness(node).ToHandle(&receiver_map)) {
- switch (receiver_map->instance_type()) {
- case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
- return ReduceTypedArrayIteratorNext(receiver_map, node,
- IterationKind::kKeys);
-
- case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
- return ReduceFastArrayIteratorNext(receiver_map, node,
- IterationKind::kKeys);
-
- case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- return ReduceTypedArrayIteratorNext(receiver_map, node,
- IterationKind::kEntries);
-
- case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
- return ReduceFastArrayIteratorNext(receiver_map, node,
- IterationKind::kEntries);
-
- case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
- return ReduceTypedArrayIteratorNext(receiver_map, node,
- IterationKind::kValues);
-
- case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
- case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
- return ReduceFastArrayIteratorNext(receiver_map, node,
- IterationKind::kValues);
-
- default:
- // Slow array iterators are not reduced
- return NoChange();
- }
+ Maybe<InstanceType> maybe_type = GetInstanceTypeWitness(node);
+ if (!maybe_type.IsJust()) return NoChange();
+ InstanceType type = maybe_type.FromJust();
+ switch (type) {
+ case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(type, node, IterationKind::kKeys);
+
+ case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(type, node, IterationKind::kKeys);
+
+ case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(type, node, IterationKind::kEntries);
+
+ case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(type, node, IterationKind::kEntries);
+
+ case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(type, node, IterationKind::kValues);
+
+ case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(type, node, IterationKind::kValues);
+
+ default:
+ // Slow array iterators are not reduced
+ return NoChange();
}
- return NoChange();
}
// ES6 section 22.1.2.2 Array.isArray ( arg )
@@ -896,398 +864,6 @@ Reduction JSBuiltinReducer::ReduceArrayIsArray(Node* node) {
return Replace(value);
}
-// ES6 section 22.1.3.17 Array.prototype.pop ( )
-Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
- Handle<Map> receiver_map;
- Node* receiver = NodeProperties::GetValueInput(node, 1);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
- // TODO(turbofan): Extend this to also handle fast holey double elements
- // once we got the hole NaN mess sorted out in TurboFan/V8.
- if (GetMapWitness(node).ToHandle(&receiver_map) &&
- CanInlineArrayResizeOperation(receiver_map) &&
- receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
- // Install code dependencies on the {receiver} prototype maps and the
- // global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
- dependencies()->AssumePrototypeMapsStable(receiver_map);
-
- // Load the "length" property of the {receiver}.
- Node* length = effect = graph()->NewNode(
- simplified()->LoadField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, effect, control);
-
- // Check if the {receiver} has any elements.
- Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
- jsgraph()->ZeroConstant());
- Node* branch =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* etrue = effect;
- Node* vtrue = jsgraph()->UndefinedConstant();
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* efalse = effect;
- Node* vfalse;
- {
- // TODO(tebbi): We should trim the backing store if the capacity is too
- // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
-
- // Load the elements backing store from the {receiver}.
- Node* elements = efalse = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
- receiver, efalse, if_false);
-
- // Ensure that we aren't popping from a copy-on-write backing store.
- if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
- elements = efalse =
- graph()->NewNode(simplified()->EnsureWritableFastElements(),
- receiver, elements, efalse, if_false);
- }
-
- // Compute the new {length}.
- length = graph()->NewNode(simplified()->NumberSubtract(), length,
- jsgraph()->OneConstant());
-
- // Store the new {length} to the {receiver}.
- efalse = graph()->NewNode(
- simplified()->StoreField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, length, efalse, if_false);
-
- // Load the last entry from the {elements}.
- vfalse = efalse = graph()->NewNode(
- simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
- receiver_map->elements_kind())),
- elements, length, efalse, if_false);
-
- // Store a hole to the element we just removed from the {receiver}.
- efalse = graph()->NewNode(
- simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
- GetHoleyElementsKind(receiver_map->elements_kind()))),
- elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
- }
-
- control = graph()->NewNode(common()->Merge(2), if_true, if_false);
- effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
- Node* value =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue, vfalse, control);
-
- // Convert the hole to undefined. Do this last, so that we can optimize
- // conversion operator via some smart strength reduction in many cases.
- if (IsHoleyElementsKind(receiver_map->elements_kind())) {
- value =
- graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
- }
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
- return NoChange();
-}
-
-// ES6 section 22.1.3.18 Array.prototype.push ( )
-Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
- DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
- int const num_values = node->op()->ValueInputCount() - 2;
- Node* receiver = NodeProperties::GetValueInput(node, 1);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
- ZoneHandleSet<Map> receiver_maps;
- NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
- if (receiver_maps.size() != 1) return NoChange();
- DCHECK_NE(NodeProperties::kNoReceiverMaps, result);
-
- // TODO(turbofan): Relax this to deal with multiple {receiver} maps.
- Handle<Map> receiver_map = receiver_maps[0];
- if (CanInlineArrayResizeOperation(receiver_map)) {
- // Collect the value inputs to push.
- std::vector<Node*> values(num_values);
- for (int i = 0; i < num_values; ++i) {
- values[i] = NodeProperties::GetValueInput(node, 2 + i);
- }
-
- // Install code dependencies on the {receiver} prototype maps and the
- // global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
- dependencies()->AssumePrototypeMapsStable(receiver_map);
-
- // If the {receiver_maps} information is not reliable, we need
- // to check that the {receiver} still has one of these maps.
- if (result == NodeProperties::kUnreliableReceiverMaps) {
- if (receiver_map->is_stable()) {
- dependencies()->AssumeMapStable(receiver_map);
- } else {
- // TODO(turbofan): This is a potential - yet unlikely - deoptimization
- // loop, since we might not learn from this deoptimization in baseline
- // code. We need a way to learn from deoptimizations in optimized to
- // address these problems.
- effect = graph()->NewNode(
- simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps),
- receiver, effect, control);
- }
- }
-
- // TODO(turbofan): Perform type checks on the {values}. We are not
- // guaranteed to learn from these checks in case they fail, as the witness
- // (i.e. the map check from the LoadIC for a.push) might not be executed in
- // baseline code (after we stored the value in the builtin and thereby
- // changed the elements kind of a) before be decide to optimize this
- // function again. We currently don't have a proper way to deal with this;
- // the proper solution here is to learn on deopt, i.e. disable
- // Array.prototype.push inlining for this function.
- for (auto& value : values) {
- if (IsSmiElementsKind(receiver_map->elements_kind())) {
- value = effect =
- graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
- } else if (IsDoubleElementsKind(receiver_map->elements_kind())) {
- value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
- effect, control);
- // Make sure we do not store signaling NaNs into double arrays.
- value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
- }
- }
-
- // Load the "length" property of the {receiver}.
- Node* length = effect = graph()->NewNode(
- simplified()->LoadField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, effect, control);
- Node* value = length;
-
- // Check if we have any {values} to push.
- if (num_values > 0) {
- // Compute the resulting "length" of the {receiver}.
- Node* new_length = value = graph()->NewNode(
- simplified()->NumberAdd(), length, jsgraph()->Constant(num_values));
-
- // Load the elements backing store of the {receiver}.
- Node* elements = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
- receiver, effect, control);
- Node* elements_length = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
- elements, effect, control);
-
- // TODO(turbofan): Check if we need to grow the {elements} backing store.
- // This will deopt if we cannot grow the array further, and we currently
- // don't necessarily learn from it. See the comment on the value type
- // check above.
- GrowFastElementsMode mode =
- IsDoubleElementsKind(receiver_map->elements_kind())
- ? GrowFastElementsMode::kDoubleElements
- : GrowFastElementsMode::kSmiOrObjectElements;
- elements = effect = graph()->NewNode(
- simplified()->MaybeGrowFastElements(mode), receiver, elements,
- graph()->NewNode(simplified()->NumberAdd(), length,
- jsgraph()->Constant(num_values - 1)),
- elements_length, effect, control);
-
- // Update the JSArray::length field. Since this is observable,
- // there must be no other check after this.
- effect = graph()->NewNode(
- simplified()->StoreField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, new_length, effect, control);
-
- // Append the {values} to the {elements}.
- for (int i = 0; i < num_values; ++i) {
- Node* value = values[i];
- Node* index = graph()->NewNode(simplified()->NumberAdd(), length,
- jsgraph()->Constant(i));
- effect = graph()->NewNode(
- simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
- receiver_map->elements_kind())),
- elements, index, value, effect, control);
- }
- }
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
- return NoChange();
-}
-
-// ES6 section 22.1.3.22 Array.prototype.shift ( )
-Reduction JSBuiltinReducer::ReduceArrayShift(Node* node) {
- Node* target = NodeProperties::GetValueInput(node, 0);
- Node* receiver = NodeProperties::GetValueInput(node, 1);
- Node* context = NodeProperties::GetContextInput(node);
- Node* frame_state = NodeProperties::GetFrameStateInput(node);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
-
- // TODO(turbofan): Extend this to also handle fast holey double elements
- // once we got the hole NaN mess sorted out in TurboFan/V8.
- Handle<Map> receiver_map;
- if (GetMapWitness(node).ToHandle(&receiver_map) &&
- CanInlineArrayResizeOperation(receiver_map) &&
- receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
- // Install code dependencies on the {receiver} prototype maps and the
- // global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
- dependencies()->AssumePrototypeMapsStable(receiver_map);
-
- // Load length of the {receiver}.
- Node* length = effect = graph()->NewNode(
- simplified()->LoadField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, effect, control);
-
- // Return undefined if {receiver} has no elements.
- Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
- jsgraph()->ZeroConstant());
- Node* branch0 =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
-
- Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
- Node* etrue0 = effect;
- Node* vtrue0 = jsgraph()->UndefinedConstant();
-
- Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
- Node* efalse0 = effect;
- Node* vfalse0;
- {
- // Check if we should take the fast-path.
- Node* check1 =
- graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
- jsgraph()->Constant(JSArray::kMaxCopyElements));
- Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check1, if_false0);
-
- Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
- Node* etrue1 = efalse0;
- Node* vtrue1;
- {
- Node* elements = etrue1 = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
- receiver, etrue1, if_true1);
-
- // Load the first element here, which we return below.
- vtrue1 = etrue1 = graph()->NewNode(
- simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
- receiver_map->elements_kind())),
- elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
-
- // Ensure that we aren't shifting a copy-on-write backing store.
- if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
- elements = etrue1 =
- graph()->NewNode(simplified()->EnsureWritableFastElements(),
- receiver, elements, etrue1, if_true1);
- }
-
- // Shift the remaining {elements} by one towards the start.
- Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
- Node* eloop =
- graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
- Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
- NodeProperties::MergeControlToEnd(graph(), common(), terminate);
- Node* index = graph()->NewNode(
- common()->Phi(MachineRepresentation::kTagged, 2),
- jsgraph()->OneConstant(),
- jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
-
- {
- Node* check2 =
- graph()->NewNode(simplified()->NumberLessThan(), index, length);
- Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
-
- if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
- etrue1 = eloop;
-
- Node* control = graph()->NewNode(common()->IfTrue(), branch2);
- Node* effect = etrue1;
-
- ElementAccess const access = AccessBuilder::ForFixedArrayElement(
- receiver_map->elements_kind());
- Node* value = effect =
- graph()->NewNode(simplified()->LoadElement(access), elements,
- index, effect, control);
- effect = graph()->NewNode(
- simplified()->StoreElement(access), elements,
- graph()->NewNode(simplified()->NumberSubtract(), index,
- jsgraph()->OneConstant()),
- value, effect, control);
-
- loop->ReplaceInput(1, control);
- eloop->ReplaceInput(1, effect);
- index->ReplaceInput(1,
- graph()->NewNode(simplified()->NumberAdd(), index,
- jsgraph()->OneConstant()));
- }
-
- // Compute the new {length}.
- length = graph()->NewNode(simplified()->NumberSubtract(), length,
- jsgraph()->OneConstant());
-
- // Store the new {length} to the {receiver}.
- etrue1 = graph()->NewNode(
- simplified()->StoreField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
- receiver, length, etrue1, if_true1);
-
- // Store a hole to the element we just removed from the {receiver}.
- etrue1 = graph()->NewNode(
- simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
- GetHoleyElementsKind(receiver_map->elements_kind()))),
- elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
- }
-
- Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
- Node* efalse1 = efalse0;
- Node* vfalse1;
- {
- // Call the generic C++ implementation.
- const int builtin_index = Builtins::kArrayShift;
- CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor(
- graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
- Builtins::name(builtin_index), node->op()->properties(),
- CallDescriptor::kNeedsFrameState);
- Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs,
- kArgvOnStack, true);
- Address builtin_entry = Builtins::CppEntryOf(builtin_index);
- Node* entry = jsgraph()->ExternalConstant(
- ExternalReference(builtin_entry, isolate()));
- Node* argc =
- jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
- if_false1 = efalse1 = vfalse1 =
- graph()->NewNode(common()->Call(desc), stub_code, receiver,
- jsgraph()->PaddingConstant(), argc, target,
- jsgraph()->UndefinedConstant(), entry, argc,
- context, frame_state, efalse1, if_false1);
- }
-
- if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
- efalse0 =
- graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
- vfalse0 =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue1, vfalse1, if_false0);
- }
-
- control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
- effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
- Node* value =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue0, vfalse0, control);
-
- // Convert the hole to undefined. Do this last, so that we can optimize
- // conversion operator via some smart strength reduction in many cases.
- if (IsHoleyElementsKind(receiver_map->elements_kind())) {
- value =
- graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
- }
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
- return NoChange();
-}
-
namespace {
bool HasInstanceTypeWitness(Node* receiver, Node* effect,
@@ -1451,6 +1027,7 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
index = effect = graph()->NewNode(
common()->Call(desc), jsgraph()->HeapConstant(callable.code()), table,
index, jsgraph()->NoContextConstant(), effect);
+ NodeProperties::SetType(index, type_cache_.kFixedArrayLengthType);
// Update the {index} and {table} on the {receiver}.
effect = graph()->NewNode(
@@ -1562,8 +1139,9 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
// Abort loop with resulting value.
Node* control = graph()->NewNode(common()->IfFalse(), branch1);
Node* effect = etrue0;
- Node* value = graph()->NewNode(
- common()->TypeGuard(Type::NonInternal()), entry_key, control);
+ Node* value = effect =
+ graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
+ entry_key, effect, control);
Node* done = jsgraph()->FalseConstant();
// Advance the index on the {receiver}.
@@ -2369,122 +1947,6 @@ Node* GetStringWitness(Node* node) {
} // namespace
-// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
-Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
- // We need at least target, receiver and index parameters.
- if (node->op()->ValueInputCount() >= 3) {
- Node* index = NodeProperties::GetValueInput(node, 2);
- Type* index_type = NodeProperties::GetType(index);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
-
- if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
- if (Node* receiver = GetStringWitness(node)) {
- if (!index_type->Is(Type::Unsigned32())) {
- // Map -0 and NaN to 0 (as per ToInteger), and the values in
- // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
- // be considered out-of-bounds as well, because of the maximal
- // String length limit in V8.
- STATIC_ASSERT(String::kMaxLength <= kMaxInt);
- index = graph()->NewNode(simplified()->NumberToUint32(), index);
- }
-
- // Determine the {receiver} length.
- Node* receiver_length = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
- effect, control);
-
- // Check if {index} is less than {receiver} length.
- Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
- receiver_length);
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check, control);
-
- // Return the character from the {receiver} as single character string.
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-
- Node* masked_index = graph()->NewNode(
- simplified()->MaskIndexWithBound(), index, receiver_length);
-
- Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
- masked_index, if_true);
-
- // Return the empty string otherwise.
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* vfalse = jsgraph()->EmptyStringConstant();
-
- control = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* value =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue, vfalse, control);
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
- }
- }
-
- return NoChange();
-}
-
-// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
-Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
- // We need at least target, receiver and index parameters.
- if (node->op()->ValueInputCount() >= 3) {
- Node* index = NodeProperties::GetValueInput(node, 2);
- Type* index_type = NodeProperties::GetType(index);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
-
- if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
- if (Node* receiver = GetStringWitness(node)) {
- if (!index_type->Is(Type::Unsigned32())) {
- // Map -0 and NaN to 0 (as per ToInteger), and the values in
- // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
- // be considered out-of-bounds as well, because of the maximal
- // String length limit in V8.
- STATIC_ASSERT(String::kMaxLength <= kMaxInt);
- index = graph()->NewNode(simplified()->NumberToUint32(), index);
- }
-
- // Determine the {receiver} length.
- Node* receiver_length = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
- effect, control);
-
- // Check if {index} is less than {receiver} length.
- Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
- receiver_length);
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check, control);
-
- // Load the character from the {receiver}.
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-
- Node* masked_index = graph()->NewNode(
- simplified()->MaskIndexWithBound(), index, receiver_length);
-
- Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
- receiver, masked_index, if_true);
-
- // Return NaN otherwise.
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* vfalse = jsgraph()->NaNConstant();
-
- control = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* value =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue, vfalse, control);
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
- }
- }
-
- return NoChange();
-}
-
// ES6 String.prototype.concat(...args)
// #sec-string.prototype.concat
Reduction JSBuiltinReducer::ReduceStringConcat(Node* node) {
@@ -2516,34 +1978,6 @@ Reduction JSBuiltinReducer::ReduceStringConcat(Node* node) {
return NoChange();
}
-// ES6 String.prototype.indexOf(searchString [, position])
-// #sec-string.prototype.indexof
-Reduction JSBuiltinReducer::ReduceStringIndexOf(Node* node) {
- // We need at least target, receiver and search_string parameters.
- if (node->op()->ValueInputCount() >= 3) {
- Node* search_string = NodeProperties::GetValueInput(node, 2);
- Type* search_string_type = NodeProperties::GetType(search_string);
- Node* position = (node->op()->ValueInputCount() >= 4)
- ? NodeProperties::GetValueInput(node, 3)
- : jsgraph()->ZeroConstant();
- Type* position_type = NodeProperties::GetType(position);
-
- if (search_string_type->Is(Type::String()) &&
- position_type->Is(Type::SignedSmall())) {
- if (Node* receiver = GetStringWitness(node)) {
- RelaxEffectsAndControls(node);
- node->ReplaceInput(0, receiver);
- node->ReplaceInput(1, search_string);
- node->ReplaceInput(2, position);
- node->TrimInputCount(3);
- NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
- return Changed(node);
- }
- }
- }
- return NoChange();
-}
-
Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
if (Node* receiver = GetStringWitness(node)) {
Node* effect = NodeProperties::GetEffectInput(node);
@@ -2584,9 +2018,7 @@ Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
Node* index = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
receiver, effect, control);
- Node* length = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForStringLength()), string,
- effect, control);
+ Node* length = graph()->NewNode(simplified()->StringLength(), string);
// branch0: if (index < length)
Node* check0 =
@@ -2677,9 +2109,8 @@ Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0);
// Update iterator.[[NextIndex]]
- Node* char_length = etrue0 = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0,
- etrue0, if_true0);
+ Node* char_length =
+ graph()->NewNode(simplified()->StringLength(), vtrue0);
index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
etrue0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
@@ -2728,9 +2159,8 @@ Reduction JSBuiltinReducer::ReduceStringSlice(Node* node) {
if (start_type->Is(type_cache_.kSingletonMinusOne) &&
end_type->Is(Type::Undefined())) {
- Node* receiver_length = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
- effect, control);
+ Node* receiver_length =
+ graph()->NewNode(simplified()->StringLength(), receiver);
Node* check =
graph()->NewNode(simplified()->NumberEqual(), receiver_length,
@@ -2855,12 +2285,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceArrayIteratorNext(node);
case kArrayIsArray:
return ReduceArrayIsArray(node);
- case kArrayPop:
- return ReduceArrayPop(node);
- case kArrayPush:
- return ReduceArrayPush(node);
- case kArrayShift:
- return ReduceArrayShift(node);
case kDateNow:
return ReduceDateNow(node);
case kDateGetTime:
@@ -3024,14 +2448,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kStringFromCharCode:
reduction = ReduceStringFromCharCode(node);
break;
- case kStringCharAt:
- return ReduceStringCharAt(node);
- case kStringCharCodeAt:
- return ReduceStringCharCodeAt(node);
case kStringConcat:
return ReduceStringConcat(node);
- case kStringIndexOf:
- return ReduceStringIndexOf(node);
case kStringIterator:
return ReduceStringIterator(node);
case kStringIteratorNext: