aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-call-reducer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-call-reducer.cc')
-rw-r--r--deps/v8/src/compiler/js-call-reducer.cc470
1 files changed, 178 insertions, 292 deletions
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc
index a06f4490a6..5b04731a64 100644
--- a/deps/v8/src/compiler/js-call-reducer.cc
+++ b/deps/v8/src/compiler/js-call-reducer.cc
@@ -25,6 +25,7 @@
#include "src/objects/arguments-inl.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
+#include "src/objects/js-objects.h"
#include "src/vector-slot-pair.h"
namespace v8 {
@@ -865,7 +866,8 @@ Reduction JSCallReducer::ReduceReflectGet(Node* node) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kGetProperty);
auto call_descriptor = Linkage::GetStubCallDescriptor(
- graph()->zone(), callable.descriptor(), 0,
+ graph()->zone(), callable.descriptor(),
+ callable.descriptor().GetStackParameterCount(),
CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
vtrue = etrue = if_true =
@@ -2160,12 +2162,8 @@ Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
Node* callback_value) {
Node* boolean_result =
graph()->NewNode(simplified()->ToBoolean(), callback_value);
-
- Node* check_boolean_result =
- graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
- jsgraph()->TrueConstant());
Node* boolean_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check_boolean_result, *control);
+ boolean_result, *control);
Node* if_true = graph()->NewNode(common()->IfTrue(), boolean_branch);
Node* etrue = *effect;
@@ -2465,11 +2463,8 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
{
Node* boolean_result =
graph()->NewNode(simplified()->ToBoolean(), callback_value);
- Node* check_boolean_result =
- graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
- jsgraph()->TrueConstant());
Node* boolean_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check_boolean_result, control);
+ boolean_result, control);
if_false_callback = graph()->NewNode(common()->IfFalse(), boolean_branch);
efalse_callback = effect;
@@ -2585,7 +2580,8 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
: GetCallableForArrayIncludes(receiver_map->elements_kind(),
isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
- graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
+ graph()->zone(), callable.descriptor(),
+ callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
Operator::kEliminatable);
// The stub expects the following arguments: the receiver array, its elements,
// the search_element, the array length, and the index to start searching
@@ -2821,11 +2817,8 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
{
Node* boolean_result =
graph()->NewNode(simplified()->ToBoolean(), callback_value);
- Node* check_boolean_result =
- graph()->NewNode(simplified()->ReferenceEqual(), boolean_result,
- jsgraph()->TrueConstant());
Node* boolean_branch = graph()->NewNode(
- common()->Branch(BranchHint::kFalse), check_boolean_result, control);
+ common()->Branch(BranchHint::kFalse), boolean_result, control);
if_true_callback = graph()->NewNode(common()->IfTrue(), boolean_branch);
etrue_callback = effect;
@@ -3026,7 +3019,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
if (access.offset == JSArray::kLengthOffset) {
// Ignore uses for arguments#length.
STATIC_ASSERT(JSArray::kLengthOffset ==
- JSArgumentsObject::kLengthOffset);
+ JSArgumentsObjectWithLength::kLengthOffset);
continue;
} else if (access.offset == JSObject::kElementsOffset) {
// Ignore safe uses for arguments#elements.
@@ -3332,7 +3325,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
}
HeapObject* heap_object;
- if (nexus.GetFeedback()->ToWeakHeapObject(&heap_object)) {
+ if (nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object)) {
Handle<HeapObject> feedback(heap_object, isolate());
// Check if we want to use CallIC feedback here.
if (!ShouldUseCallICFeedback(target)) return NoChange();
@@ -3468,53 +3461,53 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
case Builtins::kDataViewPrototypeGetUint8:
- return ReduceDataViewPrototypeGet(node,
- ExternalArrayType::kExternalUint8Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalUint8Array);
case Builtins::kDataViewPrototypeGetInt8:
- return ReduceDataViewPrototypeGet(node,
- ExternalArrayType::kExternalInt8Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalInt8Array);
case Builtins::kDataViewPrototypeGetUint16:
- return ReduceDataViewPrototypeGet(
- node, ExternalArrayType::kExternalUint16Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalUint16Array);
case Builtins::kDataViewPrototypeGetInt16:
- return ReduceDataViewPrototypeGet(node,
- ExternalArrayType::kExternalInt16Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalInt16Array);
case Builtins::kDataViewPrototypeGetUint32:
- return ReduceDataViewPrototypeGet(
- node, ExternalArrayType::kExternalUint32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalUint32Array);
case Builtins::kDataViewPrototypeGetInt32:
- return ReduceDataViewPrototypeGet(node,
- ExternalArrayType::kExternalInt32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalInt32Array);
case Builtins::kDataViewPrototypeGetFloat32:
- return ReduceDataViewPrototypeGet(
- node, ExternalArrayType::kExternalFloat32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalFloat32Array);
case Builtins::kDataViewPrototypeGetFloat64:
- return ReduceDataViewPrototypeGet(
- node, ExternalArrayType::kExternalFloat64Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kGet,
+ ExternalArrayType::kExternalFloat64Array);
case Builtins::kDataViewPrototypeSetUint8:
- return ReduceDataViewPrototypeSet(node,
- ExternalArrayType::kExternalUint8Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalUint8Array);
case Builtins::kDataViewPrototypeSetInt8:
- return ReduceDataViewPrototypeSet(node,
- ExternalArrayType::kExternalInt8Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalInt8Array);
case Builtins::kDataViewPrototypeSetUint16:
- return ReduceDataViewPrototypeSet(
- node, ExternalArrayType::kExternalUint16Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalUint16Array);
case Builtins::kDataViewPrototypeSetInt16:
- return ReduceDataViewPrototypeSet(node,
- ExternalArrayType::kExternalInt16Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalInt16Array);
case Builtins::kDataViewPrototypeSetUint32:
- return ReduceDataViewPrototypeSet(
- node, ExternalArrayType::kExternalUint32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalUint32Array);
case Builtins::kDataViewPrototypeSetInt32:
- return ReduceDataViewPrototypeSet(node,
- ExternalArrayType::kExternalInt32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalInt32Array);
case Builtins::kDataViewPrototypeSetFloat32:
- return ReduceDataViewPrototypeSet(
- node, ExternalArrayType::kExternalFloat32Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalFloat32Array);
case Builtins::kDataViewPrototypeSetFloat64:
- return ReduceDataViewPrototypeSet(
- node, ExternalArrayType::kExternalFloat64Array);
+ return ReduceDataViewAccess(node, DataViewAccess::kSet,
+ ExternalArrayType::kExternalFloat64Array);
case Builtins::kTypedArrayPrototypeByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
@@ -3758,7 +3751,7 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
}
HeapObject* feedback_object;
- if (nexus.GetFeedback()->ToStrongHeapObject(&feedback_object) &&
+ if (nexus.GetFeedback()->GetHeapObjectIfStrong(&feedback_object) &&
feedback_object->IsAllocationSite()) {
// The feedback is an AllocationSite, which means we have called the
// Array function and collected transition (and pretenuring) feedback
@@ -3787,7 +3780,7 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
NodeProperties::ReplaceValueInput(node, array_function, 1);
NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
return Changed(node);
- } else if (nexus.GetFeedback()->ToWeakHeapObject(&feedback_object) &&
+ } else if (nexus.GetFeedback()->GetHeapObjectIfWeak(&feedback_object) &&
!HeapObjectMatcher(new_target).HasValue()) {
Handle<HeapObject> object(feedback_object, isolate());
if (object->IsConstructor()) {
@@ -4835,7 +4828,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kCloneFastJSArray);
auto call_descriptor = Linkage::GetStubCallDescriptor(
- graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
+ graph()->zone(), callable.descriptor(),
+ callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
Operator::kNoThrow | Operator::kNoDeopt);
// Calls to Builtins::kCloneFastJSArray produce COW arrays
@@ -4993,18 +4987,22 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
dependencies()->DependOnProtector(PropertyCellRef(
js_heap_broker(), factory()->array_buffer_neutering_protector()));
} else {
- // Deoptimize if the array buffer was neutered.
+ // Bail out if the {iterated_object}s JSArrayBuffer was neutered.
Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
iterated_object, effect, control);
-
- Node* check = effect = graph()->NewNode(
- simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
- check = graph()->NewNode(simplified()->BooleanNot(), check);
- // TODO(bmeurer): Pass p.feedback(), or better introduce
- // CheckArrayBufferNotNeutered?
+ Node* buffer_bit_field = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
+ buffer, effect, control);
+ Node* check = graph()->NewNode(
+ simplified()->NumberEqual(),
+ graph()->NewNode(
+ simplified()->NumberBitwiseAnd(), buffer_bit_field,
+ jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->ZeroConstant());
effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
+ simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
+ p.feedback()),
check, effect, control);
}
}
@@ -5341,9 +5339,6 @@ Reduction JSCallReducer::ReduceStringFromCodePoint(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* input = NodeProperties::GetValueInput(node, 2);
- input = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
- input, effect, control);
-
input = effect =
graph()->NewNode(simplified()->CheckBounds(p.feedback()), input,
jsgraph()->Constant(0x10FFFF + 1), effect, control);
@@ -5452,9 +5447,9 @@ Reduction JSCallReducer::ReduceStringPrototypeConcat(
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
+
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- Node* context = NodeProperties::GetContextInput(node);
Node* receiver = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()),
NodeProperties::GetValueInput(node, 1), effect, control);
@@ -5463,26 +5458,22 @@ Reduction JSCallReducer::ReduceStringPrototypeConcat(
ReplaceWithValue(node, receiver, effect, control);
return Replace(receiver);
}
+
Node* argument = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()),
NodeProperties::GetValueInput(node, 2), effect, control);
+ Node* receiver_length =
+ graph()->NewNode(simplified()->StringLength(), receiver);
+ Node* argument_length =
+ graph()->NewNode(simplified()->StringLength(), argument);
+ Node* length = graph()->NewNode(simplified()->NumberAdd(), receiver_length,
+ argument_length);
+ length = effect = graph()->NewNode(
+ simplified()->CheckBounds(p.feedback()), length,
+ jsgraph()->Constant(String::kMaxLength + 1), effect, control);
- Callable const callable =
- CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
- auto call_descriptor =
- Linkage::GetStubCallDescriptor(graph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNeedsFrameState,
- Operator::kNoDeopt | Operator::kNoWrite);
-
- // TODO(turbofan): Massage the FrameState of the {node} here once we
- // have an artificial builtin frame type, so that it looks like the
- // exception from StringAdd overflow came from String.prototype.concat
- // builtin instead of the calling function.
- Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
-
- Node* value = effect = control = graph()->NewNode(
- common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()),
- receiver, argument, context, outer_frame_state, effect, control);
+ Node* value = graph()->NewNode(simplified()->StringConcat(), length, receiver,
+ argument);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
@@ -5524,7 +5515,7 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
Node* JSCallReducer::CreateArtificialFrameState(
Node* node, Node* outer_frame_state, int parameter_count,
BailoutId bailout_id, FrameStateType frame_state_type,
- Handle<SharedFunctionInfo> shared) {
+ Handle<SharedFunctionInfo> shared, Node* context) {
const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo(frame_state_type,
parameter_count + 1, 0, shared);
@@ -5534,6 +5525,7 @@ Node* JSCallReducer::CreateArtificialFrameState(
const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
Node* node0 = graph()->NewNode(op0);
std::vector<Node*> params;
+ params.reserve(parameter_count + 1);
for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
params.push_back(node->InputAt(1 + parameter));
}
@@ -5541,9 +5533,11 @@ Node* JSCallReducer::CreateArtificialFrameState(
static_cast<int>(params.size()), SparseInputMask::Dense());
Node* params_node = graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
- return graph()->NewNode(op, params_node, node0, node0,
- jsgraph()->UndefinedConstant(), node->InputAt(0),
- outer_frame_state);
+ if (!context) {
+ context = jsgraph()->UndefinedConstant();
+ }
+ return graph()->NewNode(op, params_node, node0, node0, context,
+ node->InputAt(0), outer_frame_state);
}
Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
@@ -5580,7 +5574,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
DCHECK_EQ(1, promise_shared->internal_formal_parameter_count());
Node* constructor_frame_state = CreateArtificialFrameState(
node, outer_frame_state, 1, BailoutId::ConstructStubInvoke(),
- FrameStateType::kConstructStub, promise_shared);
+ FrameStateType::kConstructStub, promise_shared, context);
// The deopt continuation of this frame state is never called; the frame state
// is only necessary to obtain the right stack trace.
@@ -6150,7 +6144,7 @@ Reduction JSCallReducer::ReduceTypedArrayConstructor(
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
node, frame_state, arity, BailoutId::ConstructStubInvoke(),
- FrameStateType::kConstructStub, shared);
+ FrameStateType::kConstructStub, shared, context);
// This continuation just returns the newly created JSTypedArray. We
// pass the_hole as the receiver, just like the builtin construct stub
@@ -6497,8 +6491,9 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kOrderedHashTableHealIndex);
auto call_descriptor = Linkage::GetStubCallDescriptor(
- graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
- Operator::kEliminatable);
+ graph()->zone(), callable.descriptor(),
+ callable.descriptor().GetStackParameterCount(),
+ CallDescriptor::kNoFlags, Operator::kEliminatable);
index = effect =
graph()->NewNode(common()->Call(call_descriptor),
jsgraph()->HeapConstant(callable.code()), table, index,
@@ -6720,6 +6715,7 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
+
if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
instance_type)) {
// Load the {receiver}s field.
@@ -6733,17 +6729,28 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
dependencies()->DependOnProtector(PropertyCellRef(
js_heap_broker(), factory()->array_buffer_neutering_protector()));
} else {
- // Check if the {receiver}s buffer was neutered.
+ // Check whether {receiver}s JSArrayBuffer was neutered.
Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
- Node* check = effect = graph()->NewNode(
- simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
-
- // Default to zero if the {receiver}s buffer was neutered.
+ Node* buffer_bit_field = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
+ buffer, effect, control);
+ Node* check = graph()->NewNode(
+ simplified()->NumberEqual(),
+ graph()->NewNode(
+ simplified()->NumberBitwiseAnd(), buffer_bit_field,
+ jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->ZeroConstant());
+
+ // TODO(turbofan): Ideally we would bail out here if the {receiver}s
+ // JSArrayBuffer was neutered, but there's no way to guard against
+ // deoptimization loops right now, since the JSCall {node} is usually
+ // created from a LOAD_IC inlining, and so there's no CALL_IC slot
+ // from which we could use the speculation bit.
value = graph()->NewNode(
- common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
- check, jsgraph()->ZeroConstant(), value);
+ common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
+ check, value, jsgraph()->ZeroConstant());
}
ReplaceWithValue(node, value, effect, control);
@@ -6767,160 +6774,33 @@ uint32_t ExternalArrayElementSize(const ExternalArrayType element_type) {
}
} // namespace
-Reduction JSCallReducer::ReduceDataViewPrototypeGet(
- Node* node, ExternalArrayType element_type) {
- uint32_t const element_size = ExternalArrayElementSize(element_type);
+Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
+ ExternalArrayType element_type) {
+ size_t const element_size = ExternalArrayElementSize(element_type);
CallParameters const& p = CallParametersOf(node->op());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* receiver = NodeProperties::GetValueInput(node, 1);
-
- if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
- return NoChange();
- }
-
Node* offset = node->op()->ValueInputCount() > 2
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->ZeroConstant();
-
- Node* is_little_endian = node->op()->ValueInputCount() > 3
- ? NodeProperties::GetValueInput(node, 3)
- : jsgraph()->FalseConstant();
-
- // Only do stuff if the {receiver} is really a DataView.
- if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
- JS_DATA_VIEW_TYPE)) {
- // Check that the {offset} is within range for the {receiver}.
- HeapObjectMatcher m(receiver);
- if (m.HasValue()) {
- // We only deal with DataViews here whose [[ByteLength]] is at least
- // {element_size} and less than 2^31-{element_size}.
- Handle<JSDataView> dataview = Handle<JSDataView>::cast(m.Value());
- if (dataview->byte_length()->Number() < element_size ||
- dataview->byte_length()->Number() - element_size > kMaxInt) {
- return NoChange();
- }
-
- // The {receiver}s [[ByteOffset]] must be within Unsigned31 range.
- if (dataview->byte_offset()->Number() > kMaxInt) {
- return NoChange();
- }
-
- // Check that the {offset} is within range of the {byte_length}.
- Node* byte_length = jsgraph()->Constant(
- dataview->byte_length()->Number() - (element_size - 1));
- offset = effect =
- graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
- byte_length, effect, control);
-
- // Add the [[ByteOffset]] to compute the effective offset.
- Node* byte_offset =
- jsgraph()->Constant(dataview->byte_offset()->Number());
- offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
- } else {
- // We only deal with DataViews here that have Smi [[ByteLength]]s.
- Node* byte_length = effect =
- graph()->NewNode(simplified()->LoadField(
- AccessBuilder::ForJSArrayBufferViewByteLength()),
- receiver, effect, control);
- byte_length = effect = graph()->NewNode(
- simplified()->CheckSmi(p.feedback()), byte_length, effect, control);
-
- // Check that the {offset} is within range of the {byte_length}.
- offset = effect =
- graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
- byte_length, effect, control);
-
- if (element_size > 0) {
- // For non-byte accesses we also need to check that the {offset}
- // plus the {element_size}-1 fits within the given {byte_length}.
- Node* end_offset =
- graph()->NewNode(simplified()->NumberAdd(), offset,
- jsgraph()->Constant(element_size - 1));
- effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
- end_offset, byte_length, effect, control);
- }
-
- // The {receiver}s [[ByteOffset]] also needs to be a (positive) Smi.
- Node* byte_offset = effect =
- graph()->NewNode(simplified()->LoadField(
- AccessBuilder::ForJSArrayBufferViewByteOffset()),
- receiver, effect, control);
- byte_offset = effect = graph()->NewNode(
- simplified()->CheckSmi(p.feedback()), byte_offset, effect, control);
-
- // Compute the buffer index at which we'll read.
- offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
- }
-
- // Coerce {is_little_endian} to boolean.
- is_little_endian =
- graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
-
- // Get the underlying buffer and check that it has not been neutered.
- Node* buffer = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
- receiver, effect, control);
-
- if (isolate()->IsArrayBufferNeuteringIntact()) {
- // Add a code dependency so we are deoptimized in case an ArrayBuffer
- // gets neutered.
- dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->array_buffer_neutering_protector()));
- } else {
- // If the buffer was neutered, deopt and let the unoptimized code throw.
- Node* check_neutered = effect = graph()->NewNode(
- simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
- check_neutered =
- graph()->NewNode(simplified()->BooleanNot(), check_neutered);
- effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
- p.feedback()),
- check_neutered, effect, control);
- }
-
- // Get the buffer's backing store.
- Node* backing_store = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSArrayBufferBackingStore()),
- buffer, effect, control);
-
- // Perform the load.
- Node* value = effect = graph()->NewNode(
- simplified()->LoadDataViewElement(element_type), buffer, backing_store,
- offset, is_little_endian, effect, control);
-
- // Continue on the regular path.
- ReplaceWithValue(node, value, effect, control);
- return Changed(value);
- }
-
- return NoChange();
-}
-
-Reduction JSCallReducer::ReduceDataViewPrototypeSet(
- Node* node, ExternalArrayType element_type) {
- uint32_t const element_size = ExternalArrayElementSize(element_type);
- CallParameters const& p = CallParametersOf(node->op());
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
- Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Node* value = (access == DataViewAccess::kGet)
+ ? nullptr
+ : (node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->ZeroConstant());
+ Node* is_little_endian = (access == DataViewAccess::kGet)
+ ? (node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->FalseConstant())
+ : (node->op()->ValueInputCount() > 4
+ ? NodeProperties::GetValueInput(node, 4)
+ : jsgraph()->FalseConstant());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
- Node* offset = node->op()->ValueInputCount() > 2
- ? NodeProperties::GetValueInput(node, 2)
- : jsgraph()->ZeroConstant();
-
- Node* value = node->op()->ValueInputCount() > 3
- ? NodeProperties::GetValueInput(node, 3)
- : jsgraph()->ZeroConstant();
-
- Node* is_little_endian = node->op()->ValueInputCount() > 4
- ? NodeProperties::GetValueInput(node, 4)
- : jsgraph()->FalseConstant();
-
// Only do stuff if the {receiver} is really a DataView.
if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
JS_DATA_VIEW_TYPE)) {
@@ -6930,26 +6810,25 @@ Reduction JSCallReducer::ReduceDataViewPrototypeSet(
// We only deal with DataViews here whose [[ByteLength]] is at least
// {element_size} and less than 2^31-{element_size}.
Handle<JSDataView> dataview = Handle<JSDataView>::cast(m.Value());
- if (dataview->byte_length()->Number() < element_size ||
- dataview->byte_length()->Number() - element_size > kMaxInt) {
+ if (dataview->byte_length() < element_size ||
+ dataview->byte_length() - element_size > kMaxInt) {
return NoChange();
}
// The {receiver}s [[ByteOffset]] must be within Unsigned31 range.
- if (dataview->byte_offset()->Number() > kMaxInt) {
+ if (dataview->byte_offset() > kMaxInt) {
return NoChange();
}
// Check that the {offset} is within range of the {byte_length}.
- Node* byte_length = jsgraph()->Constant(
- dataview->byte_length()->Number() - (element_size - 1));
+ Node* byte_length =
+ jsgraph()->Constant(dataview->byte_length() - (element_size - 1));
offset = effect =
graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
byte_length, effect, control);
// Add the [[ByteOffset]] to compute the effective offset.
- Node* byte_offset =
- jsgraph()->Constant(dataview->byte_offset()->Number());
+ Node* byte_offset = jsgraph()->Constant(dataview->byte_offset());
offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
} else {
// We only deal with DataViews here that have Smi [[ByteLength]]s.
@@ -6992,10 +6871,12 @@ Reduction JSCallReducer::ReduceDataViewPrototypeSet(
graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
// Coerce {value} to Number.
- value = effect = graph()->NewNode(
- simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
- p.feedback()),
- value, effect, control);
+ if (access == DataViewAccess::kSet) {
+ value = effect = graph()->NewNode(
+ simplified()->SpeculativeToNumber(
+ NumberOperationHint::kNumberOrOddball, p.feedback()),
+ value, effect, control);
+ }
// Get the underlying buffer and check that it has not been neutered.
Node* buffer = effect = graph()->NewNode(
@@ -7008,15 +6889,20 @@ Reduction JSCallReducer::ReduceDataViewPrototypeSet(
dependencies()->DependOnProtector(PropertyCellRef(
js_heap_broker(), factory()->array_buffer_neutering_protector()));
} else {
- // If the buffer was neutered, deopt and let the unoptimized code throw.
- Node* check_neutered = effect = graph()->NewNode(
- simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
- check_neutered =
- graph()->NewNode(simplified()->BooleanNot(), check_neutered);
+ // Bail out if the {buffer} was neutered.
+ Node* buffer_bit_field = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
+ buffer, effect, control);
+ Node* check = graph()->NewNode(
+ simplified()->NumberEqual(),
+ graph()->NewNode(
+ simplified()->NumberBitwiseAnd(), buffer_bit_field,
+ jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->ZeroConstant());
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
p.feedback()),
- check_neutered, effect, control);
+ check, effect, control);
}
// Get the buffer's backing store.
@@ -7024,12 +6910,21 @@ Reduction JSCallReducer::ReduceDataViewPrototypeSet(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferBackingStore()),
buffer, effect, control);
- // Perform the store.
- effect = graph()->NewNode(simplified()->StoreDataViewElement(element_type),
- buffer, backing_store, offset, value,
- is_little_endian, effect, control);
-
- Node* value = jsgraph()->UndefinedConstant();
+ switch (access) {
+ case DataViewAccess::kGet:
+ // Perform the load.
+ value = effect = graph()->NewNode(
+ simplified()->LoadDataViewElement(element_type), buffer,
+ backing_store, offset, is_little_endian, effect, control);
+ break;
+ case DataViewAccess::kSet:
+ // Perform the store.
+ effect = graph()->NewNode(
+ simplified()->StoreDataViewElement(element_type), buffer,
+ backing_store, offset, value, is_little_endian, effect, control);
+ value = jsgraph()->UndefinedConstant();
+ break;
+ }
// Continue on the regular path.
ReplaceWithValue(node, value, effect, control);
@@ -7242,39 +7137,30 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
+ Node* target = NodeProperties::GetValueInput(node, 0);
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Node* value = p.arity() < 3 ? jsgraph()->ZeroConstant()
+ : NodeProperties::GetValueInput(node, 2);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
- if (p.arity() <= 2) {
- ReplaceWithValue(node, jsgraph()->ZeroConstant());
- }
-
- // We don't have a new.target argument, so we can convert to number,
- // but must also convert BigInts.
- if (p.arity() == 3) {
- Node* target = NodeProperties::GetValueInput(node, 0);
- Node* context = NodeProperties::GetContextInput(node);
- Node* value = NodeProperties::GetValueInput(node, 2);
- Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
- Handle<SharedFunctionInfo> number_constructor(
- handle(native_context()->number_function()->shared(), isolate()));
-
- const std::vector<Node*> checkpoint_parameters({
- jsgraph()->UndefinedConstant(), /* receiver */
- });
- int checkpoint_parameters_size =
- static_cast<int>(checkpoint_parameters.size());
-
- Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
- jsgraph(), number_constructor,
- Builtins::kGenericConstructorLazyDeoptContinuation, target, context,
- checkpoint_parameters.data(), checkpoint_parameters_size,
- outer_frame_state, ContinuationFrameStateMode::LAZY);
-
- NodeProperties::ReplaceValueInputs(node, value);
- NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
- NodeProperties::ReplaceFrameStateInput(node, frame_state);
- return Changed(node);
- }
- return NoChange();
+ // Create the artificial frame state in the middle of the Number constructor.
+ Handle<SharedFunctionInfo> shared_info(
+ handle(native_context()->number_function()->shared(), isolate()));
+ Node* stack_parameters[] = {receiver};
+ int stack_parameter_count = arraysize(stack_parameters);
+ Node* continuation_frame_state =
+ CreateJavaScriptBuiltinContinuationFrameState(
+ jsgraph(), shared_info,
+ Builtins::kGenericConstructorLazyDeoptContinuation, target, context,
+ stack_parameters, stack_parameter_count, frame_state,
+ ContinuationFrameStateMode::LAZY);
+
+ // Convert the {value} to a Number.
+ NodeProperties::ReplaceValueInputs(node, value);
+ NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
+ NodeProperties::ReplaceFrameStateInput(node, continuation_frame_state);
+ return Changed(node);
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }