diff options
author | Michaël Zasso <targos@protonmail.com> | 2022-09-21 13:28:42 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2022-10-11 07:24:33 +0200 |
commit | 6bd756d7c6dfb7dc25daee329ad70df68c14223e (patch) | |
tree | af93818c545f5bd04cafd4a0c19817e19a475641 /deps/v8/src/compiler/js-native-context-specialization.cc | |
parent | 624dadb00706a9fc08f919ac72941cdaba7e3ec9 (diff) | |
download | node-new-6bd756d7c6dfb7dc25daee329ad70df68c14223e.tar.gz |
deps: update V8 to 10.7.193.13
PR-URL: https://github.com/nodejs/node/pull/44741
Fixes: https://github.com/nodejs/node/issues/44650
Fixes: https://github.com/nodejs/node/issues/37472
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'deps/v8/src/compiler/js-native-context-specialization.cc')
-rw-r--r-- | deps/v8/src/compiler/js-native-context-specialization.cc | 463 |
1 files changed, 366 insertions, 97 deletions
diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc index 3ff17052ee..39302152ed 100644 --- a/deps/v8/src/compiler/js-native-context-specialization.cc +++ b/deps/v8/src/compiler/js-native-context-specialization.cc @@ -4,30 +4,31 @@ #include "src/compiler/js-native-context-specialization.h" -#include "src/api/api-inl.h" +#include "src/base/logging.h" #include "src/base/optional.h" #include "src/builtins/accessors.h" #include "src/codegen/code-factory.h" -#include "src/codegen/string-constants.h" +#include "src/common/globals.h" #include "src/compiler/access-builder.h" #include "src/compiler/access-info.h" #include "src/compiler/allocation-builder-inl.h" #include "src/compiler/allocation-builder.h" #include "src/compiler/compilation-dependencies.h" #include "src/compiler/js-graph.h" +#include "src/compiler/js-heap-broker.h" #include "src/compiler/js-operator.h" #include "src/compiler/linkage.h" #include "src/compiler/map-inference.h" #include "src/compiler/node-matchers.h" #include "src/compiler/property-access-builder.h" +#include "src/compiler/simplified-operator.h" #include "src/compiler/type-cache.h" -#include "src/execution/isolate-inl.h" +#include "src/handles/handles.h" +#include "src/heap/factory.h" +#include "src/heap/heap-write-barrier-inl.h" #include "src/objects/feedback-vector.h" -#include "src/objects/field-index-inl.h" #include "src/objects/heap-number.h" -#include "src/objects/js-array-buffer-inl.h" -#include "src/objects/js-array-inl.h" -#include "src/objects/templates.h" +#include "src/objects/string.h" namespace v8 { namespace internal { @@ -124,16 +125,17 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) { return NoChange(); } +// If {node} is a HeapConstant<String>, return the String's length. If {node} is +// a number, return the maximum size that a stringified number can have. +// Otherwise, we can't easily convert {node} into a String, and we return +// nullopt. // static base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength( JSHeapBroker* broker, Node* node) { - if (node->opcode() == IrOpcode::kDelayedStringConstant) { - return StringConstantBaseOf(node->op())->GetMaxStringConstantLength(); - } - HeapObjectMatcher matcher(node); if (matcher.HasResolvedValue() && matcher.Ref(broker).IsString()) { StringRef input = matcher.Ref(broker).AsString(); + if (!input.IsContentAccessible()) return base::nullopt; return input.length(); } @@ -150,11 +152,10 @@ base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength( Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) { DCHECK_EQ(IrOpcode::kJSToString, node->opcode()); Node* const input = node->InputAt(0); - Reduction reduction; HeapObjectMatcher matcher(input); if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) { - reduction = Changed(input); // JSToString(x:string) => x + Reduction reduction = Changed(input); // JSToString(x:string) => x ReplaceWithValue(node, reduction.replacement()); return reduction; } @@ -165,46 +166,50 @@ Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) { // regressions and the stronger optimization should be re-implemented. NumberMatcher number_matcher(input); if (number_matcher.HasResolvedValue()) { - const StringConstantBase* base = shared_zone()->New<NumberToStringConstant>( - number_matcher.ResolvedValue()); - reduction = - Replace(graph()->NewNode(common()->DelayedStringConstant(base))); - ReplaceWithValue(node, reduction.replacement()); - return reduction; + Handle<Object> num_obj = + broker() + ->local_isolate_or_isolate() + ->factory() + ->NewNumber<AllocationType::kOld>(number_matcher.ResolvedValue()); + Handle<String> num_str = + broker()->local_isolate_or_isolate()->factory()->NumberToString( + num_obj); + Node* reduced = graph()->NewNode( + common()->HeapConstant(broker()->CanonicalPersistentHandle(num_str))); + + ReplaceWithValue(node, reduced); + return Replace(reduced); } return NoChange(); } -base::Optional<const StringConstantBase*> -JSNativeContextSpecialization::CreateDelayedStringConstant(Node* node) { - if (node->opcode() == IrOpcode::kDelayedStringConstant) { - return StringConstantBaseOf(node->op()); +// Return a String from {node}, which should be either a HeapConstant<String> +// (in which case we return the String), or a number (in which case we convert +// it to a String). +Handle<String> JSNativeContextSpecialization::CreateStringConstant(Node* node) { + DCHECK(IrOpcode::IsConstantOpcode(node->opcode())); + NumberMatcher number_matcher(node); + if (number_matcher.HasResolvedValue()) { + Handle<Object> num_obj = + broker() + ->local_isolate_or_isolate() + ->factory() + ->NewNumber<AllocationType::kOld>(number_matcher.ResolvedValue()); + return broker()->local_isolate_or_isolate()->factory()->NumberToString( + num_obj); } else { - NumberMatcher number_matcher(node); - if (number_matcher.HasResolvedValue()) { - return shared_zone()->New<NumberToStringConstant>( - number_matcher.ResolvedValue()); + HeapObjectMatcher matcher(node); + if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) { + return matcher.Ref(broker()).AsString().object(); } else { - HeapObjectMatcher matcher(node); - if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) { - StringRef s = matcher.Ref(broker()).AsString(); - if (!s.length().has_value()) return base::nullopt; - return shared_zone()->New<StringLiteral>( - s.object(), static_cast<size_t>(s.length().value())); - } else { - UNREACHABLE(); - } + UNREACHABLE(); } } } namespace { bool IsStringConstant(JSHeapBroker* broker, Node* node) { - if (node->opcode() == IrOpcode::kDelayedStringConstant) { - return true; - } - HeapObjectMatcher matcher(node); return matcher.HasResolvedValue() && matcher.Ref(broker).IsString(); } @@ -316,6 +321,94 @@ Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve( return Replace(promise); } +namespace { + +// Concatenates {left} and {right}. The result is fairly similar to creating a +// new ConsString with {left} and {right} and then flattening it, which we don't +// do because String::Flatten does not support background threads. Rather than +// implementing a full String::Flatten for background threads, we prefered to +// implement this Concatenate function, which, unlike String::Flatten, doesn't +// need to replace ConsStrings by ThinStrings. +Handle<String> Concatenate(Handle<String> left, Handle<String> right, + JSHeapBroker* broker) { + if (left->length() == 0) return right; + if (right->length() == 0) return left; + + // Repeated concatenations have a quadratic cost (eg, "s+=a;s+=b;s+=c;..."). + // Rather than doing static analysis to determine how many concatenations we + // there are and how many uses the result of each concatenation have, we + // generate ConsString when the result of the concatenation would have more + // than {kConstantStringFlattenMaxSize} characters, and flattened SeqString + // otherwise. + // TODO(dmercadier): ideally, we would like to get rid of this constant, and + // always flatten. This requires some care to avoid the quadratic worst-case. + constexpr int32_t kConstantStringFlattenMaxSize = 100; + + int32_t length = left->length() + right->length(); + if (length > kConstantStringFlattenMaxSize) { + // The generational write-barrier doesn't work in background threads, so, + // if {left} or {right} are in the young generation, we would have to copy + // them to the local heap (which is old) before creating the (old) + // ConsString. But, copying a ConsString instead of flattening it to a + // SeqString makes no sense here (since flattening would be faster and use + // less memory). Thus, if one of {left} or {right} is a young string, we'll + // build a SeqString rather than a ConsString, regardless of {length}. + // TODO(dmercadier, dinfuehr): always build a ConsString here once the + // generational write-barrier supports background threads. + if (!LocalHeap::Current() || + (!ObjectInYoungGeneration(*left) && !ObjectInYoungGeneration(*right))) { + return broker->local_isolate_or_isolate() + ->factory() + ->NewConsString(left, right, AllocationType::kOld) + .ToHandleChecked(); + } + } + + // If one of the string is not in readonly space, then we need a + // SharedStringAccessGuardIfNeeded before accessing its content. + bool require_guard = SharedStringAccessGuardIfNeeded::IsNeeded( + *left, broker->local_isolate_or_isolate()) || + SharedStringAccessGuardIfNeeded::IsNeeded( + *right, broker->local_isolate_or_isolate()); + SharedStringAccessGuardIfNeeded access_guard( + require_guard ? broker->local_isolate_or_isolate() : nullptr); + + if (left->IsOneByteRepresentation() && right->IsOneByteRepresentation()) { + // {left} and {right} are 1-byte ==> the result will be 1-byte. + Handle<SeqOneByteString> flat = + broker->local_isolate_or_isolate() + ->factory() + ->NewRawOneByteString(length, AllocationType::kOld) + .ToHandleChecked(); + DisallowGarbageCollection no_gc; + String::WriteToFlat(*left, flat->GetChars(no_gc, access_guard), 0, + left->length(), GetPtrComprCageBase(*left), + access_guard); + String::WriteToFlat( + *right, flat->GetChars(no_gc, access_guard) + left->length(), 0, + right->length(), GetPtrComprCageBase(*right), access_guard); + return flat; + } else { + // One (or both) of {left} and {right} is 2-byte ==> the result will be + // 2-byte. + Handle<SeqTwoByteString> flat = + broker->local_isolate_or_isolate() + ->factory() + ->NewRawTwoByteString(length, AllocationType::kOld) + .ToHandleChecked(); + DisallowGarbageCollection no_gc; + String::WriteToFlat(*left, flat->GetChars(no_gc, access_guard), 0, + left->length(), GetPtrComprCageBase(*left), + access_guard); + String::WriteToFlat( + *right, flat->GetChars(no_gc, access_guard) + left->length(), 0, + right->length(), GetPtrComprCageBase(*right), access_guard); + return flat; + } +} + +} // namespace + Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) { // TODO(turbofan): This has to run together with the inlining and // native context specialization to be able to leverage the string @@ -328,24 +421,19 @@ Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) { base::Optional<size_t> lhs_len = GetMaxStringLength(broker(), lhs); base::Optional<size_t> rhs_len = GetMaxStringLength(broker(), rhs); - if (!lhs_len || !rhs_len) { - return NoChange(); - } + if (!lhs_len || !rhs_len) return NoChange(); - // Fold into DelayedStringConstant if at least one of the parameters is a - // string constant and the addition won't throw due to too long result. + // Fold if at least one of the parameters is a string constant and the + // addition won't throw due to too long result. if (*lhs_len + *rhs_len <= String::kMaxLength && (IsStringConstant(broker(), lhs) || IsStringConstant(broker(), rhs))) { - base::Optional<const StringConstantBase*> left = - CreateDelayedStringConstant(lhs); - if (!left.has_value()) return NoChange(); - base::Optional<const StringConstantBase*> right = - CreateDelayedStringConstant(rhs); - if (!right.has_value()) return NoChange(); - const StringConstantBase* cons = - shared_zone()->New<StringCons>(left.value(), right.value()); - - Node* reduced = graph()->NewNode(common()->DelayedStringConstant(cons)); + Handle<String> left = CreateStringConstant(lhs); + Handle<String> right = CreateStringConstant(rhs); + + Handle<String> concatenated = Concatenate(left, right, broker()); + Node* reduced = graph()->NewNode(common()->HeapConstant( + broker()->CanonicalPersistentHandle(concatenated))); + ReplaceWithValue(node, reduced); return Replace(reduced); } @@ -436,7 +524,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { NodeProperties::ReplaceValueInput(node, constructor, 0); NodeProperties::ReplaceValueInput(node, object, 1); NodeProperties::ReplaceEffectInput(node, effect); - STATIC_ASSERT(n.FeedbackVectorIndex() == 2); + static_assert(n.FeedbackVectorIndex() == 2); node->RemoveInput(n.FeedbackVectorIndex()); NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); return Changed(node).FollowedBy(ReduceJSOrdinaryHasInstance(node)); @@ -482,7 +570,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { Node* target = jsgraph()->Constant(*constant); Node* feedback = jsgraph()->UndefinedConstant(); // Value inputs plus context, frame state, effect, control. - STATIC_ASSERT(JSCallNode::ArityForArgc(1) + 4 == 8); + static_assert(JSCallNode::ArityForArgc(1) + 4 == 8); node->EnsureInputCount(graph()->zone(), 8); node->ReplaceInput(JSCallNode::TargetIndex(), target); node->ReplaceInput(JSCallNode::ReceiverIndex(), constructor); @@ -757,7 +845,7 @@ FieldAccess ForPropertyCellValue(MachineRepresentation representation, MachineType r = MachineType::TypeForRepresentation(representation); FieldAccess access = { kTaggedBase, PropertyCell::kValueOffset, name.object(), map, type, r, - kind}; + kind, "PropertyCellValue"}; return access; } @@ -902,8 +990,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( jsgraph()->Constant(property_cell), effect, control); } } - } else { - DCHECK_EQ(AccessMode::kStore, access_mode); + } else if (access_mode == AccessMode::kStore) { DCHECK_EQ(receiver, lookup_start_object); DCHECK(!property_details.IsReadOnly()); switch (property_details.cell_type()) { @@ -971,6 +1058,8 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( case PropertyCellType::kInTransition: UNREACHABLE(); } + } else { + return NoChange(); } ReplaceWithValue(node, value, effect, control); @@ -1037,6 +1126,98 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { } } +Reduction JSNativeContextSpecialization::ReduceMegaDOMPropertyAccess( + Node* node, Node* value, MegaDOMPropertyAccessFeedback const& feedback, + FeedbackSource const& source) { + DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || + node->opcode() == IrOpcode::kJSLoadProperty); + // TODO(mslekova): Add support and tests for kJSLoadNamedFromSuper. + static_assert(JSLoadNamedNode::ObjectIndex() == 0 && + JSLoadPropertyNode::ObjectIndex() == 0, + "Assumptions about ObjectIndex have changed, please update " + "this function."); + + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + Node* frame_state = NodeProperties::GetFrameStateInput(node); + + Node* lookup_start_object = NodeProperties::GetValueInput(node, 0); + + if (!dependencies()->DependOnMegaDOMProtector()) { + return NoChange(); + } + + FunctionTemplateInfoRef function_template_info = feedback.info(); + int16_t range_start = + function_template_info.allowed_receiver_instance_type_range_start(); + int16_t range_end = + function_template_info.allowed_receiver_instance_type_range_end(); + DCHECK_IMPLIES(range_start == 0, range_end == 0); + DCHECK_LE(range_start, range_end); + + // TODO(mslekova): This could be a new InstanceTypeCheck operator + // that gets lowered later on (e.g. during generic lowering). + Node* receiver_map = effect = + graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), + lookup_start_object, effect, control); + Node* receiver_instance_type = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForMapInstanceType()), + receiver_map, effect, control); + + if (FLAG_embedder_instance_types && range_start != 0) { + // Embedder instance ID is set, doing a simple range check. + Node* diff_to_start = + graph()->NewNode(simplified()->NumberSubtract(), receiver_instance_type, + jsgraph()->Constant(range_start)); + Node* range_length = jsgraph()->Constant(range_end - range_start); + + // TODO(mslekova): Once we have the InstanceTypeCheck operator, we could + // lower it to Uint32LessThan later on to perform what is done in bounds.h. + Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), + diff_to_start, range_length); + effect = graph()->NewNode( + simplified()->CheckIf(DeoptimizeReason::kWrongInstanceType), check, + effect, control); + } else if (function_template_info.is_signature_undefined()) { + // Signature is undefined, enough to check if the receiver is a JSApiObject. + Node* check = + graph()->NewNode(simplified()->NumberEqual(), receiver_instance_type, + jsgraph()->Constant(JS_API_OBJECT_TYPE)); + effect = graph()->NewNode( + simplified()->CheckIf(DeoptimizeReason::kWrongInstanceType), check, + effect, control); + } else { + // Calling out to builtin to do signature check. + Callable callable = Builtins::CallableFor( + isolate(), Builtin::kCallFunctionTemplate_CheckCompatibleReceiver); + int stack_arg_count = callable.descriptor().GetStackParameterCount() + + 1 /* implicit receiver */; + + CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor( + graph()->zone(), callable.descriptor(), stack_arg_count, + CallDescriptor::kNeedsFrameState, Operator::kNoProperties); + + Node* inputs[8] = {jsgraph()->HeapConstant(callable.code()), + jsgraph()->Constant(function_template_info), + jsgraph()->Constant(stack_arg_count), + lookup_start_object, + jsgraph()->Constant(native_context()), + frame_state, + effect, + control}; + + value = effect = control = + graph()->NewNode(common()->Call(call_descriptor), 8, inputs); + return Replace(value); + } + + value = InlineApiCall(lookup_start_object, lookup_start_object, frame_state, + nullptr /*value*/, &effect, &control, + function_template_info); + ReplaceWithValue(node, value, effect, control); + return Replace(value); +} + Reduction JSNativeContextSpecialization::ReduceNamedAccess( Node* node, Node* value, NamedAccessFeedback const& feedback, AccessMode access_mode, Node* key) { @@ -1049,7 +1230,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( node->opcode() == IrOpcode::kJSHasProperty || node->opcode() == IrOpcode::kJSLoadNamedFromSuper || node->opcode() == IrOpcode::kJSDefineKeyedOwnProperty); - STATIC_ASSERT(JSLoadNamedNode::ObjectIndex() == 0 && + static_assert(JSLoadNamedNode::ObjectIndex() == 0 && JSSetNamedPropertyNode::ObjectIndex() == 0 && JSLoadPropertyNode::ObjectIndex() == 0 && JSSetKeyedPropertyNode::ObjectIndex() == 0 && @@ -1058,7 +1239,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( JSDefineKeyedOwnPropertyInLiteralNode::ObjectIndex() == 0 && JSHasPropertyNode::ObjectIndex() == 0 && JSDefineKeyedOwnPropertyNode::ObjectIndex() == 0); - STATIC_ASSERT(JSLoadNamedFromSuperNode::ReceiverIndex() == 0); + static_assert(JSLoadNamedFromSuperNode::ReceiverIndex() == 0); Node* context = NodeProperties::GetContextInput(node); FrameState frame_state{NodeProperties::GetFrameStateInput(node)}; @@ -1421,8 +1602,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { } else if (object.IsString() && name.equals(MakeRef(broker(), factory()->length_string()))) { // Constant-fold "length" property on constant strings. - if (!object.AsString().length().has_value()) return NoChange(); - Node* value = jsgraph()->Constant(object.AsString().length().value()); + Node* value = jsgraph()->Constant(object.AsString().length()); ReplaceWithValue(node, value); return Replace(value); } @@ -1454,6 +1634,44 @@ Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) { Effect effect = n.effect(); Control control = n.control(); + Node* iterator_exception_node = nullptr; + Node* if_exception_merge = nullptr; + Node* if_exception_effect_phi = nullptr; + Node* if_exception_phi = nullptr; + bool has_exception_node = + NodeProperties::IsExceptionalCall(node, &iterator_exception_node); + int exception_node_index = 0; + if (has_exception_node) { + DCHECK_NOT_NULL(iterator_exception_node); + // If there exists an IfException node for the iterator node, we need + // to merge all the desugared nodes exception. The iterator node will be + // desugared to LoadNamed, Call, CallRuntime, we can pre-allocate the + // nodes with 4 inputs here and we use dead_node as a placeholder for the + // input, which will be replaced. + // We use dead_node as a placeholder for the original exception node before + // it's uses are rewired. + + Node* dead_node = jsgraph()->Dead(); + if_exception_merge = graph()->NewNode(common()->Merge(4), dead_node, + dead_node, dead_node, dead_node); + if_exception_effect_phi = + graph()->NewNode(common()->EffectPhi(4), dead_node, dead_node, + dead_node, dead_node, if_exception_merge); + if_exception_phi = graph()->NewNode( + common()->Phi(MachineRepresentation::kTagged, 4), dead_node, dead_node, + dead_node, dead_node, if_exception_merge); + // Rewire the original exception node uses. + ReplaceWithValue(iterator_exception_node, if_exception_phi, + if_exception_effect_phi, if_exception_merge); + if_exception_merge->ReplaceInput(exception_node_index, + iterator_exception_node); + if_exception_effect_phi->ReplaceInput(exception_node_index, + iterator_exception_node); + if_exception_phi->ReplaceInput(exception_node_index, + iterator_exception_node); + exception_node_index++; + } + // Load iterator property operator NameRef iterator_symbol = MakeRef(broker(), factory()->iterator_symbol()); const Operator* load_op = @@ -1474,32 +1692,15 @@ Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) { effect = load_property; control = load_property; - // Handle exception path for the load named property - Node* iterator_exception_node = nullptr; - if (NodeProperties::IsExceptionalCall(node, &iterator_exception_node)) { - // If there exists an exception node for the given iterator_node, create a - // pair of IfException/IfSuccess nodes on the current control path. The uses - // of new exception node are merged with the original exception node. The - // IfSuccess node is returned as a control path for further reduction. - Node* exception_node = + // Merge the exception path for LoadNamed. + if (has_exception_node) { + Node* if_exception = graph()->NewNode(common()->IfException(), effect, control); - Node* if_success = graph()->NewNode(common()->IfSuccess(), control); - - // Use dead_node as a placeholder for the original exception node until - // its uses are rewired to the nodes merging the exceptions - Node* dead_node = jsgraph()->Dead(); - Node* merge_node = - graph()->NewNode(common()->Merge(2), dead_node, exception_node); - Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), dead_node, - exception_node, merge_node); - Node* phi = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - dead_node, exception_node, merge_node); - ReplaceWithValue(iterator_exception_node, phi, effect_phi, merge_node); - phi->ReplaceInput(0, iterator_exception_node); - effect_phi->ReplaceInput(0, iterator_exception_node); - merge_node->ReplaceInput(0, iterator_exception_node); - control = if_success; + if_exception_merge->ReplaceInput(exception_node_index, if_exception); + if_exception_phi->ReplaceInput(exception_node_index, if_exception); + if_exception_effect_phi->ReplaceInput(exception_node_index, if_exception); + exception_node_index++; + control = graph()->NewNode(common()->IfSuccess(), control); } // Eager deopt of call iterator property @@ -1521,11 +1722,73 @@ Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) { JSCallNode::ArityForArgc(0), CallFrequency(), p.callFeedback(), ConvertReceiverMode::kNotNullOrUndefined, mode, CallFeedbackRelation::kTarget); - Node* call_property = + // Lazy deopt to check the call result is JSReceiver. + Node* call_lazy_deopt_frame_state = CreateStubBuiltinContinuationFrameState( + jsgraph(), Builtin::kCallIteratorWithFeedbackLazyDeoptContinuation, + context, nullptr, 0, frame_state, ContinuationFrameStateMode::LAZY); + Node* call_property = effect = control = graph()->NewNode(call_op, load_property, receiver, n.feedback_vector(), - context, frame_state, effect, control); + context, call_lazy_deopt_frame_state, effect, control); - return Replace(call_property); + // Merge the exception path for Call. + if (has_exception_node) { + Node* if_exception = + graph()->NewNode(common()->IfException(), effect, control); + if_exception_merge->ReplaceInput(exception_node_index, if_exception); + if_exception_phi->ReplaceInput(exception_node_index, if_exception); + if_exception_effect_phi->ReplaceInput(exception_node_index, if_exception); + exception_node_index++; + control = graph()->NewNode(common()->IfSuccess(), control); + } + + // If the result is not JSReceiver, throw invalid iterator exception. + Node* is_receiver = + graph()->NewNode(simplified()->ObjectIsReceiver(), call_property); + Node* branch_node = graph()->NewNode(common()->Branch(BranchHint::kTrue), + is_receiver, control); + { + Node* if_not_receiver = graph()->NewNode(common()->IfFalse(), branch_node); + Node* effect_not_receiver = effect; + Node* control_not_receiver = if_not_receiver; + Node* call_runtime = effect_not_receiver = control_not_receiver = + graph()->NewNode( + javascript()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid, 0), + context, frame_state, effect_not_receiver, control_not_receiver); + // Merge the exception path for CallRuntime. + if (has_exception_node) { + Node* if_exception = graph()->NewNode( + common()->IfException(), effect_not_receiver, control_not_receiver); + if_exception_merge->ReplaceInput(exception_node_index, if_exception); + if_exception_phi->ReplaceInput(exception_node_index, if_exception); + if_exception_effect_phi->ReplaceInput(exception_node_index, if_exception); + exception_node_index++; + control_not_receiver = + graph()->NewNode(common()->IfSuccess(), control_not_receiver); + } + Node* throw_node = + graph()->NewNode(common()->Throw(), call_runtime, control_not_receiver); + NodeProperties::MergeControlToEnd(graph(), common(), throw_node); + } + Node* if_receiver = graph()->NewNode(common()->IfTrue(), branch_node); + ReplaceWithValue(node, call_property, effect, if_receiver); + + if (has_exception_node) { + DCHECK_EQ(exception_node_index, if_exception_merge->InputCount()); + DCHECK_EQ(exception_node_index, if_exception_effect_phi->InputCount() - 1); + DCHECK_EQ(exception_node_index, if_exception_phi->InputCount() - 1); +#ifdef DEBUG + for (Node* input : if_exception_merge->inputs()) { + DCHECK(!input->IsDead()); + } + for (Node* input : if_exception_effect_phi->inputs()) { + DCHECK(!input->IsDead()); + } + for (Node* input : if_exception_phi->inputs()) { + DCHECK(!input->IsDead()); + } +#endif + } + return Replace(if_receiver); } Reduction JSNativeContextSpecialization::ReduceJSSetNamedProperty(Node* node) { @@ -1632,7 +1895,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( node->opcode() == IrOpcode::kJSDefineKeyedOwnPropertyInLiteral || node->opcode() == IrOpcode::kJSHasProperty || node->opcode() == IrOpcode::kJSDefineKeyedOwnProperty); - STATIC_ASSERT(JSLoadPropertyNode::ObjectIndex() == 0 && + static_assert(JSLoadPropertyNode::ObjectIndex() == 0 && JSSetKeyedPropertyNode::ObjectIndex() == 0 && JSStoreInArrayLiteralNode::ArrayIndex() == 0 && JSDefineKeyedOwnPropertyInLiteralNode::ObjectIndex() == 0 && @@ -1874,7 +2137,7 @@ Reduction JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant( NumberMatcher mkey(key); if (mkey.IsInteger() && mkey.IsInRange(0.0, static_cast<double>(JSObject::kMaxElementIndex))) { - STATIC_ASSERT(JSObject::kMaxElementIndex <= kMaxUInt32); + static_assert(JSObject::kMaxElementIndex <= kMaxUInt32); const uint32_t index = static_cast<uint32_t>(mkey.ResolvedValue()); base::Optional<ObjectRef> element; @@ -1922,9 +2185,7 @@ Reduction JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant( if (receiver_ref.IsString()) { DCHECK_NE(access_mode, AccessMode::kHas); // Ensure that {key} is less than {receiver} length. - if (!receiver_ref.AsString().length().has_value()) return NoChange(); - Node* length = - jsgraph()->Constant(receiver_ref.AsString().length().value()); + Node* length = jsgraph()->Constant(receiver_ref.AsString().length()); // Load the single character string from {receiver} or yield // undefined if the {key} is out of bounds (depending on the @@ -1964,6 +2225,11 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess( case ProcessedFeedback::kNamedAccess: return ReduceNamedAccess(node, value, feedback.AsNamedAccess(), access_mode, key); + case ProcessedFeedback::kMegaDOMPropertyAccess: + DCHECK_EQ(access_mode, AccessMode::kLoad); + DCHECK_NULL(key); + return ReduceMegaDOMPropertyAccess( + node, value, feedback.AsMegaDOMPropertyAccess(), source); case ProcessedFeedback::kElementAccess: DCHECK_EQ(feedback.AsElementAccess().keyed_mode().access_mode(), access_mode); @@ -2420,6 +2686,7 @@ JSNativeContextSpecialization::BuildPropertyStore( field_type, MachineType::TypeForRepresentation(field_representation), kFullWriteBarrier, + "BuildPropertyStore", access_info.GetConstFieldInfo(), access_mode == AccessMode::kStoreInLiteral}; @@ -2453,6 +2720,7 @@ JSNativeContextSpecialization::BuildPropertyStore( Type::OtherInternal(), MachineType::TaggedPointer(), kPointerWriteBarrier, + "BuildPropertyStore", access_info.GetConstFieldInfo(), access_mode == AccessMode::kStoreInLiteral}; storage = effect = @@ -2533,6 +2801,7 @@ JSNativeContextSpecialization::BuildPropertyStore( case MachineRepresentation::kWord64: case MachineRepresentation::kFloat32: case MachineRepresentation::kSimd128: + case MachineRepresentation::kSimd256: case MachineRepresentation::kMapWord: UNREACHABLE(); } |