diff options
Diffstat (limited to 'deps/v8/src/compiler/js-call-reducer.cc')
-rw-r--r-- | deps/v8/src/compiler/js-call-reducer.cc | 470 |
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()), ¶ms.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(); } |