diff options
Diffstat (limited to 'deps/v8/src/compiler/js-call-reducer.cc')
-rw-r--r-- | deps/v8/src/compiler/js-call-reducer.cc | 587 |
1 files changed, 285 insertions, 302 deletions
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc index d16e38a458..4bc55c3abe 100644 --- a/deps/v8/src/compiler/js-call-reducer.cc +++ b/deps/v8/src/compiler/js-call-reducer.cc @@ -944,9 +944,10 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) { Node* etrue = effect; Node* vtrue; { + // TODO(magardn): collect feedback so this can be optimized vtrue = etrue = if_true = - graph()->NewNode(javascript()->HasProperty(), target, key, context, - frame_state, etrue, if_true); + graph()->NewNode(javascript()->HasProperty(VectorSlotPair()), target, + key, context, frame_state, etrue, if_true); } // Rewire potential exception edges. @@ -1070,10 +1071,7 @@ Reduction JSCallReducer::ReduceArrayForEach( return NoChange(); } - // Install code dependencies on the {receiver} prototype maps and the - // global array protector cell. - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If we have unreliable maps, we need a map check. if (result == NodeProperties::kUnreliableReceiverMaps) { @@ -1089,9 +1087,9 @@ Reduction JSCallReducer::ReduceArrayForEach( simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver, effect, control); - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); // Check whether the given callback function is callable. Note that this has // to happen outside the loop to make sure we also throw on empty arrays. @@ -1111,7 +1109,7 @@ Reduction JSCallReducer::ReduceArrayForEach( Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -1257,10 +1255,7 @@ Reduction JSCallReducer::ReduceArrayReduce( } }; - // Install code dependencies on the {receiver} prototype maps and the - // global array protector cell. - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If we have unreliable maps, we need a map check. if (result == NodeProperties::kUnreliableReceiverMaps) { @@ -1287,13 +1282,12 @@ Reduction JSCallReducer::ReduceArrayReduce( Builtins::Name builtin_lazy = left ? Builtins::kArrayReduceLoopLazyDeoptContinuation : Builtins::kArrayReduceRightLoopLazyDeoptContinuation; - const std::vector<Node*> checkpoint_params( - {receiver, fncallback, k, original_length, - jsgraph()->UndefinedConstant()}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, k, original_length, + jsgraph()->UndefinedConstant()}; + const int stack_parameters = arraysize(checkpoint_params); check_frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, builtin_lazy, node->InputAt(0), context, - checkpoint_params.data(), stack_parameters - 1, outer_frame_state, + &checkpoint_params[0], stack_parameters - 1, outer_frame_state, ContinuationFrameStateMode::LAZY); } Node* check_fail = nullptr; @@ -1315,13 +1309,12 @@ Reduction JSCallReducer::ReduceArrayReduce( Builtins::Name builtin_eager = left ? Builtins::kArrayReducePreLoopEagerDeoptContinuation : Builtins::kArrayReduceRightPreLoopEagerDeoptContinuation; - const std::vector<Node*> checkpoint_params( - {receiver, fncallback, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* find_first_element_frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, builtin_eager, node->InputAt(0), context, - checkpoint_params.data(), stack_parameters, outer_frame_state, + &checkpoint_params[0], stack_parameters, outer_frame_state, ContinuationFrameStateMode::EAGER); Node* vloop = k = WireInLoopStart(k, &control, &effect); @@ -1374,7 +1367,7 @@ Reduction JSCallReducer::ReduceArrayReduce( : graph()->NewNode(simplified()->NumberLessThanOrEqual(), jsgraph()->ZeroConstant(), k); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -1385,12 +1378,12 @@ Reduction JSCallReducer::ReduceArrayReduce( Builtins::Name builtin_eager = left ? Builtins::kArrayReduceLoopEagerDeoptContinuation : Builtins::kArrayReduceRightLoopEagerDeoptContinuation; - const std::vector<Node*> checkpoint_params( - {receiver, fncallback, k, original_length, curloop}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, k, original_length, + curloop}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, builtin_eager, node->InputAt(0), context, - checkpoint_params.data(), stack_parameters, outer_frame_state, + &checkpoint_params[0], stack_parameters, outer_frame_state, ContinuationFrameStateMode::EAGER); effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); @@ -1431,12 +1424,12 @@ Reduction JSCallReducer::ReduceArrayReduce( Builtins::Name builtin_lazy = left ? Builtins::kArrayReduceLoopLazyDeoptContinuation : Builtins::kArrayReduceRightLoopLazyDeoptContinuation; - const std::vector<Node*> checkpoint_params( - {receiver, fncallback, next_k, original_length, curloop}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, next_k, original_length, + curloop}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, builtin_lazy, node->InputAt(0), context, - checkpoint_params.data(), stack_parameters - 1, outer_frame_state, + &checkpoint_params[0], stack_parameters - 1, outer_frame_state, ContinuationFrameStateMode::LAZY); next_cur = control = effect = @@ -1526,12 +1519,9 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node, } if (IsHoleyElementsKind(kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } - - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_species_protector())); + if (!dependencies()->DependOnArraySpeciesProtector()) UNREACHABLE(); Node* array_constructor = jsgraph()->Constant( native_context().GetInitialJSArrayMap(kind).GetConstructor()); @@ -1550,6 +1540,13 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node, simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver, effect, control); + // If the array length >= kMaxFastArrayLength, then CreateArray + // will create a dictionary. We should deopt in this case, and make sure + // not to attempt inlining again. + original_length = effect = graph()->NewNode( + simplified()->CheckBounds(p.feedback()), original_length, + jsgraph()->Constant(JSArray::kMaxFastArrayLength), effect, control); + // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the // exceptional projections because it cannot throw with the given parameters. Node* a = control = effect = graph()->NewNode( @@ -1557,9 +1554,9 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node, array_constructor, array_constructor, original_length, context, outer_frame_state, effect, control); - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, a, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, + a, k, original_length}; + const int stack_parameters = arraysize(checkpoint_params); // Check whether the given callback function is callable. Note that this has // to happen outside the loop to make sure we also throw on empty arrays. @@ -1579,7 +1576,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node, Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -1729,12 +1726,9 @@ Reduction JSCallReducer::ReduceArrayFilter( const ElementsKind packed_kind = GetPackedElementsKind(kind); if (IsHoleyElementsKind(kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } - - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_species_protector())); + if (!dependencies()->DependOnArraySpeciesProtector()) UNREACHABLE(); MapRef initial_map = native_context().GetInitialJSArrayMap(packed_kind); @@ -1781,9 +1775,9 @@ Reduction JSCallReducer::ReduceArrayFilter( // checkpoint_params yet, but that's okay because it'll never be called. // Therefore, "to" is mentioned twice, once standing in for the k_value // value. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, a, k, original_length, to, to}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, a, + k, original_length, to, to}; + const int stack_parameters = arraysize(checkpoint_params); Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation, @@ -1801,7 +1795,7 @@ Reduction JSCallReducer::ReduceArrayFilter( Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -1809,9 +1803,9 @@ Reduction JSCallReducer::ReduceArrayFilter( control = if_true; { - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, a, k, original_length, to}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, a, + k, original_length, to}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayFilterLoopEagerDeoptContinuation, @@ -1866,9 +1860,9 @@ Reduction JSCallReducer::ReduceArrayFilter( { // This frame state is dealt with by hand in // Builtins::kArrayFilterLoopLazyDeoptContinuation. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, a, k, original_length, element, to}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, a, + k, original_length, element, to}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation, @@ -1895,10 +1889,10 @@ Reduction JSCallReducer::ReduceArrayFilter( // point in this case. This is safe, because re-evaluating a [ToBoolean] // coercion is safe. { - std::vector<Node*> checkpoint_params({receiver, fncallback, this_arg, a, k, - original_length, element, to, - callback_value}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, + a, k, original_length, + element, to, callback_value}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayFilterLoopLazyDeoptContinuation, node->InputAt(0), context, &checkpoint_params[0], stack_parameters, @@ -1997,10 +1991,7 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant, return NoChange(); } - // Install code dependencies on the {receiver} prototype maps and the - // global array protector cell. - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If we have unreliable maps, we need a map check. if (result == NodeProperties::kUnreliableReceiverMaps) { @@ -2016,9 +2007,9 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant, simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver, effect, control); - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); // Check whether the given callback function is callable. Note that this has // to happen outside the loop to make sure we also throw on empty arrays. @@ -2044,7 +2035,7 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant, Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); Node* continue_branch = graph()->NewNode( - common()->Branch(BranchHint::kTrue), continue_test, control); + common()->Branch(BranchHint::kNone), continue_test, control); control = graph()->NewNode(common()->IfTrue(), continue_branch); if_false = graph()->NewNode(common()->IfFalse(), continue_branch); } @@ -2091,11 +2082,10 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant, // Call the callback. Node* callback_value = nullptr; { - std::vector<Node*> call_checkpoint_params({receiver, fncallback, this_arg, - next_k, original_length, - if_found_return_value}); - const int call_stack_parameters = - static_cast<int>(call_checkpoint_params.size()); + Node* call_checkpoint_params[] = {receiver, fncallback, + this_arg, next_k, + original_length, if_found_return_value}; + const int call_stack_parameters = arraysize(call_checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, after_callback_lazy_continuation_builtin, @@ -2317,12 +2307,9 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node, } if (IsHoleyElementsKind(kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } - - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_species_protector())); + if (!dependencies()->DependOnArraySpeciesProtector()) UNREACHABLE(); // If we have unreliable maps, we need a map check. if (result == NodeProperties::kUnreliableReceiverMaps) { @@ -2351,9 +2338,9 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node, // This frame state doesn't ever call the deopt continuation, it's only // necessary to specifiy a continuation in order to handle the exceptional // case. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayEveryLoopLazyDeoptContinuation, @@ -2369,7 +2356,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node, Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -2377,9 +2364,9 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node, control = if_true; { - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayEveryLoopEagerDeoptContinuation, @@ -2433,9 +2420,9 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node, { // This frame state is dealt with by hand in // Builtins::kArrayEveryLoopLazyDeoptContinuation. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArrayEveryLoopLazyDeoptContinuation, @@ -2565,23 +2552,36 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes( return NoChange(); } - Handle<Map> map; - if (!NodeProperties::GetMapWitness(broker(), node).ToHandle(&map)) + Node* receiver = NodeProperties::GetValueInput(node, 1); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + + ZoneHandleSet<Map> receiver_maps; + NodeProperties::InferReceiverMapsResult result = + NodeProperties::InferReceiverMaps(broker(), receiver, effect, + &receiver_maps); + if (result == NodeProperties::kNoReceiverMaps) return NoChange(); + + ElementsKind kind; + if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) { return NoChange(); + } - MapRef receiver_map(broker(), map); - if (!receiver_map.supports_fast_array_iteration()) return NoChange(); + if (IsHoleyElementsKind(kind)) { + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); + } - ElementsKind const elements_kind = receiver_map.elements_kind(); - if (IsHoleyElementsKind(elements_kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + // If we have unreliable maps, we need a map check. + if (result == NodeProperties::kUnreliableReceiverMaps) { + effect = + graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone, + receiver_maps, p.feedback()), + receiver, effect, control); } - Callable const callable = - search_variant == SearchVariant::kIndexOf - ? GetCallableForArrayIndexOf(elements_kind, isolate()) - : GetCallableForArrayIncludes(elements_kind, isolate()); + Callable const callable = search_variant == SearchVariant::kIndexOf + ? GetCallableForArrayIndexOf(kind, isolate()) + : GetCallableForArrayIncludes(kind, isolate()); CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( graph()->zone(), callable.descriptor(), callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags, @@ -2589,9 +2589,6 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes( // The stub expects the following arguments: the receiver array, its elements, // the search_element, the array length, and the index to start searching // from. - Node* receiver = NodeProperties::GetValueInput(node, 1); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); Node* elements = effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, effect, control); @@ -2599,8 +2596,8 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes( ? NodeProperties::GetValueInput(node, 2) : jsgraph()->UndefinedConstant(); Node* length = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)), - receiver, effect, control); + simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver, + effect, control); Node* new_from_index = jsgraph()->ZeroConstant(); if (node->op()->ValueInputCount() >= 4) { Node* from_index = NodeProperties::GetValueInput(node, 3); @@ -2664,12 +2661,9 @@ Reduction JSCallReducer::ReduceArraySome(Node* node, } if (IsHoleyElementsKind(kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } - - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_species_protector())); + if (!dependencies()->DependOnArraySpeciesProtector()) UNREACHABLE(); Node* k = jsgraph()->ZeroConstant(); @@ -2698,9 +2692,9 @@ Reduction JSCallReducer::ReduceArraySome(Node* node, // This frame state doesn't ever call the deopt continuation, it's only // necessary to specifiy a continuation in order to handle the exceptional // case. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArraySomeLoopLazyDeoptContinuation, @@ -2721,7 +2715,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node, Node* continue_test = graph()->NewNode(simplified()->NumberLessThan(), k, original_length); - Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), + Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kNone), continue_test, control); Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); @@ -2729,9 +2723,9 @@ Reduction JSCallReducer::ReduceArraySome(Node* node, control = if_true; { - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArraySomeLoopEagerDeoptContinuation, @@ -2785,9 +2779,9 @@ Reduction JSCallReducer::ReduceArraySome(Node* node, { // This frame state is dealt with by hand in // Builtins::kArrayEveryLoopLazyDeoptContinuation. - std::vector<Node*> checkpoint_params( - {receiver, fncallback, this_arg, k, original_length}); - const int stack_parameters = static_cast<int>(checkpoint_params.size()); + Node* checkpoint_params[] = {receiver, fncallback, this_arg, k, + original_length}; + const int stack_parameters = arraysize(checkpoint_params); Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( jsgraph(), shared, Builtins::kArraySomeLoopLazyDeoptContinuation, @@ -2866,68 +2860,116 @@ Reduction JSCallReducer::ReduceCallApiFunction( DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); CallParameters const& p = CallParametersOf(node->op()); int const argc = static_cast<int>(p.arity()) - 2; - Node* target = NodeProperties::GetValueInput(node, 0); - Node* receiver = - (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) - ? jsgraph()->Constant(native_context().global_proxy_object()) - : NodeProperties::GetValueInput(node, 1); + Node* global_proxy = + jsgraph()->Constant(native_context().global_proxy_object()); + Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) + ? global_proxy + : NodeProperties::GetValueInput(node, 1); + Node* holder; Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); + // See if we can optimize this API call to {shared}. Handle<FunctionTemplateInfo> function_template_info( FunctionTemplateInfo::cast(shared.object()->function_data()), isolate()); + CallOptimization call_optimization(isolate(), function_template_info); + if (!call_optimization.is_simple_api_call()) return NoChange(); - // Infer the {receiver} maps, and check if we can inline the API function - // callback based on those. + // Try to infer the {receiver} maps from the graph. ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult result = NodeProperties::InferReceiverMaps(broker(), receiver, effect, &receiver_maps); - if (result == NodeProperties::kNoReceiverMaps) return NoChange(); - for (Handle<Map> map : receiver_maps) { - MapRef receiver_map(broker(), map); - if (!receiver_map.IsJSObjectMap() || - (!function_template_info->accept_any_receiver() && - receiver_map.is_access_check_needed())) { - return NoChange(); - } - // In case of unreliable {receiver} information, the {receiver_maps} - // must all be stable in order to consume the information. - if (result == NodeProperties::kUnreliableReceiverMaps) { - if (!receiver_map.is_stable()) return NoChange(); - } - } - - // See if we can constant-fold the compatible receiver checks. - CallOptimization call_optimization(isolate(), function_template_info); - if (!call_optimization.is_simple_api_call()) return NoChange(); - CallOptimization::HolderLookup lookup; - Handle<JSObject> api_holder = - call_optimization.LookupHolderOfExpectedType(receiver_maps[0], &lookup); - if (lookup == CallOptimization::kHolderNotFound) return NoChange(); - for (size_t i = 1; i < receiver_maps.size(); ++i) { - CallOptimization::HolderLookup lookupi; - Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType( - receiver_maps[i], &lookupi); - if (lookup != lookupi) return NoChange(); - if (!api_holder.is_identical_to(holder)) return NoChange(); - } - - // Install stability dependencies for unreliable {receiver_maps}. - if (result == NodeProperties::kUnreliableReceiverMaps) { + if (result != NodeProperties::kNoReceiverMaps) { + // Check that all {receiver_maps} are actually JSReceiver maps and + // that the {function_template_info} accepts them without access + // checks (even if "access check needed" is set for {receiver}). + // + // Note that we don't need to know the concrete {receiver} maps here, + // meaning it's fine if the {receiver_maps} are unreliable, and we also + // don't need to install any stability dependencies, since the only + // relevant information regarding the {receiver} is the Map::constructor + // field on the root map (which is different from the JavaScript exposed + // "constructor" property) and that field cannot change. + // + // So if we know that {receiver} had a certain constructor at some point + // in the past (i.e. it had a certain map), then this constructor is going + // to be the same later, since this information cannot change with map + // transitions. + // + // The same is true for the instance type, e.g. we still know that the + // instance type is JSObject even if that information is unreliable, and + // the "access check needed" bit, which also cannot change later. for (Handle<Map> map : receiver_maps) { MapRef receiver_map(broker(), map); - dependencies()->DependOnStableMap(receiver_map); + if (!receiver_map.IsJSReceiverMap() || + (receiver_map.is_access_check_needed() && + !function_template_info->accept_any_receiver())) { + return NoChange(); + } } - } - // Load the {target}s context. - Node* context = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target, - effect, control); + // See if we can constant-fold the compatible receiver checks. + CallOptimization::HolderLookup lookup; + Handle<JSObject> api_holder = + call_optimization.LookupHolderOfExpectedType(receiver_maps[0], &lookup); + if (lookup == CallOptimization::kHolderNotFound) return NoChange(); + for (size_t i = 1; i < receiver_maps.size(); ++i) { + CallOptimization::HolderLookup lookupi; + Handle<JSObject> holderi = call_optimization.LookupHolderOfExpectedType( + receiver_maps[i], &lookupi); + if (lookup != lookupi) return NoChange(); + if (!api_holder.is_identical_to(holderi)) return NoChange(); + } + + // Determine the appropriate holder for the {lookup}. + holder = lookup == CallOptimization::kHolderFound + ? jsgraph()->HeapConstant(api_holder) + : receiver; + } else if (function_template_info->accept_any_receiver() && + function_template_info->signature()->IsUndefined(isolate())) { + // We haven't found any {receiver_maps}, but we might still be able to + // optimize the API call depending on the {function_template_info}. + // If the API function accepts any kind of {receiver}, we only need to + // ensure that the {receiver} is actually a JSReceiver at this point, + // and also pass that as the {holder}. There are two independent bits + // here: + // + // a. When the "accept any receiver" bit is set, it means we don't + // need to perform access checks, even if the {receiver}'s map + // has the "needs access check" bit set. + // b. When the {function_template_info} has no signature, we don't + // need to do the compatible receiver check, since all receivers + // are considered compatible at that point, and the {receiver} + // will be pass as the {holder}. + // + receiver = holder = effect = + graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()), + receiver, global_proxy, effect, control); + } else { + // We don't have enough information to eliminate the access check + // and/or the compatible receiver check, so use the generic builtin + // that does those checks dynamically. This is still significantly + // faster than the generic call sequence. + Builtins::Name builtin_name = + !function_template_info->accept_any_receiver() + ? (function_template_info->signature()->IsUndefined(isolate()) + ? Builtins::kCallFunctionTemplate_CheckAccess + : Builtins:: + kCallFunctionTemplate_CheckAccessAndCompatibleReceiver) + : Builtins::kCallFunctionTemplate_CheckCompatibleReceiver; + Callable callable = Builtins::CallableFor(isolate(), builtin_name); + auto call_descriptor = Linkage::GetStubCallDescriptor( + graph()->zone(), callable.descriptor(), + argc + 1 /* implicit receiver */, CallDescriptor::kNeedsFrameState); + node->InsertInput(graph()->zone(), 0, + jsgraph()->HeapConstant(callable.code())); + node->ReplaceInput(1, jsgraph()->HeapConstant(function_template_info)); + node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc)); + NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); + return Changed(node); + } - // CallApiCallbackStub's register arguments: code, target, call data, holder, - // function address. // TODO(turbofan): Consider introducing a JSCallApiCallback operator for // this and lower it during JSGenericLowering, and unify this with the // JSNativeContextSpecialization::InlineApiCall method a bit. @@ -2937,25 +2979,18 @@ Reduction JSCallReducer::ReduceCallApiFunction( Callable call_api_callback = CodeFactory::CallApiCallback(isolate()); CallInterfaceDescriptor cid = call_api_callback.descriptor(); auto call_descriptor = Linkage::GetStubCallDescriptor( - graph()->zone(), cid, - cid.GetStackParameterCount() + argc + 1 /* implicit receiver */, + graph()->zone(), cid, argc + 1 /* implicit receiver */, CallDescriptor::kNeedsFrameState); ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback())); - Node* holder = lookup == CallOptimization::kHolderFound - ? jsgraph()->HeapConstant(api_holder) - : receiver; ExternalReference function_reference = ExternalReference::Create( &api_function, ExternalReference::DIRECT_API_CALL); node->InsertInput(graph()->zone(), 0, jsgraph()->HeapConstant(call_api_callback.code())); - node->ReplaceInput(1, context); - node->InsertInput(graph()->zone(), 2, - jsgraph()->ExternalConstant(function_reference)); - node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(argc)); - node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(data)); - node->InsertInput(graph()->zone(), 5, holder); - node->ReplaceInput(6, receiver); - node->RemoveInput(7 + argc); // Remove context input. + node->ReplaceInput(1, jsgraph()->ExternalConstant(function_reference)); + node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc)); + node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(data)); + node->InsertInput(graph()->zone(), 4, holder); + node->ReplaceInput(5, receiver); // Update receiver input. node->ReplaceInput(8 + argc, effect); // Update effect input. NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); return Changed(node); @@ -3094,8 +3129,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread( // that no one messed with the %ArrayIteratorPrototype%.next method. if (node->opcode() == IrOpcode::kJSCallWithSpread || node->opcode() == IrOpcode::kJSConstructWithSpread) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_iterator_protector())); + if (!dependencies()->DependOnArrayIteratorProtector()) UNREACHABLE(); } // Remove the {arguments_list} input from the {node}. @@ -3332,12 +3366,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { if (!p.feedback().IsValid()) return NoChange(); FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot()); if (nexus.IsUninitialized()) { - if (flags() & kBailoutOnUninitialized) { - // Introduce a SOFT deopt if the call {node} wasn't executed so far. - return ReduceSoftDeoptimize( - node, DeoptimizeReason::kInsufficientTypeFeedbackForCall); - } - return NoChange(); + return ReduceSoftDeoptimize( + node, DeoptimizeReason::kInsufficientTypeFeedbackForCall); } base::Optional<HeapObjectRef> feedback = @@ -3752,13 +3782,8 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) { if (p.feedback().IsValid()) { FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot()); if (nexus.IsUninitialized()) { - if (flags() & kBailoutOnUninitialized) { - // Introduce a SOFT deopt if the construct {node} wasn't executed so - // far. - return ReduceSoftDeoptimize( - node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct); - } - return NoChange(); + return ReduceSoftDeoptimize( + node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct); } base::Optional<HeapObjectRef> feedback = @@ -4304,18 +4329,21 @@ Reduction JSCallReducer::ReduceReturnReceiver(Node* node) { Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason) { - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - Node* frame_state = NodeProperties::FindFrameStateBefore(node); - Node* deoptimize = graph()->NewNode( - common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()), - frame_state, effect, control); - // TODO(bmeurer): This should be on the AdvancedReducer somehow. - NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); - Revisit(graph()->end()); - node->TrimInputCount(0); - NodeProperties::ChangeOp(node, common()->Dead()); - return Changed(node); + if (flags() & kBailoutOnUninitialized) { + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + Node* frame_state = NodeProperties::FindFrameStateBefore(node); + Node* deoptimize = graph()->NewNode( + common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()), + frame_state, effect, control); + // TODO(bmeurer): This should be on the AdvancedReducer somehow. + NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); + Revisit(graph()->end()); + node->TrimInputCount(0); + NodeProperties::ChangeOp(node, common()->Dead()); + return Changed(node); + } + return NoChange(); } // ES6 section 22.1.3.18 Array.prototype.push ( ) @@ -4343,8 +4371,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { return NoChange(); } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If the {receiver_maps} information is not reliable, we need // to check that the {receiver} still has one of these maps. @@ -4448,8 +4475,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) { return NoChange(); } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If the {receiver_maps} information is not reliable, we need // to check that the {receiver} still has one of these maps. @@ -4558,8 +4584,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { return NoChange(); } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); // If the {receiver_maps} information is not reliable, we need // to check that the {receiver} still has one of these maps. @@ -4770,15 +4795,10 @@ Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) { } } - // Install code dependency on the Array[@@species] protector. - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->array_species_protector())); - - // Install code dependency on the array protector for holey arrays. if (can_be_holey) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } + if (!dependencies()->DependOnArraySpeciesProtector()) UNREACHABLE(); // If we have unreliable maps, we need a map check, as there might be // side-effects caused by the evaluation of the {node}s parameters. @@ -4931,8 +4951,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { // Install code dependency on the array protector for holey arrays. if (IsHoleyElementsKind(elements_kind)) { - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->no_elements_protector())); + if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE(); } // Load the (current) {iterated_object} from the {iterator}. @@ -4949,12 +4968,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { if (IsFixedTypedArrayElementsKind(elements_kind)) { // See if we can skip the detaching check. - if (isolate()->IsArrayBufferDetachingIntact()) { - // Add a code dependency so we are deoptimized in case an ArrayBuffer - // gets detached. - dependencies()->DependOnProtector(PropertyCellRef( - broker(), factory()->array_buffer_detaching_protector())); - } else { + if (!dependencies()->DependOnArrayBufferDetachingProtector()) { // Bail out if the {iterated_object}s JSArrayBuffer was detached. Node* buffer = effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), @@ -5013,7 +5027,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { // Check whether {index} is within the valid range for the {iterated_object}. Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, length); Node* branch = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); + graph()->NewNode(common()->Branch(BranchHint::kNone), check, control); Node* done_true; Node* value_true; @@ -5355,7 +5369,7 @@ Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) { Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index, length); Node* branch0 = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); + graph()->NewNode(common()->Branch(BranchHint::kNone), check0, control); Node* etrue0 = effect; Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); @@ -5490,13 +5504,11 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) { Node* control = NodeProperties::GetControlInput(node); if (!FLAG_experimental_inline_promise_constructor) return NoChange(); - if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); // Only handle builtins Promises, not subclasses. if (target != new_target) return NoChange(); - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_hook_protector())); + if (!dependencies()->DependOnPromiseHookProtector()) return NoChange(); SharedFunctionInfoRef promise_shared = native_context().promise_function().shared(); @@ -5648,10 +5660,7 @@ Reduction JSCallReducer::ReducePromiseInternalConstructor(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); // Check that promises aren't being observed through (debug) hooks. - if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); - - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_hook_protector())); + if (!dependencies()->DependOnPromiseHookProtector()) return NoChange(); // Create a new pending promise. Node* value = effect = @@ -5720,12 +5729,6 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); - // Check that the Promise.then protector is intact. This protector guards - // that all JSPromise instances whose [[Prototype]] is the initial - // %PromisePrototype% yield the initial %PromisePrototype%.then method - // when looking up "then". - if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange(); - // Check if we know something about {receiver} already. ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult result = @@ -5746,8 +5749,11 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) { } } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_then_protector())); + // Check that the Promise.then protector is intact. This protector guards + // that all JSPromise instances whose [[Prototype]] is the initial + // %PromisePrototype% yield the initial %PromisePrototype%.then method + // when looking up "then". + if (!dependencies()->DependOnPromiseThenProtector()) return NoChange(); // If the {receiver_maps} aren't reliable, we need to repeat the // map check here, guarded by the CALL_IC. @@ -5790,21 +5796,6 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) { return NoChange(); } - // Check that promises aren't being observed through (debug) hooks. - if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); - - // Check that the Promise#then protector is intact. This protector guards - // that all JSPromise instances whose [[Prototype]] is the initial - // %PromisePrototype% yield the initial %PromisePrototype%.then method - // when looking up "then". - if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange(); - - // Also check that the @@species protector is intact, which guards the - // lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is - // the initial %PromisePrototype%, and the Symbol.species lookup on the - // %PromisePrototype%. - if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange(); - // Check if we know something about {receiver} already. ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult result = @@ -5825,12 +5816,20 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) { } } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_hook_protector())); - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_then_protector())); - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_species_protector())); + // Check that promises aren't being observed through (debug) hooks. + if (!dependencies()->DependOnPromiseHookProtector()) return NoChange(); + + // Check that the Promise#then protector is intact. This protector guards + // that all JSPromise instances whose [[Prototype]] is the initial + // %PromisePrototype% yield the initial %PromisePrototype%.then method + // when looking up "then". + if (!dependencies()->DependOnPromiseThenProtector()) return NoChange(); + + // Also check that the @@species protector is intact, which guards the + // lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is + // the initial %PromisePrototype%, and the Symbol.species lookup on the + // %PromisePrototype%. + if (!dependencies()->DependOnPromiseSpeciesProtector()) return NoChange(); // If the {receiver_maps} aren't reliable, we need to repeat the // map check here, guarded by the CALL_IC. @@ -5951,15 +5950,6 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) { Node* control = NodeProperties::GetControlInput(node); Node* frame_state = NodeProperties::GetFrameStateInput(node); - // Check that promises aren't being observed through (debug) hooks. - if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); - - // Check if the @@species protector is intact. The @@species protector - // guards the "constructor" lookup on all JSPromise instances and the - // initial Promise.prototype, as well as the Symbol.species lookup on - // the Promise constructor. - if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange(); - // Check if we know something about {receiver} already. ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult infer_receiver_maps_result = @@ -5982,10 +5972,14 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) { } } - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_hook_protector())); - dependencies()->DependOnProtector( - PropertyCellRef(broker(), factory()->promise_species_protector())); + // Check that promises aren't being observed through (debug) hooks. + if (!dependencies()->DependOnPromiseHookProtector()) return NoChange(); + + // Check if the @@species protector is intact. The @@species protector + // guards the "constructor" lookup on all JSPromise instances and the + // initial Promise.prototype, as well as the Symbol.species lookup on + // the Promise constructor. + if (!dependencies()->DependOnPromiseSpeciesProtector()) return NoChange(); // If the {receiver_maps} aren't reliable, we need to repeat the // map check here, guarded by the CALL_IC. @@ -6676,12 +6670,7 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor( receiver, effect, control); // See if we can skip the detaching check. - if (isolate()->IsArrayBufferDetachingIntact()) { - // Add a code dependency so we are deoptimized in case an ArrayBuffer - // gets detached. - dependencies()->DependOnProtector(PropertyCellRef( - broker(), factory()->array_buffer_detaching_protector())); - } else { + if (!dependencies()->DependOnArrayBufferDetachingProtector()) { // Check whether {receiver}s JSArrayBuffer was detached. Node* buffer = effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), @@ -6825,12 +6814,7 @@ Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access, simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), receiver, effect, control); - if (isolate()->IsArrayBufferDetachingIntact()) { - // Add a code dependency so we are deoptimized in case an ArrayBuffer - // gets detached. - dependencies()->DependOnProtector(PropertyCellRef( - broker(), factory()->array_buffer_detaching_protector())); - } else { + if (!dependencies()->DependOnArrayBufferDetachingProtector()) { // Bail out if the {buffer} was detached. Node* buffer_bit_field = effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), @@ -7017,8 +7001,8 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { // Compute property access info for "exec" on {resolution}. PropertyAccessInfo ai_exec; - AccessInfoFactory access_info_factory( - broker(), dependencies(), native_context().object(), graph()->zone()); + AccessInfoFactory access_info_factory(broker(), dependencies(), + graph()->zone()); if (!access_info_factory.ComputePropertyAccessInfo( MapHandles(regexp_maps.begin(), regexp_maps.end()), factory()->exec_string(), AccessMode::kLoad, &ai_exec)) { @@ -7044,19 +7028,18 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { // Protect the prototype chain from changes. dependencies()->DependOnStablePrototypeChains( - broker(), ai_exec.receiver_maps(), JSObjectRef(broker(), holder)); + ai_exec.receiver_maps(), JSObjectRef(broker(), holder)); // Protect the exec method change in the holder. Handle<Object> exec_on_proto; - Handle<Map> holder_map(holder->map(), isolate()); - Handle<DescriptorArray> descriptors(holder_map->instance_descriptors(), - isolate()); + MapRef holder_map(broker(), handle(holder->map(), isolate())); + Handle<DescriptorArray> descriptors( + holder_map.object()->instance_descriptors(), isolate()); int descriptor_index = - descriptors->Search(*(factory()->exec_string()), *holder_map); + descriptors->Search(*(factory()->exec_string()), *holder_map.object()); CHECK_NE(descriptor_index, DescriptorArray::kNotFound); - - dependencies()->DependOnFieldType(MapRef(broker(), holder_map), - descriptor_index); + holder_map.SerializeOwnDescriptors(); + dependencies()->DependOnFieldType(holder_map, descriptor_index); } else { return NoChange(); } @@ -7067,7 +7050,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { Handle<JSObject> holder; if (ai_exec.holder().ToHandle(&holder)) { dependencies()->DependOnStablePrototypeChains( - broker(), ai_exec.receiver_maps(), JSObjectRef(broker(), holder)); + ai_exec.receiver_maps(), JSObjectRef(broker(), holder)); } if (need_map_check) { |