Commit dbb80b62 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Move ArrayView/TypedArray to JSCallReducer

This moves ArrayView.isArray and some TypedArray accessors to
the JSCallReducer.

Bug: v8:7340, v8:7250
Change-Id: Ia6ed9dc5eb8f0c84c286c58d757cbc149d811cf7
Reviewed-on: https://chromium-review.googlesource.com/995454Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52379}
parent 8f20e60f
......@@ -115,77 +115,6 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
native_context_(native_context),
type_cache_(TypeCache::Get()) {}
// ES #sec-get-%typedarray%.prototype-@@tostringtag
Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
NodeVector values(graph()->zone());
NodeVector effects(graph()->zone());
NodeVector controls(graph()->zone());
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
control =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
values.push_back(jsgraph()->UndefinedConstant());
effects.push_back(effect);
controls.push_back(graph()->NewNode(common()->IfTrue(), control));
control = graph()->NewNode(common()->IfFalse(), control);
Node* receiver_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
receiver, effect, control);
Node* receiver_bit_field2 = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
effect, control);
Node* receiver_elements_kind = graph()->NewNode(
simplified()->NumberShiftRightLogical(),
graph()->NewNode(simplified()->NumberBitwiseAnd(), receiver_bit_field2,
jsgraph()->Constant(Map::ElementsKindBits::kMask)),
jsgraph()->Constant(Map::ElementsKindBits::kShift));
// Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
// so that the branch cascade below is turned into a simple table
// switch by the ControlFlowOptimizer later.
receiver_elements_kind = graph()->NewNode(
simplified()->NumberSubtract(), receiver_elements_kind,
jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
do { \
Node* check = graph()->NewNode( \
simplified()->NumberEqual(), receiver_elements_kind, \
jsgraph()->Constant(TYPE##_ELEMENTS - \
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); \
control = graph()->NewNode(common()->Branch(), check, control); \
values.push_back(jsgraph()->HeapConstant( \
factory()->InternalizeUtf8String(#Type "Array"))); \
effects.push_back(effect); \
controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
control = graph()->NewNode(common()->IfFalse(), control); \
} while (false);
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
values.push_back(jsgraph()->UndefinedConstant());
effects.push_back(effect);
controls.push_back(control);
int const count = static_cast<int>(controls.size());
control = graph()->NewNode(common()->Merge(count), count, &controls.front());
effects.push_back(control);
effect =
graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
values.push_back(control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
count + 1, &values.front());
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// ES6 section 22.1.2.2 Array.isArray ( arg )
Reduction JSBuiltinReducer::ReduceArrayIsArray(Node* node) {
// We certainly know that undefined is not an array.
......@@ -445,54 +374,6 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
return Replace(value);
}
Reduction JSBuiltinReducer::ReduceArrayBufferIsView(Node* node) {
Node* value = node->op()->ValueInputCount() >= 3
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
RelaxEffectsAndControls(node);
node->ReplaceInput(0, value);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
return Changed(node);
}
Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(receiver, effect, instance_type)) {
// Load the {receiver}s field.
Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
receiver, effect, control);
// See if we can skip the neutering check.
if (isolate()->IsArrayBufferNeuteringIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
// gets neutered.
dependencies()->AssumePropertyCell(
factory()->array_buffer_neutering_protector());
} else {
// Check if the {receiver}s buffer was neutered.
Node* receiver_buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
Node* check = effect =
graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
receiver_buffer, effect, control);
// Default to zero if the {receiver}s buffer was neutered.
value = graph()->NewNode(
common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
check, jsgraph()->ZeroConstant(), value);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
Reduction JSBuiltinReducer::Reduce(Node* node) {
Reduction reduction = NoChange();
JSCallReduction r(node);
......@@ -519,29 +400,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kObjectCreate:
reduction = ReduceObjectCreate(node);
break;
case kArrayBufferIsView:
return ReduceArrayBufferIsView(node);
case kDataViewByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteLength());
case kDataViewByteOffset:
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
case kTypedArrayByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
AccessBuilder::ForJSArrayBufferViewByteLength());
case kTypedArrayByteOffset:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
case kTypedArrayLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
case kTypedArrayToStringTag:
return ReduceTypedArrayToStringTag(node);
default:
break;
}
......
......@@ -39,7 +39,6 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction Reduce(Node* node) final;
private:
Reduction ReduceTypedArrayToStringTag(Node* node);
Reduction ReduceArrayIsArray(Node* node);
Reduction ReduceDateNow(Node* node);
......@@ -48,11 +47,6 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction ReduceGlobalIsNaN(Node* node);
Reduction ReduceNumberParseInt(Node* node);
Reduction ReduceObjectCreate(Node* node);
Reduction ReduceArrayBufferIsView(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
FieldAccess const& access);
Node* ToNumber(Node* value);
Node* ToUint32(Node* value);
......
......@@ -3359,6 +3359,29 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceArrayIterator(node, IterationKind::kValues);
case Builtins::kArrayIteratorPrototypeNext:
return ReduceArrayIteratorPrototypeNext(node);
case Builtins::kArrayBufferIsView:
return ReduceArrayBufferIsView(node);
case Builtins::kDataViewPrototypeGetByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteLength());
case Builtins::kDataViewPrototypeGetByteOffset:
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
case Builtins::kTypedArrayPrototypeByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
AccessBuilder::ForJSArrayBufferViewByteLength());
case Builtins::kTypedArrayPrototypeByteOffset:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
case Builtins::kTypedArrayPrototypeLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
case Builtins::kTypedArrayPrototypeToStringTag:
return ReduceTypedArrayPrototypeToStringTag(node);
case Builtins::kMathAbs:
return ReduceMathUnary(node, simplified()->NumberAbs());
case Builtins::kMathAcos:
......@@ -5958,6 +5981,77 @@ Reduction JSCallReducer::ReduceTypedArrayConstructor(
return Replace(result);
}
// ES #sec-get-%typedarray%.prototype-@@tostringtag
Reduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
NodeVector values(graph()->zone());
NodeVector effects(graph()->zone());
NodeVector controls(graph()->zone());
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
control =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
values.push_back(jsgraph()->UndefinedConstant());
effects.push_back(effect);
controls.push_back(graph()->NewNode(common()->IfTrue(), control));
control = graph()->NewNode(common()->IfFalse(), control);
Node* receiver_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
receiver, effect, control);
Node* receiver_bit_field2 = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
effect, control);
Node* receiver_elements_kind = graph()->NewNode(
simplified()->NumberShiftRightLogical(),
graph()->NewNode(simplified()->NumberBitwiseAnd(), receiver_bit_field2,
jsgraph()->Constant(Map::ElementsKindBits::kMask)),
jsgraph()->Constant(Map::ElementsKindBits::kShift));
// Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
// so that the branch cascade below is turned into a simple table
// switch by the ControlFlowOptimizer later.
receiver_elements_kind = graph()->NewNode(
simplified()->NumberSubtract(), receiver_elements_kind,
jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
do { \
Node* check = graph()->NewNode( \
simplified()->NumberEqual(), receiver_elements_kind, \
jsgraph()->Constant(TYPE##_ELEMENTS - \
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); \
control = graph()->NewNode(common()->Branch(), check, control); \
values.push_back(jsgraph()->HeapConstant( \
factory()->InternalizeUtf8String(#Type "Array"))); \
effects.push_back(effect); \
controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
control = graph()->NewNode(common()->IfFalse(), control); \
} while (false);
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
values.push_back(jsgraph()->UndefinedConstant());
effects.push_back(effect);
controls.push_back(control);
int const count = static_cast<int>(controls.size());
control = graph()->NewNode(common()->Merge(count), count, &controls.front());
effects.push_back(control);
effect =
graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
values.push_back(control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
count + 1, &values.front());
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// ES #sec-number.isfinite
Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) {
if (node->op()->ValueInputCount() < 3) {
......@@ -6418,6 +6512,54 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
return Replace(iterator_result);
}
Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
Node* value = node->op()->ValueInputCount() >= 3
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
RelaxEffectsAndControls(node);
node->ReplaceInput(0, value);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
return Changed(node);
}
Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(receiver, effect, instance_type)) {
// Load the {receiver}s field.
Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
receiver, effect, control);
// See if we can skip the neutering check.
if (isolate()->IsArrayBufferNeuteringIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
// gets neutered.
dependencies()->AssumePropertyCell(
factory()->array_buffer_neutering_protector());
} else {
// Check if the {receiver}s buffer was neutered.
Node* receiver_buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
Node* check = effect =
graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
receiver_buffer, effect, control);
// Default to zero if the {receiver}s buffer was neutered.
value = graph()->NewNode(
common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
check, jsgraph()->ZeroConstant(), value);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
......
......@@ -23,6 +23,7 @@ namespace compiler {
// Forward declarations.
class CallFrequency;
class CommonOperatorBuilder;
struct FieldAccess;
class JSGraph;
class JSOperatorBuilder;
class SimplifiedOperatorBuilder;
......@@ -142,6 +143,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceTypedArrayConstructor(Node* node,
Handle<SharedFunctionInfo> shared);
Reduction ReduceTypedArrayPrototypeToStringTag(Node* node);
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
......@@ -168,6 +170,11 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
InstanceType collection_iterator_instance_type_first,
InstanceType collection_iterator_instance_type_last);
Reduction ReduceArrayBufferIsView(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
FieldAccess const& access);
// Returns the updated {to} node, and updates control and effect along the
// way.
Node* DoFilterPostCallbackWork(ElementsKind kind, Node** control,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment