LCOV - code coverage report
Current view: top level - src/compiler - js-native-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 811 847 95.7 %
Date: 2017-04-26 Functions: 37 44 84.1 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/js-native-context-specialization.h"
       6             : 
       7             : #include "src/accessors.h"
       8             : #include "src/code-factory.h"
       9             : #include "src/compilation-dependencies.h"
      10             : #include "src/compiler/access-builder.h"
      11             : #include "src/compiler/access-info.h"
      12             : #include "src/compiler/js-graph.h"
      13             : #include "src/compiler/js-operator.h"
      14             : #include "src/compiler/linkage.h"
      15             : #include "src/compiler/node-matchers.h"
      16             : #include "src/compiler/type-cache.h"
      17             : #include "src/feedback-vector.h"
      18             : #include "src/field-index-inl.h"
      19             : #include "src/isolate-inl.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : namespace compiler {
      24             : 
      25             : namespace {
      26             : 
      27             : bool HasNumberMaps(MapList const& maps) {
      28       28300 :   for (auto map : maps) {
      29       10448 :     if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
      30             :   }
      31             :   return false;
      32             : }
      33             : 
      34             : bool HasOnlyJSArrayMaps(MapList const& maps) {
      35       64223 :   for (auto map : maps) {
      36       22903 :     if (!map->IsJSArrayMap()) return false;
      37             :   }
      38             :   return true;
      39             : }
      40             : 
      41             : bool HasOnlyNumberMaps(MapList const& maps) {
      42      165074 :   for (auto map : maps) {
      43       82414 :     if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
      44             :   }
      45             :   return true;
      46             : }
      47             : 
      48             : template <typename T>
      49             : bool HasOnlyStringMaps(T const& maps) {
      50      225224 :   for (auto map : maps) {
      51      111689 :     if (!map->IsStringMap()) return false;
      52             :   }
      53             :   return true;
      54             : }
      55             : 
      56             : }  // namespace
      57             : 
      58             : struct JSNativeContextSpecialization::ScriptContextTableLookupResult {
      59             :   Handle<Context> context;
      60             :   bool immutable;
      61             :   int index;
      62             : };
      63             : 
      64      395342 : JSNativeContextSpecialization::JSNativeContextSpecialization(
      65             :     Editor* editor, JSGraph* jsgraph, Flags flags,
      66             :     Handle<Context> native_context, CompilationDependencies* dependencies,
      67             :     Zone* zone)
      68             :     : AdvancedReducer(editor),
      69             :       jsgraph_(jsgraph),
      70             :       flags_(flags),
      71             :       global_object_(native_context->global_object()),
      72      395343 :       global_proxy_(JSGlobalProxy::cast(native_context->global_proxy())),
      73             :       native_context_(native_context),
      74             :       dependencies_(dependencies),
      75             :       zone_(zone),
      76     1186027 :       type_cache_(TypeCache::Get()) {}
      77             : 
      78    33010996 : Reduction JSNativeContextSpecialization::Reduce(Node* node) {
      79    33010996 :   switch (node->opcode()) {
      80             :     case IrOpcode::kJSAdd:
      81      119015 :       return ReduceJSAdd(node);
      82             :     case IrOpcode::kJSGetSuperConstructor:
      83         489 :       return ReduceJSGetSuperConstructor(node);
      84             :     case IrOpcode::kJSInstanceOf:
      85        2080 :       return ReduceJSInstanceOf(node);
      86             :     case IrOpcode::kJSOrdinaryHasInstance:
      87        1098 :       return ReduceJSOrdinaryHasInstance(node);
      88             :     case IrOpcode::kJSLoadContext:
      89      745205 :       return ReduceJSLoadContext(node);
      90             :     case IrOpcode::kJSLoadGlobal:
      91      523986 :       return ReduceJSLoadGlobal(node);
      92             :     case IrOpcode::kJSStoreGlobal:
      93       36670 :       return ReduceJSStoreGlobal(node);
      94             :     case IrOpcode::kJSLoadNamed:
      95      453799 :       return ReduceJSLoadNamed(node);
      96             :     case IrOpcode::kJSStoreNamed:
      97       64462 :       return ReduceJSStoreNamed(node);
      98             :     case IrOpcode::kJSLoadProperty:
      99       76291 :       return ReduceJSLoadProperty(node);
     100             :     case IrOpcode::kJSStoreProperty:
     101       43969 :       return ReduceJSStoreProperty(node);
     102             :     case IrOpcode::kJSStoreNamedOwn:
     103       36313 :       return ReduceJSStoreNamedOwn(node);
     104             :     case IrOpcode::kJSStoreDataPropertyInLiteral:
     105       44202 :       return ReduceJSStoreDataPropertyInLiteral(node);
     106             :     default:
     107             :       break;
     108             :   }
     109             :   return NoChange();
     110             : }
     111             : 
     112      121950 : Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
     113             :   // TODO(turbofan): This has to run together with the inlining and
     114             :   // native context specialization to be able to leverage the string
     115             :   // constant-folding for optimizing property access, but we should
     116             :   // nevertheless find a better home for this at some point.
     117             :   DCHECK_EQ(IrOpcode::kJSAdd, node->opcode());
     118             : 
     119             :   // Constant-fold string concatenation.
     120      119015 :   HeapObjectBinopMatcher m(node);
     121      274153 :   if (m.left().HasValue() && m.left().Value()->IsString() &&
     122      140022 :       m.right().HasValue() && m.right().Value()->IsString()) {
     123             :     Handle<String> left = Handle<String>::cast(m.left().Value());
     124             :     Handle<String> right = Handle<String>::cast(m.right().Value());
     125        2935 :     if (left->length() + right->length() <= String::kMaxLength) {
     126             :       Handle<String> result =
     127        5870 :           factory()->NewConsString(left, right).ToHandleChecked();
     128        2935 :       Node* value = jsgraph()->HeapConstant(result);
     129        2935 :       ReplaceWithValue(node, value);
     130             :       return Replace(value);
     131             :     }
     132             :   }
     133             :   return NoChange();
     134             : }
     135             : 
     136         489 : Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
     137         876 :     Node* node) {
     138             :   DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode());
     139         489 :   Node* constructor = NodeProperties::GetValueInput(node, 0);
     140             : 
     141             :   // Check if the input is a known JSFunction.
     142             :   HeapObjectMatcher m(constructor);
     143         489 :   if (!m.HasValue()) return NoChange();
     144             :   Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
     145             :   Handle<Map> function_map(function->map(), isolate());
     146             :   Handle<Object> function_prototype(function_map->prototype(), isolate());
     147             : 
     148             :   // We can constant-fold the super constructor access if the
     149             :   // {function}s map is stable, i.e. we can use a code dependency
     150             :   // to guard against [[Prototype]] changes of {function}.
     151         442 :   if (function_map->is_stable()) {
     152         438 :     Node* value = jsgraph()->Constant(function_prototype);
     153         438 :     dependencies()->AssumeMapStable(function_map);
     154         438 :     if (function_prototype->IsConstructor()) {
     155         406 :       ReplaceWithValue(node, value);
     156             :       return Replace(value);
     157             :     }
     158             :   }
     159             : 
     160             :   return NoChange();
     161             : }
     162             : 
     163        4398 : Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
     164             :   DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
     165        2088 :   Node* object = NodeProperties::GetValueInput(node, 0);
     166        2088 :   Node* constructor = NodeProperties::GetValueInput(node, 1);
     167        2088 :   Node* context = NodeProperties::GetContextInput(node);
     168        2088 :   Node* effect = NodeProperties::GetEffectInput(node);
     169        2088 :   Node* control = NodeProperties::GetControlInput(node);
     170             : 
     171             :   // Check if the right hand side is a known {receiver}.
     172             :   HeapObjectMatcher m(constructor);
     173        3294 :   if (!m.HasValue() || !m.Value()->IsJSObject()) return NoChange();
     174             :   Handle<JSObject> receiver = Handle<JSObject>::cast(m.Value());
     175             :   Handle<Map> receiver_map(receiver->map(), isolate());
     176             : 
     177             :   // Compute property access info for @@hasInstance on {receiver}.
     178        1200 :   PropertyAccessInfo access_info;
     179             :   AccessInfoFactory access_info_factory(dependencies(), native_context(),
     180        2400 :                                         graph()->zone());
     181        1200 :   if (!access_info_factory.ComputePropertyAccessInfo(
     182             :           receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad,
     183        1200 :           &access_info)) {
     184             :     return NoChange();
     185             :   }
     186             : 
     187        1119 :   if (access_info.IsNotFound()) {
     188             :     // If there's no @@hasInstance handler, the OrdinaryHasInstance operation
     189             :     // takes over, but that requires the {receiver} to be callable.
     190           8 :     if (receiver->IsCallable()) {
     191             :       // Determine actual holder and perform prototype chain checks.
     192             :       Handle<JSObject> holder;
     193           8 :       if (access_info.holder().ToHandle(&holder)) {
     194           0 :         AssumePrototypesStable(access_info.receiver_maps(), holder);
     195             :       }
     196             : 
     197             :       // Monomorphic property access.
     198             :       effect = BuildCheckMaps(constructor, effect, control,
     199           8 :                               access_info.receiver_maps());
     200             : 
     201             :       // Lower to OrdinaryHasInstance(C, O).
     202           8 :       NodeProperties::ReplaceValueInput(node, constructor, 0);
     203           8 :       NodeProperties::ReplaceValueInput(node, object, 1);
     204           8 :       NodeProperties::ReplaceEffectInput(node, effect);
     205           8 :       NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
     206           8 :       Reduction const reduction = ReduceJSOrdinaryHasInstance(node);
     207           8 :       return reduction.Changed() ? reduction : Changed(node);
     208             :     }
     209        1111 :   } else if (access_info.IsDataConstant() ||
     210             :              access_info.IsDataConstantField()) {
     211             :     // Determine actual holder and perform prototype chain checks.
     212             :     Handle<JSObject> holder;
     213        1110 :     if (access_info.holder().ToHandle(&holder)) {
     214        1086 :       AssumePrototypesStable(access_info.receiver_maps(), holder);
     215             :     } else {
     216          24 :       holder = receiver;
     217             :     }
     218             : 
     219             :     Handle<Object> constant;
     220        1110 :     if (access_info.IsDataConstant()) {
     221             :       DCHECK(!FLAG_track_constant_fields);
     222        1110 :       constant = access_info.constant();
     223             :     } else {
     224             :       DCHECK(FLAG_track_constant_fields);
     225             :       DCHECK(access_info.IsDataConstantField());
     226             :       // The value must be callable therefore tagged.
     227             :       DCHECK(CanBeTaggedPointer(access_info.field_representation()));
     228           0 :       FieldIndex field_index = access_info.field_index();
     229             :       constant = JSObject::FastPropertyAt(holder, Representation::Tagged(),
     230           0 :                                           field_index);
     231             :     }
     232             :     DCHECK(constant->IsCallable());
     233             : 
     234             :     // Monomorphic property access.
     235             :     effect = BuildCheckMaps(constructor, effect, control,
     236        1110 :                             access_info.receiver_maps());
     237             : 
     238             :     // Call the @@hasInstance handler.
     239        1110 :     Node* target = jsgraph()->Constant(constant);
     240        1110 :     node->InsertInput(graph()->zone(), 0, target);
     241        1110 :     node->ReplaceInput(1, constructor);
     242        1110 :     node->ReplaceInput(2, object);
     243        1110 :     node->ReplaceInput(5, effect);
     244             :     NodeProperties::ChangeOp(
     245             :         node,
     246             :         javascript()->Call(3, 0.0f, VectorSlotPair(),
     247        2220 :                            ConvertReceiverMode::kNotNullOrUndefined));
     248             : 
     249             :     // Rewire the value uses of {node} to ToBoolean conversion of the result.
     250             :     Node* value = graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
     251        2220 :                                    node, context);
     252       12724 :     for (Edge edge : node->use_edges()) {
     253        8354 :       if (NodeProperties::IsValueEdge(edge) && edge.from() != value) {
     254        1437 :         edge.UpdateTo(value);
     255        2874 :         Revisit(edge.from());
     256             :       }
     257             :     }
     258             :     return Changed(node);
     259             :   }
     260             : 
     261             :   return NoChange();
     262             : }
     263             : 
     264        1106 : Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
     265        8924 :     Node* node) {
     266             :   DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
     267        1106 :   Node* constructor = NodeProperties::GetValueInput(node, 0);
     268        1106 :   Node* object = NodeProperties::GetValueInput(node, 1);
     269        1106 :   Node* context = NodeProperties::GetContextInput(node);
     270        1106 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     271        1106 :   Node* effect = NodeProperties::GetEffectInput(node);
     272        1106 :   Node* control = NodeProperties::GetControlInput(node);
     273             : 
     274             :   // Check if the {constructor} is known at compile time.
     275             :   HeapObjectMatcher m(constructor);
     276        1106 :   if (!m.HasValue()) return NoChange();
     277             : 
     278             :   // Check if the {constructor} is a JSBoundFunction.
     279        1106 :   if (m.Value()->IsJSBoundFunction()) {
     280             :     // OrdinaryHasInstance on bound functions turns into a recursive
     281             :     // invocation of the instanceof operator again.
     282             :     // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
     283             :     Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
     284             :     Handle<JSReceiver> bound_target_function(function->bound_target_function());
     285           8 :     NodeProperties::ReplaceValueInput(node, object, 0);
     286             :     NodeProperties::ReplaceValueInput(
     287           8 :         node, jsgraph()->HeapConstant(bound_target_function), 1);
     288           8 :     NodeProperties::ChangeOp(node, javascript()->InstanceOf());
     289           8 :     Reduction const reduction = ReduceJSInstanceOf(node);
     290           8 :     return reduction.Changed() ? reduction : Changed(node);
     291             :   }
     292             : 
     293             :   // Check if the {constructor} is a JSFunction.
     294        1098 :   if (m.Value()->IsJSFunction()) {
     295             :     // Check if the {function} is a constructor and has an instance "prototype".
     296             :     Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
     297        3159 :     if (function->IsConstructor() && function->has_instance_prototype() &&
     298        1011 :         function->prototype()->IsJSReceiver()) {
     299             :       // Ensure that the {function} has a valid initial map, so we can
     300             :       // depend on that for the prototype constant-folding below.
     301        1000 :       JSFunction::EnsureHasInitialMap(function);
     302             : 
     303             :       // Install a code dependency on the {function}s initial map.
     304             :       Handle<Map> initial_map(function->initial_map(), isolate());
     305             :       dependencies()->AssumeInitialMapCantChange(initial_map);
     306             :       Handle<JSReceiver> function_prototype =
     307             :           handle(JSReceiver::cast(initial_map->prototype()), isolate());
     308             : 
     309             :       // Check if we can constant-fold the prototype chain walk
     310             :       // for the given {object} and the {function_prototype}.
     311             :       InferHasInPrototypeChainResult result =
     312        1000 :           InferHasInPrototypeChain(object, effect, function_prototype);
     313        1000 :       if (result != kMayBeInPrototypeChain) {
     314          24 :         Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
     315        1206 :         ReplaceWithValue(node, value, effect, control);
     316             :         return Replace(value);
     317             :       }
     318             : 
     319         988 :       Node* prototype = jsgraph()->Constant(function_prototype);
     320             : 
     321         988 :       Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
     322             :       Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
     323         988 :                                        check0, control);
     324             : 
     325         988 :       Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
     326             :       Node* etrue0 = effect;
     327         988 :       Node* vtrue0 = jsgraph()->FalseConstant();
     328             : 
     329         988 :       control = graph()->NewNode(common()->IfFalse(), branch0);
     330             : 
     331             :       // Loop through the {object}s prototype chain looking for the {prototype}.
     332             :       Node* loop = control =
     333         988 :           graph()->NewNode(common()->Loop(2), control, control);
     334             :       Node* eloop = effect =
     335         988 :           graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
     336             :       Node* vloop = object =
     337             :           graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     338         988 :                            object, object, loop);
     339             : 
     340             :       // Load the {object} map and instance type.
     341             :       Node* object_map = effect =
     342             :           graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
     343        2964 :                            object, effect, control);
     344             :       Node* object_instance_type = effect = graph()->NewNode(
     345             :           simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
     346        2964 :           object_map, effect, control);
     347             : 
     348             :       // Check if the {object} is a special receiver, because for special
     349             :       // receivers, i.e. proxies or API objects that need access checks,
     350             :       // we have to use the %HasInPrototypeChain runtime function instead.
     351             :       Node* check1 = graph()->NewNode(
     352             :           simplified()->NumberLessThanOrEqual(), object_instance_type,
     353        1976 :           jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
     354             :       Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
     355         988 :                                        check1, control);
     356             : 
     357         988 :       control = graph()->NewNode(common()->IfFalse(), branch1);
     358             : 
     359         988 :       Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
     360             :       Node* etrue1 = effect;
     361             :       Node* vtrue1;
     362             : 
     363             :       // Check if the {object} is not a receiver at all.
     364             :       Node* check10 =
     365             :           graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
     366        1976 :                            jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
     367             :       Node* branch10 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
     368         988 :                                         check10, if_true1);
     369             : 
     370             :       // A primitive value cannot match the {prototype} we're looking for.
     371         988 :       if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
     372         988 :       vtrue1 = jsgraph()->FalseConstant();
     373             : 
     374         988 :       Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
     375             :       Node* efalse1 = etrue1;
     376             :       Node* vfalse1;
     377             :       {
     378             :         // Slow path, need to call the %HasInPrototypeChain runtime function.
     379             :         vfalse1 = efalse1 = if_false1 = graph()->NewNode(
     380             :             javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
     381         988 :             prototype, context, frame_state, efalse1, if_false1);
     382             : 
     383             :         // Replace any potential {IfException} uses of {node} to catch
     384             :         // exceptions from this %HasInPrototypeChain runtime call instead.
     385         988 :         Node* on_exception = nullptr;
     386         988 :         if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
     387         206 :           NodeProperties::ReplaceControlInput(on_exception, vfalse1);
     388         206 :           NodeProperties::ReplaceEffectInput(on_exception, efalse1);
     389         206 :           if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
     390         206 :           Revisit(on_exception);
     391             :         }
     392             :       }
     393             : 
     394             :       // Load the {object} prototype.
     395             :       Node* object_prototype = effect = graph()->NewNode(
     396             :           simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
     397        2964 :           effect, control);
     398             : 
     399             :       // Check if we reached the end of {object}s prototype chain.
     400             :       Node* check2 =
     401             :           graph()->NewNode(simplified()->ReferenceEqual(), object_prototype,
     402        1976 :                            jsgraph()->NullConstant());
     403         988 :       Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
     404             : 
     405         988 :       Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
     406             :       Node* etrue2 = effect;
     407         988 :       Node* vtrue2 = jsgraph()->FalseConstant();
     408             : 
     409         988 :       control = graph()->NewNode(common()->IfFalse(), branch2);
     410             : 
     411             :       // Check if we reached the {prototype}.
     412             :       Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
     413         988 :                                       object_prototype, prototype);
     414         988 :       Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
     415             : 
     416         988 :       Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
     417             :       Node* etrue3 = effect;
     418         988 :       Node* vtrue3 = jsgraph()->TrueConstant();
     419             : 
     420         988 :       control = graph()->NewNode(common()->IfFalse(), branch3);
     421             : 
     422             :       // Close the loop.
     423         988 :       vloop->ReplaceInput(1, object_prototype);
     424         988 :       eloop->ReplaceInput(1, effect);
     425         988 :       loop->ReplaceInput(1, control);
     426             : 
     427             :       control = graph()->NewNode(common()->Merge(5), if_true0, if_true1,
     428         988 :                                  if_true2, if_true3, if_false1);
     429             :       effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
     430         988 :                                 etrue3, efalse1, control);
     431             : 
     432             :       // Morph the {node} into an appropriate Phi.
     433             :       ReplaceWithValue(node, node, effect, control);
     434         988 :       node->ReplaceInput(0, vtrue0);
     435         988 :       node->ReplaceInput(1, vtrue1);
     436         988 :       node->ReplaceInput(2, vtrue2);
     437         988 :       node->ReplaceInput(3, vtrue3);
     438         988 :       node->ReplaceInput(4, vfalse1);
     439         988 :       node->ReplaceInput(5, control);
     440         988 :       node->TrimInputCount(6);
     441             :       NodeProperties::ChangeOp(
     442         988 :           node, common()->Phi(MachineRepresentation::kTagged, 5));
     443             :       return Changed(node);
     444             :     }
     445             :   }
     446             : 
     447             :   return NoChange();
     448             : }
     449             : 
     450      762684 : Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
     451             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     452      745205 :   ContextAccess const& access = ContextAccessOf(node->op());
     453             :   // Specialize JSLoadContext(NATIVE_CONTEXT_INDEX) to the known native
     454             :   // context (if any), so we can constant-fold those fields, which is
     455             :   // safe, since the NATIVE_CONTEXT_INDEX slot is always immutable.
     456      745205 :   if (access.index() == Context::NATIVE_CONTEXT_INDEX) {
     457       17479 :     Node* value = jsgraph()->HeapConstant(native_context());
     458       17479 :     ReplaceWithValue(node, value);
     459             :     return Replace(value);
     460             :   }
     461             :   return NoChange();
     462             : }
     463             : 
     464             : namespace {
     465             : 
     466       68106 : FieldAccess ForPropertyCellValue(MachineRepresentation representation,
     467             :                                  Type* type, MaybeHandle<Map> map,
     468             :                                  Handle<Name> name) {
     469             :   WriteBarrierKind kind = kFullWriteBarrier;
     470       68106 :   if (representation == MachineRepresentation::kTaggedSigned) {
     471             :     kind = kNoWriteBarrier;
     472       38939 :   } else if (representation == MachineRepresentation::kTaggedPointer) {
     473             :     kind = kPointerWriteBarrier;
     474             :   }
     475       68106 :   MachineType r = MachineType::TypeForRepresentation(representation);
     476             :   FieldAccess access = {
     477      136212 :       kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
     478       68106 :   return access;
     479             : }
     480             : 
     481             : }  // namespace
     482             : 
     483      554868 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
     484             :     Node* node, Node* receiver, Node* value, Handle<Name> name,
     485      873709 :     AccessMode access_mode, Node* index) {
     486      554868 :   Node* effect = NodeProperties::GetEffectInput(node);
     487      554868 :   Node* control = NodeProperties::GetControlInput(node);
     488             : 
     489             :   // Lookup on the global object. We only deal with own data properties
     490             :   // of the global object here (represented as PropertyCell).
     491      554868 :   LookupIterator it(global_object(), name, LookupIterator::OWN);
     492      554868 :   it.TryLookupCachedProperty();
     493      554868 :   if (it.state() != LookupIterator::DATA) return NoChange();
     494      450444 :   if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
     495      450444 :   Handle<PropertyCell> property_cell = it.GetPropertyCell();
     496             :   PropertyDetails property_details = property_cell->property_details();
     497             :   Handle<Object> property_cell_value(property_cell->value(), isolate());
     498             :   PropertyCellType property_cell_type = property_details.cell_type();
     499             : 
     500             :   // We have additional constraints for stores.
     501      450444 :   if (access_mode == AccessMode::kStore) {
     502       21584 :     if (property_details.IsReadOnly()) {
     503             :       // Don't even bother trying to lower stores to read-only data properties.
     504             :       return NoChange();
     505       21513 :     } else if (property_cell_type == PropertyCellType::kUndefined) {
     506             :       // There's no fast-path for dealing with undefined property cells.
     507             :       return NoChange();
     508       21004 :     } else if (property_cell_type == PropertyCellType::kConstantType) {
     509             :       // There's also no fast-path to store to a global cell which pretended
     510             :       // to be stable, but is no longer stable now.
     511       11499 :       if (property_cell_value->IsHeapObject() &&
     512             :           !Handle<HeapObject>::cast(property_cell_value)->map()->is_stable()) {
     513             :         return NoChange();
     514             :       }
     515             :     }
     516             :   }
     517             : 
     518             :   // Ensure that {index} matches the specified {name} (if {index} is given).
     519      449864 :   if (index != nullptr) {
     520             :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
     521          39 :                                    jsgraph()->HeapConstant(name));
     522          13 :     effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
     523             :   }
     524             : 
     525             :   // Check if we have a {receiver} to validate. If so, we need to check that
     526             :   // the {receiver} is actually the JSGlobalProxy for the native context that
     527             :   // we are specializing to.
     528      449864 :   if (receiver != nullptr) {
     529             :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
     530         639 :                                    jsgraph()->HeapConstant(global_proxy()));
     531         213 :     effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
     532             :   }
     533             : 
     534      449864 :   if (access_mode == AccessMode::kLoad) {
     535             :     // Load from non-configurable, read-only data property on the global
     536             :     // object can be constant-folded, even without deoptimization support.
     537      666592 :     if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
     538       15190 :       value = jsgraph()->Constant(property_cell_value);
     539             :     } else {
     540             :       // Record a code dependency on the cell if we can benefit from the
     541             :       // additional feedback, or the global property is configurable (i.e.
     542             :       // can be deleted or reconfigured to an accessor property).
     543      413670 :       if (property_details.cell_type() != PropertyCellType::kMutable ||
     544             :           property_details.IsConfigurable()) {
     545             :         dependencies()->AssumePropertyCell(property_cell);
     546             :       }
     547             : 
     548             :       // Load from constant/undefined global property can be constant-folded.
     549      413670 :       if (property_details.cell_type() == PropertyCellType::kConstant ||
     550             :           property_details.cell_type() == PropertyCellType::kUndefined) {
     551      364149 :         value = jsgraph()->Constant(property_cell_value);
     552             :       } else {
     553             :         // Load from constant type cell can benefit from type feedback.
     554             :         MaybeHandle<Map> map;
     555             :         Type* property_cell_value_type = Type::NonInternal();
     556             :         MachineRepresentation representation = MachineRepresentation::kTagged;
     557       49521 :         if (property_details.cell_type() == PropertyCellType::kConstantType) {
     558             :           // Compute proper type based on the current value in the cell.
     559       27160 :           if (property_cell_value->IsSmi()) {
     560             :             property_cell_value_type = Type::SignedSmall();
     561             :             representation = MachineRepresentation::kTaggedSigned;
     562        8348 :           } else if (property_cell_value->IsNumber()) {
     563             :             property_cell_value_type = Type::Number();
     564             :             representation = MachineRepresentation::kTaggedPointer;
     565             :           } else {
     566             :             Handle<Map> property_cell_value_map(
     567             :                 Handle<HeapObject>::cast(property_cell_value)->map(),
     568             :                 isolate());
     569             :             property_cell_value_type = Type::For(property_cell_value_map);
     570             :             representation = MachineRepresentation::kTaggedPointer;
     571             : 
     572             :             // We can only use the property cell value map for map check
     573             :             // elimination if it's stable, i.e. the HeapObject wasn't
     574             :             // mutated without the cell state being updated.
     575        6900 :             if (property_cell_value_map->is_stable()) {
     576        6828 :               dependencies()->AssumeMapStable(property_cell_value_map);
     577             :               map = property_cell_value_map;
     578             :             }
     579             :           }
     580             :         }
     581             :         value = effect = graph()->NewNode(
     582             :             simplified()->LoadField(ForPropertyCellValue(
     583             :                 representation, property_cell_value_type, map, name)),
     584      148563 :             jsgraph()->HeapConstant(property_cell), effect, control);
     585             :       }
     586             :     }
     587             :   } else {
     588             :     DCHECK_EQ(AccessMode::kStore, access_mode);
     589             :     DCHECK(!property_details.IsReadOnly());
     590       21004 :     switch (property_details.cell_type()) {
     591             :       case PropertyCellType::kUndefined: {
     592           0 :         UNREACHABLE();
     593             :         break;
     594             :       }
     595             :       case PropertyCellType::kConstant: {
     596             :         // Record a code dependency on the cell, and just deoptimize if the new
     597             :         // value doesn't match the previous value stored inside the cell.
     598             :         dependencies()->AssumePropertyCell(property_cell);
     599             :         Node* check =
     600             :             graph()->NewNode(simplified()->ReferenceEqual(), value,
     601        4838 :                              jsgraph()->Constant(property_cell_value));
     602             :         effect =
     603        2419 :             graph()->NewNode(simplified()->CheckIf(), check, effect, control);
     604        2419 :         break;
     605             :       }
     606             :       case PropertyCellType::kConstantType: {
     607             :         // Record a code dependency on the cell, and just deoptimize if the new
     608             :         // values' type doesn't match the type of the previous value in the
     609             :         // cell.
     610             :         dependencies()->AssumePropertyCell(property_cell);
     611             :         Type* property_cell_value_type;
     612             :         MachineRepresentation representation = MachineRepresentation::kTagged;
     613       10927 :         if (property_cell_value->IsHeapObject()) {
     614             :           // We cannot do anything if the {property_cell_value}s map is no
     615             :           // longer stable.
     616             :           Handle<Map> property_cell_value_map(
     617             :               Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
     618             :           DCHECK(property_cell_value_map->is_stable());
     619         572 :           dependencies()->AssumeMapStable(property_cell_value_map);
     620             : 
     621             :           // Check that the {value} is a HeapObject.
     622             :           value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
     623         572 :                                             value, effect, control);
     624             : 
     625             :           // Check {value} map agains the {property_cell} map.
     626             :           effect =
     627             :               graph()->NewNode(simplified()->CheckMaps(
     628             :                                    CheckMapsFlag::kNone,
     629             :                                    ZoneHandleSet<Map>(property_cell_value_map)),
     630        1144 :                                value, effect, control);
     631             :           property_cell_value_type = Type::OtherInternal();
     632             :           representation = MachineRepresentation::kTaggedPointer;
     633             :         } else {
     634             :           // Check that the {value} is a Smi.
     635             :           value = effect = graph()->NewNode(simplified()->CheckSmi(), value,
     636       10355 :                                             effect, control);
     637             :           property_cell_value_type = Type::SignedSmall();
     638             :           representation = MachineRepresentation::kTaggedSigned;
     639             :         }
     640             :         effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
     641             :                                       representation, property_cell_value_type,
     642             :                                       MaybeHandle<Map>(), name)),
     643             :                                   jsgraph()->HeapConstant(property_cell), value,
     644       43708 :                                   effect, control);
     645       10927 :         break;
     646             :       }
     647             :       case PropertyCellType::kMutable: {
     648             :         // Record a code dependency on the cell, and just deoptimize if the
     649             :         // property ever becomes read-only.
     650             :         dependencies()->AssumePropertyCell(property_cell);
     651             :         effect = graph()->NewNode(
     652             :             simplified()->StoreField(ForPropertyCellValue(
     653             :                 MachineRepresentation::kTagged, Type::NonInternal(),
     654             :                 MaybeHandle<Map>(), name)),
     655       30632 :             jsgraph()->HeapConstant(property_cell), value, effect, control);
     656        7658 :         break;
     657             :       }
     658             :     }
     659             :   }
     660             : 
     661      449864 :   ReplaceWithValue(node, value, effect, control);
     662             :   return Replace(value);
     663             : }
     664             : 
     665      530455 : Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
     666             :   DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
     667      523986 :   Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
     668      523986 :   Node* effect = NodeProperties::GetEffectInput(node);
     669             : 
     670             :   // Try to lookup the name on the script context table first (lexical scoping).
     671             :   ScriptContextTableLookupResult result;
     672      523986 :   if (LookupInScriptContextTable(name, &result)) {
     673       13146 :     if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
     674        6469 :     Node* context = jsgraph()->HeapConstant(result.context);
     675             :     Node* value = effect = graph()->NewNode(
     676             :         javascript()->LoadContext(0, result.index, result.immutable), context,
     677       12938 :         effect);
     678        6469 :     ReplaceWithValue(node, value, effect);
     679             :     return Replace(value);
     680             :   }
     681             : 
     682             :   // Lookup the {name} on the global object instead.
     683      517413 :   return ReduceGlobalAccess(node, nullptr, nullptr, name, AccessMode::kLoad);
     684             : }
     685             : 
     686       36690 : Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
     687             :   DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
     688       36670 :   Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
     689       36670 :   Node* value = NodeProperties::GetValueInput(node, 0);
     690       36670 :   Node* effect = NodeProperties::GetEffectInput(node);
     691       36670 :   Node* control = NodeProperties::GetControlInput(node);
     692             : 
     693             :   // Try to lookup the name on the script context table first (lexical scoping).
     694             :   ScriptContextTableLookupResult result;
     695       36670 :   if (LookupInScriptContextTable(name, &result)) {
     696          50 :     if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
     697          24 :     if (result.immutable) return NoChange();
     698          20 :     Node* context = jsgraph()->HeapConstant(result.context);
     699             :     effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
     700          40 :                               value, context, effect, control);
     701          20 :     ReplaceWithValue(node, value, effect, control);
     702             :     return Replace(value);
     703             :   }
     704             : 
     705             :   // Lookup the {name} on the global object instead.
     706       36645 :   return ReduceGlobalAccess(node, nullptr, value, name, AccessMode::kStore);
     707             : }
     708             : 
     709       88417 : Reduction JSNativeContextSpecialization::ReduceNamedAccess(
     710       88417 :     Node* node, Node* value, MapHandleList const& receiver_maps,
     711             :     Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
     712      185881 :     Node* index) {
     713             :   DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
     714             :          node->opcode() == IrOpcode::kJSStoreNamed ||
     715             :          node->opcode() == IrOpcode::kJSLoadProperty ||
     716             :          node->opcode() == IrOpcode::kJSStoreProperty ||
     717             :          node->opcode() == IrOpcode::kJSStoreNamedOwn);
     718       88417 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
     719       88417 :   Node* context = NodeProperties::GetContextInput(node);
     720       88417 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     721       88417 :   Node* effect = NodeProperties::GetEffectInput(node);
     722       88417 :   Node* control = NodeProperties::GetControlInput(node);
     723             : 
     724             :   // Check if we have an access o.x or o.x=v where o is the current
     725             :   // native contexts' global proxy, and turn that into a direct access
     726             :   // to the current native contexts' global object instead.
     727       88417 :   if (receiver_maps.length() == 1) {
     728       84636 :     Handle<Map> receiver_map = receiver_maps.first();
     729       84636 :     if (receiver_map->IsJSGlobalProxyMap()) {
     730         233 :       Object* maybe_constructor = receiver_map->GetConstructor();
     731             :       // Detached global proxies have |null| as their constructor.
     732         466 :       if (maybe_constructor->IsJSFunction() &&
     733             :           JSFunction::cast(maybe_constructor)->native_context() ==
     734             :               *native_context()) {
     735             :         return ReduceGlobalAccess(node, receiver, value, name, access_mode,
     736         233 :                                   index);
     737             :       }
     738             :     }
     739             :   }
     740             : 
     741             :   // Compute property access infos for the receiver maps.
     742             :   AccessInfoFactory access_info_factory(dependencies(), native_context(),
     743      176368 :                                         graph()->zone());
     744             :   ZoneVector<PropertyAccessInfo> access_infos(zone());
     745       88184 :   if (!access_info_factory.ComputePropertyAccessInfos(
     746       88184 :           receiver_maps, name, access_mode, &access_infos)) {
     747             :     return NoChange();
     748             :   }
     749             : 
     750             :   // TODO(turbofan): Add support for inlining into try blocks.
     751       86835 :   bool is_exceptional = NodeProperties::IsExceptionalCall(node);
     752      262897 :   for (const auto& access_info : access_infos) {
     753       89323 :     if (access_info.IsAccessorConstant()) {
     754             :       // Accessor in try-blocks are not supported yet.
     755        2478 :       if (is_exceptional || !(flags() & kAccessorInliningEnabled)) {
     756             :         return NoChange();
     757             :       }
     758             :     }
     759             :   }
     760             : 
     761             :   // Nothing to do if we have no non-deprecated maps.
     762       86739 :   if (access_infos.empty()) {
     763             :     return ReduceSoftDeoptimize(
     764          11 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
     765             :   }
     766             : 
     767             :   // Ensure that {index} matches the specified {name} (if {index} is given).
     768       86728 :   if (index != nullptr) {
     769             :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
     770         594 :                                    jsgraph()->HeapConstant(name));
     771         594 :     effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
     772             :   }
     773             : 
     774             :   // Check for the monomorphic cases.
     775      173456 :   if (access_infos.size() == 1) {
     776       84670 :     PropertyAccessInfo access_info = access_infos.front();
     777       84670 :     if (HasOnlyStringMaps(access_info.receiver_maps())) {
     778             :       // Monormorphic string access (ignoring the fact that there are multiple
     779             :       // String maps).
     780             :       receiver = effect = graph()->NewNode(simplified()->CheckString(),
     781        6768 :                                            receiver, effect, control);
     782       82414 :     } else if (HasOnlyNumberMaps(access_info.receiver_maps())) {
     783             :       // Monomorphic number access (we also deal with Smis here).
     784             :       receiver = effect = graph()->NewNode(simplified()->CheckNumber(),
     785         738 :                                            receiver, effect, control);
     786             :     } else {
     787             :       // Monomorphic property access.
     788       82168 :       receiver = BuildCheckHeapObject(receiver, &effect, control);
     789             :       effect = BuildCheckMaps(receiver, effect, control,
     790       82168 :                               access_info.receiver_maps());
     791             :     }
     792             : 
     793             :     // Generate the actual property access.
     794             :     ValueEffectControl continuation = BuildPropertyAccess(
     795             :         receiver, value, context, frame_state, effect, control, name,
     796       84670 :         access_info, access_mode, language_mode);
     797       84670 :     value = continuation.value();
     798       84670 :     effect = continuation.effect();
     799       84670 :     control = continuation.control();
     800             :   } else {
     801             :     // The final states for every polymorphic branch. We join them with
     802             :     // Merge+Phi+EffectPhi at the bottom.
     803             :     ZoneVector<Node*> values(zone());
     804             :     ZoneVector<Node*> effects(zone());
     805             :     ZoneVector<Node*> controls(zone());
     806             : 
     807             :     // Check if {receiver} may be a number.
     808             :     bool receiverissmi_possible = false;
     809        8485 :     for (PropertyAccessInfo const& access_info : access_infos) {
     810        4449 :       if (HasNumberMaps(access_info.receiver_maps())) {
     811             :         receiverissmi_possible = true;
     812             :         break;
     813             :       }
     814             :     }
     815             : 
     816             :     // Ensure that {receiver} is a heap object.
     817        2058 :     Node* receiverissmi_control = nullptr;
     818        2058 :     Node* receiverissmi_effect = effect;
     819        2058 :     if (receiverissmi_possible) {
     820          80 :       Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
     821         160 :       Node* branch = graph()->NewNode(common()->Branch(), check, control);
     822         160 :       control = graph()->NewNode(common()->IfFalse(), branch);
     823         160 :       receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
     824          80 :       receiverissmi_effect = effect;
     825             :     } else {
     826        1978 :       receiver = BuildCheckHeapObject(receiver, &effect, control);
     827             :     }
     828             : 
     829             :     // Load the {receiver} map. The resulting effect is the dominating effect
     830             :     // for all (polymorphic) branches.
     831             :     Node* receiver_map = effect =
     832             :         graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
     833        6174 :                          receiver, effect, control);
     834             : 
     835             :     // Generate code for the various different property access patterns.
     836        2058 :     Node* fallthrough_control = control;
     837       13230 :     for (size_t j = 0; j < access_infos.size(); ++j) {
     838             :       PropertyAccessInfo const& access_info = access_infos[j];
     839             :       Node* this_value = value;
     840             :       Node* this_receiver = receiver;
     841        4557 :       Node* this_effect = effect;
     842        4557 :       Node* this_control = fallthrough_control;
     843             : 
     844             :       // Perform map check on {receiver}.
     845        4557 :       MapList const& receiver_maps = access_info.receiver_maps();
     846             :       {
     847             :         // Emit a (sequence of) map checks for other {receiver}s.
     848             :         ZoneVector<Node*> this_controls(zone());
     849             :         ZoneVector<Node*> this_effects(zone());
     850        4557 :         if (j == access_infos.size() - 1) {
     851             :           // Last map check on the fallthrough control path, do a
     852             :           // conditional eager deoptimization exit here.
     853             :           this_effect = BuildCheckMaps(receiver, this_effect, this_control,
     854        2058 :                                        receiver_maps);
     855        2058 :           this_effects.push_back(this_effect);
     856        2058 :           this_controls.push_back(fallthrough_control);
     857        2058 :           fallthrough_control = nullptr;
     858             :         } else {
     859        7698 :           for (auto map : receiver_maps) {
     860             :             Node* check =
     861             :                 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
     862        8100 :                                  jsgraph()->Constant(map));
     863             :             Node* branch = graph()->NewNode(common()->Branch(), check,
     864        5400 :                                             fallthrough_control);
     865        5400 :             fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
     866             :             this_controls.push_back(
     867        8100 :                 graph()->NewNode(common()->IfTrue(), branch));
     868        2700 :             this_effects.push_back(this_effect);
     869             :           }
     870             :         }
     871             : 
     872             :         // The Number case requires special treatment to also deal with Smis.
     873        4557 :         if (HasNumberMaps(receiver_maps)) {
     874             :           // Join this check with the "receiver is smi" check above.
     875             :           DCHECK_NOT_NULL(receiverissmi_effect);
     876             :           DCHECK_NOT_NULL(receiverissmi_control);
     877          80 :           this_effects.push_back(receiverissmi_effect);
     878          80 :           this_controls.push_back(receiverissmi_control);
     879          80 :           receiverissmi_effect = receiverissmi_control = nullptr;
     880             :         }
     881             : 
     882             :         // Create single chokepoint for the control.
     883        9114 :         int const this_control_count = static_cast<int>(this_controls.size());
     884        4557 :         if (this_control_count == 1) {
     885        4276 :           this_control = this_controls.front();
     886        4276 :           this_effect = this_effects.front();
     887             :         } else {
     888             :           this_control =
     889             :               graph()->NewNode(common()->Merge(this_control_count),
     890         562 :                                this_control_count, &this_controls.front());
     891         281 :           this_effects.push_back(this_control);
     892             :           this_effect =
     893             :               graph()->NewNode(common()->EffectPhi(this_control_count),
     894         843 :                                this_control_count + 1, &this_effects.front());
     895             :         }
     896             :       }
     897             : 
     898             :       // Generate the actual property access.
     899             :       ValueEffectControl continuation = BuildPropertyAccess(
     900             :           this_receiver, this_value, context, frame_state, this_effect,
     901        4557 :           this_control, name, access_info, access_mode, language_mode);
     902        9114 :       values.push_back(continuation.value());
     903        9114 :       effects.push_back(continuation.effect());
     904        9114 :       controls.push_back(continuation.control());
     905             :     }
     906             : 
     907             :     DCHECK_NULL(fallthrough_control);
     908             : 
     909             :     // Generate the final merge point for all (polymorphic) branches.
     910        4116 :     int const control_count = static_cast<int>(controls.size());
     911        2058 :     if (control_count == 0) {
     912           0 :       value = effect = control = jsgraph()->Dead();
     913        2058 :     } else if (control_count == 1) {
     914           0 :       value = values.front();
     915           0 :       effect = effects.front();
     916           0 :       control = controls.front();
     917             :     } else {
     918             :       control = graph()->NewNode(common()->Merge(control_count), control_count,
     919        4116 :                                  &controls.front());
     920        2058 :       values.push_back(control);
     921             :       value = graph()->NewNode(
     922             :           common()->Phi(MachineRepresentation::kTagged, control_count),
     923        6174 :           control_count + 1, &values.front());
     924        2058 :       effects.push_back(control);
     925             :       effect = graph()->NewNode(common()->EffectPhi(control_count),
     926        4116 :                                 control_count + 1, &effects.front());
     927             :     }
     928             :   }
     929       86728 :   ReplaceWithValue(node, value, effect, control);
     930             :   return Replace(value);
     931             : }
     932             : 
     933      551039 : Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
     934             :     Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
     935             :     AccessMode access_mode, LanguageMode language_mode) {
     936             :   DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
     937             :          node->opcode() == IrOpcode::kJSStoreNamed ||
     938             :          node->opcode() == IrOpcode::kJSStoreNamedOwn);
     939      551039 :   Node* const receiver = NodeProperties::GetValueInput(node, 0);
     940      551040 :   Node* const effect = NodeProperties::GetEffectInput(node);
     941             : 
     942             :   // Check if we are accessing the current native contexts' global proxy.
     943             :   HeapObjectMatcher m(receiver);
     944      673007 :   if (m.HasValue() && m.Value().is_identical_to(global_proxy())) {
     945             :     // Optimize accesses to the current native contexts' global proxy.
     946         577 :     return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
     947             :   }
     948             : 
     949             :   // Check if the {nexus} reports type feedback for the IC.
     950      550463 :   if (nexus.IsUninitialized()) {
     951      438941 :     if (flags() & kBailoutOnUninitialized) {
     952             :       return ReduceSoftDeoptimize(
     953             :           node,
     954         462 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
     955             :     }
     956             :     return NoChange();
     957             :   }
     958             : 
     959             :   // Extract receiver maps from the IC using the {nexus}.
     960             :   MapHandleList receiver_maps;
     961      111522 :   if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
     962             :     return NoChange();
     963       87824 :   } else if (receiver_maps.length() == 0) {
     964           0 :     if (flags() & kBailoutOnUninitialized) {
     965             :       return ReduceSoftDeoptimize(
     966             :           node,
     967           0 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
     968             :     }
     969             :     return NoChange();
     970             :   }
     971             : 
     972             :   // Try to lower the named access based on the {receiver_maps}.
     973             :   return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
     974       87824 :                            language_mode);
     975             : }
     976             : 
     977      914542 : Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
     978             :   DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
     979      904063 :   NamedAccess const& p = NamedAccessOf(node->op());
     980      453799 :   Node* const receiver = NodeProperties::GetValueInput(node, 0);
     981      453799 :   Node* const value = jsgraph()->Dead();
     982             : 
     983             :   // Check if we have a constant receiver.
     984             :   HeapObjectMatcher m(receiver);
     985      453799 :   if (m.HasValue()) {
     986      139397 :     if (m.Value()->IsJSFunction() &&
     987             :         p.name().is_identical_to(factory()->prototype_string())) {
     988             :       // Optimize "prototype" property of functions.
     989             :       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
     990        3414 :       if (function->IsConstructor()) {
     991             :         // We need to add a code dependency on the initial map of the
     992             :         // {function} in order to be notified about changes to the
     993             :         // "prototype" of {function}.
     994        3409 :         JSFunction::EnsureHasInitialMap(function);
     995             :         Handle<Map> initial_map(function->initial_map(), isolate());
     996             :         dependencies()->AssumeInitialMapCantChange(initial_map);
     997        3409 :         Handle<Object> prototype(function->prototype(), isolate());
     998        3409 :         Node* value = jsgraph()->Constant(prototype);
     999        3535 :         ReplaceWithValue(node, value);
    1000             :         return Replace(value);
    1001             :       }
    1002      122778 :     } else if (m.Value()->IsString() &&
    1003             :                p.name().is_identical_to(factory()->length_string())) {
    1004             :       // Constant-fold "length" property on constant strings.
    1005             :       Handle<String> string = Handle<String>::cast(m.Value());
    1006         126 :       Node* value = jsgraph()->Constant(string->length());
    1007             :       ReplaceWithValue(node, value);
    1008             :       return Replace(value);
    1009             :     }
    1010             :   }
    1011             : 
    1012             :   // Extract receiver maps from the LOAD_IC using the LoadICNexus.
    1013      450264 :   if (!p.feedback().IsValid()) return NoChange();
    1014             :   LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1015             : 
    1016             :   // Try to lower the named access based on the {receiver_maps}.
    1017             :   return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
    1018      450264 :                                     AccessMode::kLoad, p.language_mode());
    1019             : }
    1020             : 
    1021             : 
    1022       64462 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
    1023             :   DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
    1024      128924 :   NamedAccess const& p = NamedAccessOf(node->op());
    1025       64462 :   Node* const value = NodeProperties::GetValueInput(node, 1);
    1026             : 
    1027             :   // Extract receiver maps from the STORE_IC using the StoreICNexus.
    1028       64462 :   if (!p.feedback().IsValid()) return NoChange();
    1029             :   StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1030             : 
    1031             :   // Try to lower the named access based on the {receiver_maps}.
    1032             :   return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
    1033       64462 :                                     AccessMode::kStore, p.language_mode());
    1034             : }
    1035             : 
    1036       36313 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
    1037             :   DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
    1038       36313 :   StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
    1039       36313 :   Node* const value = NodeProperties::GetValueInput(node, 1);
    1040             : 
    1041             :   // Extract receiver maps from the IC using the StoreOwnICNexus.
    1042       36313 :   if (!p.feedback().IsValid()) return NoChange();
    1043             :   StoreOwnICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1044             : 
    1045             :   // Try to lower the creation of a named property based on the {receiver_maps}.
    1046             :   return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
    1047       36313 :                                     AccessMode::kStoreInLiteral, STRICT);
    1048             : }
    1049             : 
    1050       26477 : Reduction JSNativeContextSpecialization::ReduceElementAccess(
    1051             :     Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
    1052             :     AccessMode access_mode, LanguageMode language_mode,
    1053       71045 :     KeyedAccessStoreMode store_mode) {
    1054             :   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
    1055             :          node->opcode() == IrOpcode::kJSStoreProperty);
    1056       26477 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1057       26477 :   Node* effect = NodeProperties::GetEffectInput(node);
    1058       26477 :   Node* control = NodeProperties::GetControlInput(node);
    1059       26477 :   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    1060             : 
    1061             :   // Check for keyed access to strings.
    1062       26477 :   if (HasOnlyStringMaps(receiver_maps)) {
    1063             :     // Strings are immutable in JavaScript.
    1064          62 :     if (access_mode == AccessMode::kStore) return NoChange();
    1065             : 
    1066             :     // Ensure that the {receiver} is actually a String.
    1067             :     receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver,
    1068         186 :                                          effect, control);
    1069             : 
    1070             :     // Determine the {receiver} length.
    1071             :     Node* length = effect = graph()->NewNode(
    1072             :         simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
    1073         186 :         effect, control);
    1074             : 
    1075             :     // Ensure that {index} is less than {receiver} length.
    1076             :     index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    1077         186 :                                       length, effect, control);
    1078             : 
    1079             :     // Return the character from the {receiver} as single character string.
    1080             :     value = graph()->NewNode(simplified()->StringCharAt(), receiver, index,
    1081         124 :                              control);
    1082             :   } else {
    1083             :     // Retrieve the native context from the given {node}.
    1084             :     // Compute element access infos for the receiver maps.
    1085             :     AccessInfoFactory access_info_factory(dependencies(), native_context(),
    1086       52830 :                                           graph()->zone());
    1087             :     ZoneVector<ElementAccessInfo> access_infos(zone());
    1088       26415 :     if (!access_info_factory.ComputeElementAccessInfos(
    1089       26415 :             receiver_maps, access_mode, &access_infos)) {
    1090             :       return NoChange();
    1091             :     }
    1092             : 
    1093             :     // Nothing to do if we have no non-deprecated maps.
    1094       25720 :     if (access_infos.empty()) {
    1095             :       return ReduceSoftDeoptimize(
    1096             :           node,
    1097           0 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    1098             :     }
    1099             : 
    1100             :     // For holey stores or growing stores, we need to check that the prototype
    1101             :     // chain contains no setters for elements, and we need to guard those checks
    1102             :     // via code dependencies on the relevant prototype maps.
    1103       25720 :     if (access_mode == AccessMode::kStore) {
    1104             :       // TODO(turbofan): We could have a fast path here, that checks for the
    1105             :       // common case of Array or Object prototype only and therefore avoids
    1106             :       // the zone allocation of this vector.
    1107             :       ZoneVector<Handle<Map>> prototype_maps(zone());
    1108       31436 :       for (ElementAccessInfo const& access_info : access_infos) {
    1109       33188 :         for (Handle<Map> receiver_map : access_info.receiver_maps()) {
    1110             :           // If the {receiver_map} has a prototype and it's elements backing
    1111             :           // store is either holey, or we have a potentially growing store,
    1112             :           // then we need to check that all prototypes have stable maps with
    1113             :           // fast elements (and we need to guard against changes to that below).
    1114       19600 :           if (IsHoleyElementsKind(receiver_map->elements_kind()) ||
    1115             :               IsGrowStoreMode(store_mode)) {
    1116             :             // Make sure all prototypes are stable and have fast elements.
    1117        2957 :             for (Handle<Map> map = receiver_map;;) {
    1118             :               Handle<Object> map_prototype(map->prototype(), isolate());
    1119        7602 :               if (map_prototype->IsNull(isolate())) break;
    1120        4679 :               if (!map_prototype->IsJSObject()) return NoChange();
    1121             :               map = handle(Handle<JSObject>::cast(map_prototype)->map(),
    1122        4679 :                            isolate());
    1123        4679 :               if (!map->is_stable()) return NoChange();
    1124        4646 :               if (!IsFastElementsKind(map->elements_kind())) return NoChange();
    1125        4645 :               prototype_maps.push_back(map);
    1126        4645 :             }
    1127             :           }
    1128             :         }
    1129             :       }
    1130             : 
    1131             :       // Install dependencies on the relevant prototype maps.
    1132       24985 :       for (Handle<Map> prototype_map : prototype_maps) {
    1133        4637 :         dependencies()->AssumeMapStable(prototype_map);
    1134             :       }
    1135             :     }
    1136             : 
    1137             :     // Ensure that {receiver} is a heap object.
    1138       25686 :     receiver = BuildCheckHeapObject(receiver, &effect, control);
    1139             : 
    1140             :     // Check for the monomorphic case.
    1141       51372 :     if (access_infos.size() == 1) {
    1142       24634 :       ElementAccessInfo access_info = access_infos.front();
    1143             : 
    1144             :       // Perform possible elements kind transitions.
    1145       49680 :       for (auto transition : access_info.transitions()) {
    1146             :         Handle<Map> const transition_source = transition.first;
    1147             :         Handle<Map> const transition_target = transition.second;
    1148             :         effect = graph()->NewNode(
    1149             :             simplified()->TransitionElementsKind(ElementsTransition(
    1150             :                 IsSimpleMapChangeTransition(transition_source->elements_kind(),
    1151             :                                             transition_target->elements_kind())
    1152             :                     ? ElementsTransition::kFastTransition
    1153             :                     : ElementsTransition::kSlowTransition,
    1154             :                 transition_source, transition_target)),
    1155        1648 :             receiver, effect, control);
    1156             :       }
    1157             : 
    1158             :       // TODO(turbofan): The effect/control linearization will not find a
    1159             :       // FrameState after the StoreField or Call that is generated for the
    1160             :       // elements kind transition above. This is because those operators
    1161             :       // don't have the kNoWrite flag on it, even though they are not
    1162             :       // observable by JavaScript.
    1163             :       effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect,
    1164       73902 :                                 control);
    1165             : 
    1166             :       // Perform map check on the {receiver}.
    1167             :       effect = BuildCheckMaps(receiver, effect, control,
    1168       24634 :                               access_info.receiver_maps());
    1169             : 
    1170             :       // Access the actual element.
    1171             :       ValueEffectControl continuation =
    1172             :           BuildElementAccess(receiver, index, value, effect, control,
    1173       24634 :                              access_info, access_mode, store_mode);
    1174       24634 :       value = continuation.value();
    1175       24634 :       effect = continuation.effect();
    1176       24634 :       control = continuation.control();
    1177             :     } else {
    1178             :       // The final states for every polymorphic branch. We join them with
    1179             :       // Merge+Phi+EffectPhi at the bottom.
    1180             :       ZoneVector<Node*> values(zone());
    1181             :       ZoneVector<Node*> effects(zone());
    1182             :       ZoneVector<Node*> controls(zone());
    1183             : 
    1184             :       // Generate code for the various different element access patterns.
    1185        1052 :       Node* fallthrough_control = control;
    1186        6526 :       for (size_t j = 0; j < access_infos.size(); ++j) {
    1187             :         ElementAccessInfo const& access_info = access_infos[j];
    1188             :         Node* this_receiver = receiver;
    1189             :         Node* this_value = value;
    1190             :         Node* this_index = index;
    1191        2211 :         Node* this_effect = effect;
    1192        2211 :         Node* this_control = fallthrough_control;
    1193             : 
    1194             :         // Perform possible elements kind transitions.
    1195        4443 :         for (auto transition : access_info.transitions()) {
    1196             :           Handle<Map> const transition_source = transition.first;
    1197             :           Handle<Map> const transition_target = transition.second;
    1198             :           this_effect = graph()->NewNode(
    1199             :               simplified()->TransitionElementsKind(
    1200             :                   ElementsTransition(IsSimpleMapChangeTransition(
    1201             :                                          transition_source->elements_kind(),
    1202             :                                          transition_target->elements_kind())
    1203             :                                          ? ElementsTransition::kFastTransition
    1204             :                                          : ElementsTransition::kSlowTransition,
    1205             :                                      transition_source, transition_target)),
    1206          84 :               receiver, this_effect, this_control);
    1207             :         }
    1208             : 
    1209             :         // Load the {receiver} map.
    1210             :         Node* receiver_map = this_effect =
    1211             :             graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
    1212        6633 :                              receiver, this_effect, this_control);
    1213             : 
    1214             :         // Perform map check(s) on {receiver}.
    1215        2211 :         MapList const& receiver_maps = access_info.receiver_maps();
    1216        4422 :         if (j == access_infos.size() - 1) {
    1217             :           // Last map check on the fallthrough control path, do a
    1218             :           // conditional eager deoptimization exit here.
    1219             :           this_effect = BuildCheckMaps(receiver, this_effect, this_control,
    1220        1052 :                                        receiver_maps);
    1221             :           fallthrough_control = nullptr;
    1222             :         } else {
    1223             :           ZoneVector<Node*> this_controls(zone());
    1224             :           ZoneVector<Node*> this_effects(zone());
    1225        3477 :           for (Handle<Map> map : receiver_maps) {
    1226             :             Node* check =
    1227             :                 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
    1228        3477 :                                  jsgraph()->Constant(map));
    1229             :             Node* branch = graph()->NewNode(common()->Branch(), check,
    1230        1159 :                                             fallthrough_control);
    1231             :             this_controls.push_back(
    1232        3477 :                 graph()->NewNode(common()->IfTrue(), branch));
    1233        1159 :             this_effects.push_back(this_effect);
    1234        1159 :             fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
    1235             :           }
    1236             : 
    1237             :           // Create single chokepoint for the control.
    1238        2318 :           int const this_control_count = static_cast<int>(this_controls.size());
    1239        1159 :           if (this_control_count == 1) {
    1240        1159 :             this_control = this_controls.front();
    1241        1159 :             this_effect = this_effects.front();
    1242             :           } else {
    1243             :             this_control =
    1244             :                 graph()->NewNode(common()->Merge(this_control_count),
    1245           0 :                                  this_control_count, &this_controls.front());
    1246           0 :             this_effects.push_back(this_control);
    1247             :             this_effect =
    1248             :                 graph()->NewNode(common()->EffectPhi(this_control_count),
    1249           0 :                                  this_control_count + 1, &this_effects.front());
    1250             :           }
    1251             :         }
    1252             : 
    1253             :         // Access the actual element.
    1254             :         ValueEffectControl continuation = BuildElementAccess(
    1255             :             this_receiver, this_index, this_value, this_effect, this_control,
    1256        2211 :             access_info, access_mode, store_mode);
    1257        4422 :         values.push_back(continuation.value());
    1258        4422 :         effects.push_back(continuation.effect());
    1259        4422 :         controls.push_back(continuation.control());
    1260             :       }
    1261             : 
    1262             :       DCHECK_NULL(fallthrough_control);
    1263             : 
    1264             :       // Generate the final merge point for all (polymorphic) branches.
    1265        2104 :       int const control_count = static_cast<int>(controls.size());
    1266        1052 :       if (control_count == 0) {
    1267           0 :         value = effect = control = jsgraph()->Dead();
    1268        1052 :       } else if (control_count == 1) {
    1269           0 :         value = values.front();
    1270           0 :         effect = effects.front();
    1271           0 :         control = controls.front();
    1272             :       } else {
    1273             :         control = graph()->NewNode(common()->Merge(control_count),
    1274        2104 :                                    control_count, &controls.front());
    1275        1052 :         values.push_back(control);
    1276             :         value = graph()->NewNode(
    1277             :             common()->Phi(MachineRepresentation::kTagged, control_count),
    1278        3156 :             control_count + 1, &values.front());
    1279        1052 :         effects.push_back(control);
    1280             :         effect = graph()->NewNode(common()->EffectPhi(control_count),
    1281        2104 :                                   control_count + 1, &effects.front());
    1282             :       }
    1283             :     }
    1284             :   }
    1285             : 
    1286       25748 :   ReplaceWithValue(node, value, effect, control);
    1287             :   return Replace(value);
    1288             : }
    1289             : 
    1290             : template <typename KeyedICNexus>
    1291      120260 : Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
    1292             :     Node* node, Node* index, Node* value, KeyedICNexus const& nexus,
    1293             :     AccessMode access_mode, LanguageMode language_mode,
    1294         107 :     KeyedAccessStoreMode store_mode) {
    1295             :   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
    1296             :          node->opcode() == IrOpcode::kJSStoreProperty);
    1297      120260 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1298      120260 :   Node* effect = NodeProperties::GetEffectInput(node);
    1299      120260 :   Node* control = NodeProperties::GetControlInput(node);
    1300             : 
    1301             :   // Optimize access for constant {receiver}.
    1302             :   HeapObjectMatcher mreceiver(receiver);
    1303      131589 :   if (mreceiver.HasValue() && mreceiver.Value()->IsString()) {
    1304             :     Handle<String> string = Handle<String>::cast(mreceiver.Value());
    1305             : 
    1306             :     // Strings are immutable in JavaScript.
    1307         143 :     if (access_mode == AccessMode::kStore) return NoChange();
    1308             : 
    1309             :     // Properly deal with constant {index}.
    1310             :     NumberMatcher mindex(index);
    1311         249 :     if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) {
    1312             :       // Constant-fold the {index} access to {string}.
    1313             :       Node* value = jsgraph()->HeapConstant(
    1314             :           factory()->LookupSingleCharacterStringFromCode(
    1315         100 :               string->Get(static_cast<int>(mindex.Value()))));
    1316         107 :       ReplaceWithValue(node, value, effect, control);
    1317             :       return Replace(value);
    1318             :     }
    1319             : 
    1320             :     // We can only assume that the {index} is a valid array index if the IC
    1321             :     // is in element access mode and not MEGAMORPHIC, otherwise there's no
    1322             :     // guard for the bounds check below.
    1323         216 :     if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
    1324             :       // Ensure that {index} is less than {receiver} length.
    1325          82 :       Node* length = jsgraph()->Constant(string->length());
    1326             :       index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    1327          82 :                                         length, effect, control);
    1328             : 
    1329             :       // Return the character from the {receiver} as single character string.
    1330             :       value = graph()->NewNode(simplified()->StringCharAt(), receiver, index,
    1331          82 :                                control);
    1332             :       ReplaceWithValue(node, value, effect, control);
    1333             :       return Replace(value);
    1334             :     }
    1335             :   }
    1336             : 
    1337             :   // Check if the {nexus} reports type feedback for the IC.
    1338      240286 :   if (nexus.IsUninitialized()) {
    1339       84205 :     if (flags() & kBailoutOnUninitialized) {
    1340             :       return ReduceSoftDeoptimize(
    1341             :           node,
    1342         545 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    1343             :     }
    1344             :     return NoChange();
    1345             :   }
    1346             : 
    1347             :   // Extract receiver maps from the {nexus}.
    1348             :   MapHandleList receiver_maps;
    1349       35938 :   if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
    1350             :     return NoChange();
    1351       28506 :   } else if (receiver_maps.length() == 0) {
    1352           0 :     if (flags() & kBailoutOnUninitialized) {
    1353             :       return ReduceSoftDeoptimize(
    1354             :           node,
    1355           0 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    1356             :     }
    1357             :     return NoChange();
    1358             :   }
    1359             : 
    1360             :   // Optimize access for constant {index}.
    1361             :   HeapObjectMatcher mindex(index);
    1362       28894 :   if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
    1363             :     // Keyed access requires a ToPropertyKey on the {index} first before
    1364             :     // looking up the property on the object (see ES6 section 12.3.2.1).
    1365             :     // We can only do this for non-observable ToPropertyKey invocations,
    1366             :     // so we limit the constant indices to primitives at this point.
    1367             :     Handle<Name> name;
    1368         748 :     if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
    1369             :       uint32_t array_index;
    1370         374 :       if (name->AsArrayIndex(&array_index)) {
    1371             :         // Use the constant array index.
    1372           0 :         index = jsgraph()->Constant(static_cast<double>(array_index));
    1373             :       } else {
    1374         374 :         name = factory()->InternalizeName(name);
    1375             :         return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
    1376         374 :                                  language_mode);
    1377             :       }
    1378             :     }
    1379             :   }
    1380             : 
    1381             :   // Check if we have feedback for a named access.
    1382       28132 :   if (Name* name = nexus.FindFirstName()) {
    1383             :     return ReduceNamedAccess(node, value, receiver_maps,
    1384             :                              handle(name, isolate()), access_mode,
    1385         219 :                              language_mode, index);
    1386       27913 :   } else if (nexus.GetKeyType() != ELEMENT) {
    1387             :     // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
    1388             :     // that the {index} is a valid array index, thus we just let the IC continue
    1389             :     // to deal with this load/store.
    1390             :     return NoChange();
    1391       27888 :   } else if (nexus.ic_state() == MEGAMORPHIC) {
    1392             :     // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption
    1393             :     // that a numeric {index} is within the valid bounds for {receiver}, i.e.
    1394             :     // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus
    1395             :     // we cannot continue here if the IC state is MEGAMORPHIC.
    1396             :     return NoChange();
    1397             :   }
    1398             : 
    1399             :   // Try to lower the element access based on the {receiver_maps}.
    1400             :   return ReduceElementAccess(node, index, value, receiver_maps, access_mode,
    1401       26477 :                              language_mode, store_mode);
    1402             : }
    1403             : 
    1404        1018 : Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
    1405             :     Node* node, DeoptimizeReason reason) {
    1406        1018 :   Node* effect = NodeProperties::GetEffectInput(node);
    1407        1018 :   Node* control = NodeProperties::GetControlInput(node);
    1408        1018 :   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    1409             :   Node* deoptimize =
    1410             :       graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kSoft, reason),
    1411        1018 :                        frame_state, effect, control);
    1412             :   // TODO(bmeurer): This should be on the AdvancedReducer somehow.
    1413        1018 :   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
    1414        1018 :   Revisit(graph()->end());
    1415        1018 :   node->TrimInputCount(0);
    1416        1018 :   NodeProperties::ChangeOp(node, common()->Dead());
    1417        1018 :   return Changed(node);
    1418             : }
    1419             : 
    1420             : 
    1421      152582 : Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
    1422             :   DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
    1423      152582 :   PropertyAccess const& p = PropertyAccessOf(node->op());
    1424       76291 :   Node* const index = NodeProperties::GetValueInput(node, 1);
    1425       76291 :   Node* const value = jsgraph()->Dead();
    1426             : 
    1427             :   // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus.
    1428       76291 :   if (!p.feedback().IsValid()) return NoChange();
    1429             :   KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1430             : 
    1431             :   // Try to lower the keyed access based on the {nexus}.
    1432             :   return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad,
    1433       76291 :                            p.language_mode(), STANDARD_STORE);
    1434             : }
    1435             : 
    1436             : 
    1437       43969 : Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
    1438             :   DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
    1439       87938 :   PropertyAccess const& p = PropertyAccessOf(node->op());
    1440       43969 :   Node* const index = NodeProperties::GetValueInput(node, 1);
    1441       43969 :   Node* const value = NodeProperties::GetValueInput(node, 2);
    1442             : 
    1443             :   // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus.
    1444       43969 :   if (!p.feedback().IsValid()) return NoChange();
    1445             :   KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1446             : 
    1447             :   // Extract the keyed access store mode from the KEYED_STORE_IC.
    1448       43969 :   KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
    1449             : 
    1450             :   // Try to lower the keyed access based on the {nexus}.
    1451             :   return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
    1452       43969 :                            p.language_mode(), store_mode);
    1453             : }
    1454             : 
    1455             : JSNativeContextSpecialization::ValueEffectControl
    1456       89343 : JSNativeContextSpecialization::BuildPropertyAccess(
    1457             :     Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
    1458       27654 :     Node* control, Handle<Name> name, PropertyAccessInfo const& access_info,
    1459       75352 :     AccessMode access_mode, LanguageMode language_mode) {
    1460             :   // Determine actual holder and perform prototype chain checks.
    1461             :   Handle<JSObject> holder;
    1462       89343 :   if (access_info.holder().ToHandle(&holder)) {
    1463             :     DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
    1464       19218 :     AssumePrototypesStable(access_info.receiver_maps(), holder);
    1465             :   }
    1466             : 
    1467             :   // Generate the actual property access.
    1468       89343 :   if (access_info.IsNotFound()) {
    1469             :     DCHECK_EQ(AccessMode::kLoad, access_mode);
    1470        2287 :     value = jsgraph()->UndefinedConstant();
    1471       87056 :   } else if (access_info.IsDataConstant()) {
    1472             :     DCHECK(!FLAG_track_constant_fields);
    1473       58211 :     Node* constant_value = jsgraph()->Constant(access_info.constant());
    1474       58211 :     if (access_mode == AccessMode::kStore) {
    1475             :       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value,
    1476           7 :                                      constant_value);
    1477             :       effect =
    1478          21 :           graph()->NewNode(simplified()->CheckIf(), check, effect, control);
    1479             :     }
    1480             :     value = constant_value;
    1481       28845 :   } else if (access_info.IsAccessorConstant()) {
    1482             :     // TODO(bmeurer): Properly rewire the IfException edge here if there's any.
    1483        1191 :     Node* target = jsgraph()->Constant(access_info.constant());
    1484        1191 :     FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
    1485             :     Handle<SharedFunctionInfo> shared_info =
    1486        1191 :         frame_info.shared_info().ToHandleChecked();
    1487        1191 :     switch (access_mode) {
    1488             :       case AccessMode::kLoad: {
    1489             :         // We need a FrameState for the getter stub to restore the correct
    1490             :         // context before returning to fullcodegen.
    1491             :         FrameStateFunctionInfo const* frame_info0 =
    1492             :             common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub,
    1493         736 :                                                    1, 0, shared_info);
    1494             :         Node* frame_state0 = graph()->NewNode(
    1495             :             common()->FrameState(BailoutId::None(),
    1496             :                                  OutputFrameStateCombine::Ignore(),
    1497             :                                  frame_info0),
    1498             :             graph()->NewNode(common()->StateValues(1, SparseInputMask::Dense()),
    1499             :                              receiver),
    1500             :             jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
    1501        2944 :             context, target, frame_state);
    1502             : 
    1503             :         // Introduce the call to the getter function.
    1504         736 :         if (access_info.constant()->IsJSFunction()) {
    1505             :           value = effect = control = graph()->NewNode(
    1506             :               javascript()->Call(2, 0.0f, VectorSlotPair(),
    1507             :                                  ConvertReceiverMode::kNotNullOrUndefined),
    1508        2205 :               target, receiver, context, frame_state0, effect, control);
    1509             :         } else {
    1510             :           DCHECK(access_info.constant()->IsFunctionTemplateInfo());
    1511             :           Handle<FunctionTemplateInfo> function_template_info(
    1512           1 :               Handle<FunctionTemplateInfo>::cast(access_info.constant()));
    1513             :           DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
    1514             :           ValueEffectControl value_effect_control = InlineApiCall(
    1515             :               receiver, context, target, frame_state0, nullptr, effect, control,
    1516           1 :               shared_info, function_template_info);
    1517           1 :           value = value_effect_control.value();
    1518           1 :           effect = value_effect_control.effect();
    1519           1 :           control = value_effect_control.control();
    1520             :         }
    1521             :         break;
    1522             :       }
    1523             :       case AccessMode::kStoreInLiteral:
    1524             :       case AccessMode::kStore: {
    1525             :         // We need a FrameState for the setter stub to restore the correct
    1526             :         // context and return the appropriate value to fullcodegen.
    1527             :         FrameStateFunctionInfo const* frame_info0 =
    1528             :             common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub,
    1529         455 :                                                    2, 0, shared_info);
    1530             :         Node* frame_state0 = graph()->NewNode(
    1531             :             common()->FrameState(BailoutId::None(),
    1532             :                                  OutputFrameStateCombine::Ignore(),
    1533             :                                  frame_info0),
    1534             :             graph()->NewNode(common()->StateValues(2, SparseInputMask::Dense()),
    1535             :                              receiver, value),
    1536             :             jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
    1537        1820 :             context, target, frame_state);
    1538             : 
    1539             :         // Introduce the call to the setter function.
    1540         455 :         if (access_info.constant()->IsJSFunction()) {
    1541             :           effect = control = graph()->NewNode(
    1542             :               javascript()->Call(3, 0.0f, VectorSlotPair(),
    1543             :                                  ConvertReceiverMode::kNotNullOrUndefined),
    1544        1365 :               target, receiver, value, context, frame_state0, effect, control);
    1545             :         } else {
    1546             :           DCHECK(access_info.constant()->IsFunctionTemplateInfo());
    1547             :           Handle<FunctionTemplateInfo> function_template_info(
    1548           0 :               Handle<FunctionTemplateInfo>::cast(access_info.constant()));
    1549             :           DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
    1550             :           ValueEffectControl value_effect_control = InlineApiCall(
    1551             :               receiver, context, target, frame_state0, value, effect, control,
    1552           0 :               shared_info, function_template_info);
    1553           0 :           value = value_effect_control.value();
    1554           0 :           effect = value_effect_control.effect();
    1555           0 :           control = value_effect_control.control();
    1556             :         }
    1557             :         break;
    1558             :       }
    1559             :     }
    1560             :   } else {
    1561             :     DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
    1562             :     FieldIndex const field_index = access_info.field_index();
    1563             :     Type* const field_type = access_info.field_type();
    1564             :     MachineRepresentation const field_representation =
    1565       27654 :         access_info.field_representation();
    1566       27654 :     if (access_mode == AccessMode::kLoad) {
    1567       20401 :       if (access_info.holder().ToHandle(&holder)) {
    1568         190 :         receiver = jsgraph()->Constant(holder);
    1569             :       }
    1570             :       // Optimize immutable property loads.
    1571             :       HeapObjectMatcher m(receiver);
    1572       22054 :       if (m.HasValue() && m.Value()->IsJSObject()) {
    1573             :         // TODO(ishell): Use something simpler like
    1574             :         //
    1575             :         // Handle<Object> value =
    1576             :         //     JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
    1577             :         //                              Representation::Tagged(), field_index);
    1578             :         //
    1579             :         // here, once we have the immutable bit in the access_info.
    1580             : 
    1581             :         // TODO(turbofan): Given that we already have the field_index here, we
    1582             :         // might be smarter in the future and not rely on the LookupIterator,
    1583             :         // but for now let's just do what Crankshaft does.
    1584             :         LookupIterator it(m.Value(), name,
    1585        1653 :                           LookupIterator::OWN_SKIP_INTERCEPTOR);
    1586        1653 :         if (it.state() == LookupIterator::DATA) {
    1587             :           bool is_reaonly_non_configurable =
    1588        1679 :               it.IsReadOnly() && !it.IsConfigurable();
    1589        1508 :           if (is_reaonly_non_configurable ||
    1590             :               (FLAG_track_constant_fields &&
    1591             :                access_info.IsDataConstantField())) {
    1592         342 :             Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
    1593         171 :             if (!is_reaonly_non_configurable) {
    1594             :               // It's necessary to add dependency on the map that introduced
    1595             :               // the field.
    1596             :               DCHECK(access_info.IsDataConstantField());
    1597             :               DCHECK(!it.is_dictionary_holder());
    1598           0 :               Handle<Map> field_owner_map = it.GetFieldOwnerMap();
    1599             :               dependencies()->AssumeFieldOwner(field_owner_map);
    1600             :             }
    1601         342 :             return ValueEffectControl(value, effect, control);
    1602             :           }
    1603             :         }
    1604             :       }
    1605             :     }
    1606             :     Node* storage = receiver;
    1607       27483 :     if (!field_index.is_inobject()) {
    1608             :       storage = effect = graph()->NewNode(
    1609             :           simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
    1610        4443 :           storage, effect, control);
    1611             :     }
    1612             :     FieldAccess field_access = {
    1613             :         kTaggedBase,
    1614             :         field_index.offset(),
    1615             :         name,
    1616             :         MaybeHandle<Map>(),
    1617             :         field_type,
    1618             :         MachineType::TypeForRepresentation(field_representation),
    1619       82449 :         kFullWriteBarrier};
    1620       27483 :     if (access_mode == AccessMode::kLoad) {
    1621       20230 :       if (field_representation == MachineRepresentation::kFloat64) {
    1622         686 :         if (!field_index.is_inobject() || field_index.is_hidden_field() ||
    1623             :             !FLAG_unbox_double_fields) {
    1624             :           FieldAccess const storage_access = {kTaggedBase,
    1625             :                                               field_index.offset(),
    1626             :                                               name,
    1627             :                                               MaybeHandle<Map>(),
    1628             :                                               Type::OtherInternal(),
    1629             :                                               MachineType::TaggedPointer(),
    1630          60 :                                               kPointerWriteBarrier};
    1631             :           storage = effect =
    1632             :               graph()->NewNode(simplified()->LoadField(storage_access), storage,
    1633          90 :                                effect, control);
    1634          30 :           field_access.offset = HeapNumber::kValueOffset;
    1635          30 :           field_access.name = MaybeHandle<Name>();
    1636             :         }
    1637       19872 :       } else if (field_representation ==
    1638             :                  MachineRepresentation::kTaggedPointer) {
    1639             :         // Remember the map of the field value, if its map is stable. This is
    1640             :         // used by the LoadElimination to eliminate map checks on the result.
    1641             :         Handle<Map> field_map;
    1642        5532 :         if (access_info.field_map().ToHandle(&field_map)) {
    1643        1912 :           if (field_map->is_stable()) {
    1644        1877 :             dependencies()->AssumeMapStable(field_map);
    1645        1877 :             field_access.map = field_map;
    1646             :           }
    1647             :         }
    1648             :       }
    1649             :       value = effect = graph()->NewNode(simplified()->LoadField(field_access),
    1650       60690 :                                         storage, effect, control);
    1651             :     } else {
    1652             :       bool store_to_constant_field = FLAG_track_constant_fields &&
    1653             :                                      (access_mode == AccessMode::kStore) &&
    1654             :                                      access_info.IsDataConstantField();
    1655             : 
    1656             :       DCHECK(access_mode == AccessMode::kStore ||
    1657             :              access_mode == AccessMode::kStoreInLiteral);
    1658        7253 :       switch (field_representation) {
    1659             :         case MachineRepresentation::kFloat64: {
    1660             :           value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
    1661         738 :                                             effect, control);
    1662         438 :           if (!field_index.is_inobject() || field_index.is_hidden_field() ||
    1663             :               !FLAG_unbox_double_fields) {
    1664          54 :             if (access_info.HasTransitionMap()) {
    1665             :               // Allocate a MutableHeapNumber for the new property.
    1666             :               effect = graph()->NewNode(
    1667             :                   common()->BeginRegion(RegionObservability::kNotObservable),
    1668          18 :                   effect);
    1669             :               Node* box = effect = graph()->NewNode(
    1670             :                   simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
    1671          27 :                   jsgraph()->Constant(HeapNumber::kSize), effect, control);
    1672             :               effect = graph()->NewNode(
    1673             :                   simplified()->StoreField(AccessBuilder::ForMap()), box,
    1674             :                   jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
    1675          27 :                   effect, control);
    1676             :               effect = graph()->NewNode(
    1677             :                   simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
    1678          27 :                   box, value, effect, control);
    1679             :               value = effect =
    1680          18 :                   graph()->NewNode(common()->FinishRegion(), box, effect);
    1681             : 
    1682           9 :               field_access.type = Type::Any();
    1683           9 :               field_access.machine_type = MachineType::TaggedPointer();
    1684           9 :               field_access.write_barrier_kind = kPointerWriteBarrier;
    1685             :             } else {
    1686             :               // We just store directly to the MutableHeapNumber.
    1687             :               FieldAccess const storage_access = {kTaggedBase,
    1688             :                                                   field_index.offset(),
    1689             :                                                   name,
    1690             :                                                   MaybeHandle<Map>(),
    1691             :                                                   Type::OtherInternal(),
    1692             :                                                   MachineType::TaggedPointer(),
    1693          90 :                                                   kPointerWriteBarrier};
    1694             :               storage = effect =
    1695             :                   graph()->NewNode(simplified()->LoadField(storage_access),
    1696          90 :                                    storage, effect, control);
    1697          45 :               field_access.offset = HeapNumber::kValueOffset;
    1698          45 :               field_access.name = MaybeHandle<Name>();
    1699          45 :               field_access.machine_type = MachineType::Float64();
    1700             :             }
    1701             :           }
    1702             :           if (store_to_constant_field) {
    1703             :             DCHECK(!access_info.HasTransitionMap());
    1704             :             // If the field is constant check that the value we are going
    1705             :             // to store matches current value.
    1706             :             Node* current_value = effect =
    1707             :                 graph()->NewNode(simplified()->LoadField(field_access), storage,
    1708             :                                  effect, control);
    1709             : 
    1710             :             Node* check = graph()->NewNode(simplified()->NumberEqual(),
    1711             :                                            current_value, value);
    1712             :             effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
    1713             :                                       control);
    1714             :             return ValueEffectControl(value, effect, control);
    1715             :           }
    1716             :           break;
    1717             :         }
    1718             :         case MachineRepresentation::kTaggedSigned:
    1719             :         case MachineRepresentation::kTaggedPointer:
    1720             :         case MachineRepresentation::kTagged:
    1721             :           if (store_to_constant_field) {
    1722             :             DCHECK(!access_info.HasTransitionMap());
    1723             :             // If the field is constant check that the value we are going
    1724             :             // to store matches current value.
    1725             :             Node* current_value = effect =
    1726             :                 graph()->NewNode(simplified()->LoadField(field_access), storage,
    1727             :                                  effect, control);
    1728             : 
    1729             :             Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
    1730             :                                            current_value, value);
    1731             :             effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
    1732             :                                       control);
    1733             :             return ValueEffectControl(value, effect, control);
    1734             :           }
    1735             : 
    1736        7007 :           if (field_representation == MachineRepresentation::kTaggedSigned) {
    1737             :             value = effect = graph()->NewNode(simplified()->CheckSmi(), value,
    1738       12768 :                                               effect, control);
    1739        4256 :             field_access.write_barrier_kind = kNoWriteBarrier;
    1740             : 
    1741        2751 :           } else if (field_representation ==
    1742             :                      MachineRepresentation::kTaggedPointer) {
    1743             :             // Ensure that {value} is a HeapObject.
    1744        2297 :             value = BuildCheckHeapObject(value, &effect, control);
    1745             :             Handle<Map> field_map;
    1746        2297 :             if (access_info.field_map().ToHandle(&field_map)) {
    1747             :               // Emit a map check for the value.
    1748             :               effect = graph()->NewNode(
    1749             :                   simplified()->CheckMaps(CheckMapsFlag::kNone,
    1750             :                                           ZoneHandleSet<Map>(field_map)),
    1751        1185 :                   value, effect, control);
    1752             :             }
    1753        2297 :             field_access.write_barrier_kind = kPointerWriteBarrier;
    1754             : 
    1755             :           } else {
    1756             :             DCHECK_EQ(MachineRepresentation::kTagged, field_representation);
    1757             :           }
    1758             :           break;
    1759             :         case MachineRepresentation::kNone:
    1760             :         case MachineRepresentation::kBit:
    1761             :         case MachineRepresentation::kWord8:
    1762             :         case MachineRepresentation::kWord16:
    1763             :         case MachineRepresentation::kWord32:
    1764             :         case MachineRepresentation::kWord64:
    1765             :         case MachineRepresentation::kFloat32:
    1766             :         case MachineRepresentation::kSimd128:
    1767             :         case MachineRepresentation::kSimd1x4:
    1768             :         case MachineRepresentation::kSimd1x8:
    1769             :         case MachineRepresentation::kSimd1x16:
    1770           0 :           UNREACHABLE();
    1771             :           break;
    1772             :       }
    1773             :       // Check if we need to perform a transitioning store.
    1774             :       Handle<Map> transition_map;
    1775        7253 :       if (access_info.transition_map().ToHandle(&transition_map)) {
    1776             :         // Check if we need to grow the properties backing store
    1777             :         // with this transitioning store.
    1778             :         Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
    1779        4517 :                                  isolate());
    1780        4517 :         if (original_map->unused_property_fields() == 0) {
    1781             :           DCHECK(!field_index.is_inobject());
    1782             : 
    1783             :           // Reallocate the properties {storage}.
    1784             :           storage = effect = BuildExtendPropertiesBackingStore(
    1785         257 :               original_map, storage, effect, control);
    1786             : 
    1787             :           // Perform the actual store.
    1788             :           effect = graph()->NewNode(simplified()->StoreField(field_access),
    1789         514 :                                     storage, value, effect, control);
    1790             : 
    1791             :           // Atomically switch to the new properties below.
    1792         257 :           field_access = AccessBuilder::ForJSObjectProperties();
    1793             :           value = storage;
    1794             :           storage = receiver;
    1795             :         }
    1796             :         effect = graph()->NewNode(
    1797       13551 :             common()->BeginRegion(RegionObservability::kObservable), effect);
    1798             :         effect = graph()->NewNode(
    1799             :             simplified()->StoreField(AccessBuilder::ForMap()), receiver,
    1800       13551 :             jsgraph()->Constant(transition_map), effect, control);
    1801             :         effect = graph()->NewNode(simplified()->StoreField(field_access),
    1802        9034 :                                   storage, value, effect, control);
    1803             :         effect = graph()->NewNode(common()->FinishRegion(),
    1804       13551 :                                   jsgraph()->UndefinedConstant(), effect);
    1805             :       } else {
    1806             :         // Regular non-transitioning field store.
    1807             :         effect = graph()->NewNode(simplified()->StoreField(field_access),
    1808        8208 :                                   storage, value, effect, control);
    1809             :       }
    1810             :     }
    1811             :   }
    1812             : 
    1813       89172 :   return ValueEffectControl(value, effect, control);
    1814             : }
    1815             : 
    1816       44202 : Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
    1817       44489 :     Node* node) {
    1818             :   DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
    1819             : 
    1820       44202 :   FeedbackParameter const& p = FeedbackParameterOf(node->op());
    1821             : 
    1822       44202 :   if (!p.feedback().IsValid()) return NoChange();
    1823             : 
    1824             :   StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(),
    1825             :                                           p.feedback().slot());
    1826       44202 :   if (nexus.IsUninitialized()) {
    1827             :     return NoChange();
    1828             :   }
    1829             : 
    1830         214 :   if (nexus.ic_state() == MEGAMORPHIC) {
    1831             :     return NoChange();
    1832             :   }
    1833             : 
    1834             :   DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
    1835             : 
    1836         171 :   Map* map = nexus.FindFirstMap();
    1837         171 :   if (map == nullptr) {
    1838             :     // Maps are weakly held in the type feedback vector, we may not have one.
    1839             :     return NoChange();
    1840             :   }
    1841             : 
    1842             :   Handle<Map> receiver_map(map, isolate());
    1843             :   Handle<Name> cached_name =
    1844         171 :       handle(Name::cast(nexus.GetFeedbackExtra()), isolate());
    1845             : 
    1846         171 :   PropertyAccessInfo access_info;
    1847             :   AccessInfoFactory access_info_factory(dependencies(), native_context(),
    1848         342 :                                         graph()->zone());
    1849         171 :   if (!access_info_factory.ComputePropertyAccessInfo(
    1850             :           receiver_map, cached_name, AccessMode::kStoreInLiteral,
    1851         171 :           &access_info)) {
    1852             :     return NoChange();
    1853             :   }
    1854             : 
    1855         116 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1856         116 :   Node* effect = NodeProperties::GetEffectInput(node);
    1857         116 :   Node* control = NodeProperties::GetControlInput(node);
    1858             : 
    1859             :   // Monomorphic property access.
    1860         116 :   receiver = BuildCheckHeapObject(receiver, &effect, control);
    1861             : 
    1862             :   effect =
    1863         116 :       BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
    1864             : 
    1865             :   // Ensure that {name} matches the cached name.
    1866         116 :   Node* name = NodeProperties::GetValueInput(node, 1);
    1867             :   Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
    1868         348 :                                  jsgraph()->HeapConstant(cached_name));
    1869         348 :   effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
    1870             : 
    1871         116 :   Node* value = NodeProperties::GetValueInput(node, 2);
    1872         116 :   Node* context = NodeProperties::GetContextInput(node);
    1873         116 :   Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
    1874             : 
    1875             :   // Generate the actual property access.
    1876             :   ValueEffectControl continuation = BuildPropertyAccess(
    1877             :       receiver, value, context, frame_state_lazy, effect, control, cached_name,
    1878         116 :       access_info, AccessMode::kStoreInLiteral, LanguageMode::SLOPPY);
    1879         116 :   value = continuation.value();
    1880         116 :   effect = continuation.effect();
    1881         116 :   control = continuation.control();
    1882             : 
    1883         116 :   ReplaceWithValue(node, value, effect, control);
    1884             :   return Replace(value);
    1885             : }
    1886             : 
    1887             : namespace {
    1888             : 
    1889        4994 : ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
    1890        4994 :   switch (kind) {
    1891             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
    1892             :   case TYPE##_ELEMENTS:                                 \
    1893             :     return kExternal##Type##Array;
    1894         385 :     TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1895             : #undef TYPED_ARRAY_CASE
    1896             :     default:
    1897             :       break;
    1898             :   }
    1899           0 :   UNREACHABLE();
    1900             :   return kExternalInt8Array;
    1901             : }
    1902             : 
    1903             : }  // namespace
    1904             : 
    1905             : JSNativeContextSpecialization::ValueEffectControl
    1906       26845 : JSNativeContextSpecialization::BuildElementAccess(
    1907             :     Node* receiver, Node* index, Node* value, Node* effect, Node* control,
    1908       26845 :     ElementAccessInfo const& access_info, AccessMode access_mode,
    1909       13331 :     KeyedAccessStoreMode store_mode) {
    1910             :   DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
    1911             : 
    1912             :   // TODO(bmeurer): We currently specialize based on elements kind. We should
    1913             :   // also be able to properly support strings and other JSObjects here.
    1914             :   ElementsKind elements_kind = access_info.elements_kind();
    1915       26845 :   MapList const& receiver_maps = access_info.receiver_maps();
    1916             : 
    1917       26845 :   if (IsFixedTypedArrayElementsKind(elements_kind)) {
    1918             :     Node* buffer;
    1919             :     Node* length;
    1920             :     Node* base_pointer;
    1921             :     Node* external_pointer;
    1922             : 
    1923             :     // Check if we can constant-fold information about the {receiver} (i.e.
    1924             :     // for asm.js-like code patterns).
    1925             :     HeapObjectMatcher m(receiver);
    1926        6939 :     if (m.HasValue() && m.Value()->IsJSTypedArray()) {
    1927             :       Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(m.Value());
    1928             : 
    1929             :       // Determine the {receiver}s (known) length.
    1930        3890 :       length = jsgraph()->Constant(typed_array->length_value());
    1931             : 
    1932             :       // Check if the {receiver}s buffer was neutered.
    1933        3890 :       buffer = jsgraph()->HeapConstant(typed_array->GetBuffer());
    1934             : 
    1935             :       // Load the (known) base and external pointer for the {receiver}. The
    1936             :       // {external_pointer} might be invalid if the {buffer} was neutered, so
    1937             :       // we need to make sure that any access is properly guarded.
    1938        1945 :       base_pointer = jsgraph()->ZeroConstant();
    1939             :       external_pointer = jsgraph()->PointerConstant(
    1940             :           FixedTypedArrayBase::cast(typed_array->elements())
    1941             :               ->external_pointer());
    1942             :     } else {
    1943             :       // Load the {receiver}s length.
    1944             :       length = effect = graph()->NewNode(
    1945             :           simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()),
    1946        9147 :           receiver, effect, control);
    1947             : 
    1948             :       // Load the buffer for the {receiver}.
    1949             :       buffer = effect = graph()->NewNode(
    1950             :           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
    1951        9147 :           receiver, effect, control);
    1952             : 
    1953             :       // Load the elements for the {receiver}.
    1954             :       Node* elements = effect = graph()->NewNode(
    1955             :           simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
    1956        9147 :           receiver, effect, control);
    1957             : 
    1958             :       // Load the base and external pointer for the {receiver}s {elements}.
    1959             :       base_pointer = effect = graph()->NewNode(
    1960             :           simplified()->LoadField(
    1961             :               AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
    1962        9147 :           elements, effect, control);
    1963             :       external_pointer = effect = graph()->NewNode(
    1964             :           simplified()->LoadField(
    1965             :               AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
    1966        9147 :           elements, effect, control);
    1967             :     }
    1968             : 
    1969             :     // See if we can skip the neutering check.
    1970        4994 :     if (isolate()->IsArrayBufferNeuteringIntact()) {
    1971             :       // Add a code dependency so we are deoptimized in case an ArrayBuffer
    1972             :       // gets neutered.
    1973             :       dependencies()->AssumePropertyCell(
    1974             :           factory()->array_buffer_neutering_protector());
    1975             :     } else {
    1976             :       // Default to zero if the {receiver}s buffer was neutered.
    1977             :       Node* check = effect = graph()->NewNode(
    1978         150 :           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
    1979             :       length = graph()->NewNode(
    1980             :           common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
    1981         300 :           check, jsgraph()->ZeroConstant(), length);
    1982             :     }
    1983             : 
    1984        4994 :     if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
    1985             :       // Check that the {index} is a valid array index, we do the actual
    1986             :       // bounds check below and just skip the store below if it's out of
    1987             :       // bounds for the {receiver}.
    1988             :       index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    1989             :                                         jsgraph()->Constant(Smi::kMaxValue),
    1990         188 :                                         effect, control);
    1991             :     } else {
    1992             :       // Check that the {index} is in the valid range for the {receiver}.
    1993             :       index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    1994        4900 :                                         length, effect, control);
    1995             :     }
    1996             : 
    1997             :     // Access the actual element.
    1998             :     ExternalArrayType external_array_type =
    1999        4994 :         GetArrayTypeFromElementsKind(elements_kind);
    2000        4994 :     switch (access_mode) {
    2001             :       case AccessMode::kLoad: {
    2002             :         value = effect = graph()->NewNode(
    2003             :             simplified()->LoadTypedElement(external_array_type), buffer,
    2004        2546 :             base_pointer, external_pointer, index, effect, control);
    2005        2546 :         break;
    2006             :       }
    2007             :       case AccessMode::kStoreInLiteral:
    2008           0 :         UNREACHABLE();
    2009             :         break;
    2010             :       case AccessMode::kStore: {
    2011             :         // Ensure that the {value} is actually a Number.
    2012             :         value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
    2013        2448 :                                           effect, control);
    2014             : 
    2015             :         // Introduce the appropriate truncation for {value}. Currently we
    2016             :         // only need to do this for ClamedUint8Array {receiver}s, as the
    2017             :         // other truncations are implicit in the StoreTypedElement, but we
    2018             :         // might want to change that at some point.
    2019        2448 :         if (external_array_type == kExternalUint8ClampedArray) {
    2020         457 :           value = graph()->NewNode(simplified()->NumberToUint8Clamped(), value);
    2021             :         }
    2022             : 
    2023             :         // Check if we can skip the out-of-bounds store.
    2024        2448 :         if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
    2025             :           Node* check =
    2026          94 :               graph()->NewNode(simplified()->NumberLessThan(), index, length);
    2027             :           Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
    2028          94 :                                           check, control);
    2029             : 
    2030          94 :           Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    2031             :           Node* etrue = effect;
    2032             :           {
    2033             :             // Perform the actual store.
    2034             :             etrue = graph()->NewNode(
    2035             :                 simplified()->StoreTypedElement(external_array_type), buffer,
    2036          94 :                 base_pointer, external_pointer, index, value, etrue, if_true);
    2037             :           }
    2038             : 
    2039          94 :           Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    2040             :           Node* efalse = effect;
    2041             :           {
    2042             :             // Just ignore the out-of-bounds write.
    2043             :           }
    2044             : 
    2045          94 :           control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    2046             :           effect =
    2047          94 :               graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    2048             :         } else {
    2049             :           // Perform the actual store
    2050             :           effect = graph()->NewNode(
    2051             :               simplified()->StoreTypedElement(external_array_type), buffer,
    2052        2354 :               base_pointer, external_pointer, index, value, effect, control);
    2053             :         }
    2054             :         break;
    2055             :       }
    2056             :     }
    2057             :   } else {
    2058             :     // Load the elements for the {receiver}.
    2059             :     Node* elements = effect = graph()->NewNode(
    2060             :         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
    2061       65553 :         effect, control);
    2062             : 
    2063             :     // Don't try to store to a copy-on-write backing store.
    2064       30423 :     if (access_mode == AccessMode::kStore &&
    2065       29546 :         IsFastSmiOrObjectElementsKind(elements_kind) &&
    2066             :         store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
    2067             :       effect = graph()->NewNode(
    2068             :           simplified()->CheckMaps(
    2069             :               CheckMapsFlag::kNone,
    2070             :               ZoneHandleSet<Map>(factory()->fixed_array_map())),
    2071       15178 :           elements, effect, control);
    2072             :     }
    2073             : 
    2074             :     // Check if the {receiver} is a JSArray.
    2075             :     bool receiver_is_jsarray = HasOnlyJSArrayMaps(receiver_maps);
    2076             : 
    2077             :     // Load the length of the {receiver}.
    2078             :     Node* length = effect =
    2079             :         receiver_is_jsarray
    2080             :             ? graph()->NewNode(
    2081             :                   simplified()->LoadField(
    2082             :                       AccessBuilder::ForJSArrayLength(elements_kind)),
    2083       80258 :                   receiver, effect, control)
    2084             :             : graph()->NewNode(
    2085             :                   simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
    2086       50848 :                   elements, effect, control);
    2087             : 
    2088             :     // Check if we might need to grow the {elements} backing store.
    2089       21851 :     if (IsGrowStoreMode(store_mode)) {
    2090             :       DCHECK_EQ(AccessMode::kStore, access_mode);
    2091             : 
    2092             :       // Check that the {index} is a valid array index; the actual checking
    2093             :       // happens below right before the element store.
    2094             :       index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    2095             :                                         jsgraph()->Constant(Smi::kMaxValue),
    2096         926 :                                         effect, control);
    2097             :     } else {
    2098             :       // Check that the {index} is in the valid range for the {receiver}.
    2099             :       index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
    2100       21388 :                                         length, effect, control);
    2101             :     }
    2102             : 
    2103             :     // Compute the element access.
    2104             :     Type* element_type = Type::NonInternal();
    2105             :     MachineType element_machine_type = MachineType::AnyTagged();
    2106       21851 :     if (IsFastDoubleElementsKind(elements_kind)) {
    2107             :       element_type = Type::Number();
    2108             :       element_machine_type = MachineType::Float64();
    2109       20010 :     } else if (IsFastSmiElementsKind(elements_kind)) {
    2110             :       element_type = Type::SignedSmall();
    2111             :       element_machine_type = MachineType::TaggedSigned();
    2112             :     }
    2113             :     ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
    2114             :                                     element_type, element_machine_type,
    2115       21851 :                                     kFullWriteBarrier};
    2116             : 
    2117             :     // Access the actual element.
    2118       21851 :     if (access_mode == AccessMode::kLoad) {
    2119             :       // Compute the real element access type, which includes the hole in case
    2120             :       // of holey backing stores.
    2121       13279 :       if (IsHoleyElementsKind(elements_kind)) {
    2122             :         element_access.type =
    2123        3147 :             Type::Union(element_type, Type::Hole(), graph()->zone());
    2124             :       }
    2125       13279 :       if (elements_kind == FAST_HOLEY_ELEMENTS ||
    2126             :           elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
    2127        2375 :         element_access.machine_type = MachineType::AnyTagged();
    2128             :       }
    2129             :       // Perform the actual backing store access.
    2130             :       value = effect =
    2131             :           graph()->NewNode(simplified()->LoadElement(element_access), elements,
    2132       13279 :                            index, effect, control);
    2133             :       // Handle loading from holey backing stores correctly, by either mapping
    2134             :       // the hole to undefined if possible, or deoptimizing otherwise.
    2135       13279 :       if (elements_kind == FAST_HOLEY_ELEMENTS ||
    2136             :           elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
    2137             :         // Check if we are allowed to turn the hole into undefined.
    2138        2375 :         if (CanTreatHoleAsUndefined(receiver_maps)) {
    2139             :           // Turn the hole into undefined.
    2140             :           value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
    2141        1566 :                                    value);
    2142             :         } else {
    2143             :           // Bailout if we see the hole.
    2144             :           value = effect = graph()->NewNode(simplified()->CheckTaggedHole(),
    2145         809 :                                             value, effect, control);
    2146             :         }
    2147       10904 :       } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
    2148             :         // Perform the hole check on the result.
    2149             :         CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
    2150             :         // Check if we are allowed to return the hole directly.
    2151         772 :         if (CanTreatHoleAsUndefined(receiver_maps)) {
    2152             :           // Return the signaling NaN hole directly if all uses are truncating.
    2153             :           mode = CheckFloat64HoleMode::kAllowReturnHole;
    2154             :         }
    2155             :         value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode),
    2156         772 :                                           value, effect, control);
    2157             :       }
    2158             :     } else {
    2159             :       DCHECK_EQ(AccessMode::kStore, access_mode);
    2160        8572 :       if (IsFastSmiElementsKind(elements_kind)) {
    2161             :         value = effect =
    2162        1828 :             graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
    2163        6744 :       } else if (IsFastDoubleElementsKind(elements_kind)) {
    2164             :         value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
    2165         877 :                                           effect, control);
    2166             :         // Make sure we do not store signalling NaNs into double arrays.
    2167         877 :         value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
    2168             :       }
    2169             : 
    2170             :       // Ensure that copy-on-write backing store is writable.
    2171        8572 :       if (IsFastSmiOrObjectElementsKind(elements_kind) &&
    2172             :           store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
    2173             :         elements = effect =
    2174             :             graph()->NewNode(simplified()->EnsureWritableFastElements(),
    2175         106 :                              receiver, elements, effect, control);
    2176        8466 :       } else if (IsGrowStoreMode(store_mode)) {
    2177             :         // Grow {elements} backing store if necessary. Also updates the
    2178             :         // "length" property for JSArray {receiver}s, hence there must
    2179             :         // not be any other check after this operation, as the write
    2180             :         // to the "length" property is observable.
    2181             :         GrowFastElementsFlags flags = GrowFastElementsFlag::kNone;
    2182         463 :         if (receiver_is_jsarray) {
    2183             :           flags |= GrowFastElementsFlag::kArrayObject;
    2184             :         }
    2185         463 :         if (IsHoleyElementsKind(elements_kind)) {
    2186             :           flags |= GrowFastElementsFlag::kHoleyElements;
    2187             :         }
    2188         463 :         if (IsFastDoubleElementsKind(elements_kind)) {
    2189             :           flags |= GrowFastElementsFlag::kDoubleElements;
    2190             :         }
    2191             :         elements = effect = graph()->NewNode(
    2192             :             simplified()->MaybeGrowFastElements(flags), receiver, elements,
    2193         463 :             index, length, effect, control);
    2194             :       }
    2195             : 
    2196             :       // Perform the actual element access.
    2197             :       effect = graph()->NewNode(simplified()->StoreElement(element_access),
    2198        8572 :                                 elements, index, value, effect, control);
    2199             :     }
    2200             :   }
    2201             : 
    2202       26845 :   return ValueEffectControl(value, effect, control);
    2203             : }
    2204             : 
    2205             : JSNativeContextSpecialization::ValueEffectControl
    2206           1 : JSNativeContextSpecialization::InlineApiCall(
    2207             :     Node* receiver, Node* context, Node* target, Node* frame_state, Node* value,
    2208             :     Node* effect, Node* control, Handle<SharedFunctionInfo> shared_info,
    2209           2 :     Handle<FunctionTemplateInfo> function_template_info) {
    2210             :   Handle<CallHandlerInfo> call_handler_info = handle(
    2211             :       CallHandlerInfo::cast(function_template_info->call_code()), isolate());
    2212             :   Handle<Object> call_data_object(call_handler_info->data(), isolate());
    2213             : 
    2214             :   // Only setters have a value.
    2215           1 :   int const argc = value == nullptr ? 0 : 1;
    2216             :   // The stub always expects the receiver as the first param on the stack.
    2217             :   CallApiCallbackStub stub(
    2218             :       isolate(), argc,
    2219             :       true /* FunctionTemplateInfo doesn't have an associated context. */);
    2220             :   CallInterfaceDescriptor call_interface_descriptor =
    2221             :       stub.GetCallInterfaceDescriptor();
    2222             :   CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
    2223             :       isolate(), graph()->zone(), call_interface_descriptor,
    2224           1 :       call_interface_descriptor.GetStackParameterCount() + argc +
    2225             :           1 /* implicit receiver */,
    2226             :       CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
    2227           3 :       MachineType::AnyTagged(), 1);
    2228             : 
    2229           1 :   Node* data = jsgraph()->Constant(call_data_object);
    2230             :   ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
    2231             :   Node* function_reference =
    2232             :       graph()->NewNode(common()->ExternalConstant(ExternalReference(
    2233           3 :           &function, ExternalReference::DIRECT_API_CALL, isolate())));
    2234           2 :   Node* code = jsgraph()->HeapConstant(stub.GetCode());
    2235             : 
    2236             :   // Add CallApiCallbackStub's register argument as well.
    2237             :   Node* inputs[11] = {
    2238           1 :       code, target, data, receiver /* holder */, function_reference, receiver};
    2239           1 :   int index = 6 + argc;
    2240           1 :   inputs[index++] = context;
    2241           1 :   inputs[index++] = frame_state;
    2242           1 :   inputs[index++] = effect;
    2243           1 :   inputs[index++] = control;
    2244             :   // This needs to stay here because of the edge case described in
    2245             :   // http://crbug.com/675648.
    2246           1 :   if (value != nullptr) {
    2247           0 :     inputs[6] = value;
    2248             :   }
    2249             : 
    2250             :   Node* control0;
    2251             :   Node* effect0;
    2252             :   Node* value0 = effect0 = control0 =
    2253           2 :       graph()->NewNode(common()->Call(call_descriptor), index, inputs);
    2254           1 :   return ValueEffectControl(value0, effect0, control0);
    2255             : }
    2256             : 
    2257      112245 : Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver,
    2258             :                                                           Node** effect,
    2259             :                                                           Node* control) {
    2260      112245 :   switch (receiver->opcode()) {
    2261             :     case IrOpcode::kHeapConstant:
    2262             :     case IrOpcode::kJSCreate:
    2263             :     case IrOpcode::kJSCreateArguments:
    2264             :     case IrOpcode::kJSCreateArray:
    2265             :     case IrOpcode::kJSCreateClosure:
    2266             :     case IrOpcode::kJSCreateIterResultObject:
    2267             :     case IrOpcode::kJSCreateLiteralArray:
    2268             :     case IrOpcode::kJSCreateLiteralObject:
    2269             :     case IrOpcode::kJSCreateLiteralRegExp:
    2270             :     case IrOpcode::kJSConvertReceiver:
    2271             :     case IrOpcode::kJSToName:
    2272             :     case IrOpcode::kJSToString:
    2273             :     case IrOpcode::kJSToObject:
    2274             :     case IrOpcode::kJSTypeOf: {
    2275             :       return receiver;
    2276             :     }
    2277             :     default: {
    2278             :       return *effect = graph()->NewNode(simplified()->CheckHeapObject(),
    2279      120252 :                                         receiver, *effect, control);
    2280             :     }
    2281             :   }
    2282             : }
    2283             : 
    2284      111146 : Node* JSNativeContextSpecialization::BuildCheckMaps(
    2285             :     Node* receiver, Node* effect, Node* control,
    2286       51271 :     std::vector<Handle<Map>> const& receiver_maps) {
    2287             :   HeapObjectMatcher m(receiver);
    2288      111146 :   if (m.HasValue()) {
    2289             :     Handle<Map> receiver_map(m.Value()->map(), isolate());
    2290       55073 :     if (receiver_map->is_stable()) {
    2291      102542 :       for (Handle<Map> map : receiver_maps) {
    2292       51271 :         if (map.is_identical_to(receiver_map)) {
    2293       51271 :           dependencies()->AssumeMapStable(receiver_map);
    2294             :           return effect;
    2295             :         }
    2296             :       }
    2297             :     }
    2298             :   }
    2299             :   ZoneHandleSet<Map> maps;
    2300             :   CheckMapsFlags flags = CheckMapsFlag::kNone;
    2301      182833 :   for (Handle<Map> map : receiver_maps) {
    2302       63083 :     maps.insert(map, graph()->zone());
    2303       63083 :     if (map->is_migration_target()) {
    2304             :       flags |= CheckMapsFlag::kTryMigrateInstance;
    2305             :     }
    2306             :   }
    2307             :   return graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
    2308      119750 :                           effect, control);
    2309             : }
    2310             : 
    2311         257 : Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
    2312        1799 :     Handle<Map> map, Node* properties, Node* effect, Node* control) {
    2313             :   // TODO(bmeurer/jkummerow): Property deletions can undo map transitions
    2314             :   // while keeping the backing store around, meaning that even though the
    2315             :   // map might believe that objects have no unused property fields, there
    2316             :   // might actually be some. It would be nice to not create a new backing
    2317             :   // store in that case (i.e. when properties->length() >= new_length).
    2318             :   // However, introducing branches and Phi nodes here would make it more
    2319             :   // difficult for escape analysis to get rid of the backing stores used
    2320             :   // for intermediate states of chains of property additions. That makes
    2321             :   // it unclear what the best approach is here.
    2322             :   DCHECK_EQ(0, map->unused_property_fields());
    2323             :   // Compute the length of the old {properties} and the new properties.
    2324         514 :   int length = map->NextFreePropertyIndex() - map->GetInObjectProperties();
    2325         257 :   int new_length = length + JSObject::kFieldsAdded;
    2326             :   // Collect the field values from the {properties}.
    2327             :   ZoneVector<Node*> values(zone());
    2328         257 :   values.reserve(new_length);
    2329         278 :   for (int i = 0; i < length; ++i) {
    2330             :     Node* value = effect = graph()->NewNode(
    2331             :         simplified()->LoadField(AccessBuilder::ForFixedArraySlot(i)),
    2332          63 :         properties, effect, control);
    2333          21 :     values.push_back(value);
    2334             :   }
    2335             :   // Initialize the new fields to undefined.
    2336         771 :   for (int i = 0; i < JSObject::kFieldsAdded; ++i) {
    2337        1542 :     values.push_back(jsgraph()->UndefinedConstant());
    2338             :   }
    2339             :   // Allocate and initialize the new properties.
    2340             :   effect = graph()->NewNode(
    2341         257 :       common()->BeginRegion(RegionObservability::kNotObservable), effect);
    2342             :   Node* new_properties = effect = graph()->NewNode(
    2343             :       simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
    2344         514 :       jsgraph()->Constant(FixedArray::SizeFor(new_length)), effect, control);
    2345             :   effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
    2346             :                             new_properties, jsgraph()->FixedArrayMapConstant(),
    2347         771 :                             effect, control);
    2348             :   effect = graph()->NewNode(
    2349             :       simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
    2350         771 :       new_properties, jsgraph()->Constant(new_length), effect, control);
    2351        1049 :   for (int i = 0; i < new_length; ++i) {
    2352             :     effect = graph()->NewNode(
    2353             :         simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)),
    2354        3168 :         new_properties, values[i], effect, control);
    2355             :   }
    2356         514 :   return graph()->NewNode(common()->FinishRegion(), new_properties, effect);
    2357             : }
    2358             : 
    2359       20304 : void JSNativeContextSpecialization::AssumePrototypesStable(
    2360       20918 :     std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
    2361             :   // Determine actual holder and perform prototype chain checks.
    2362       61526 :   for (auto map : receiver_maps) {
    2363             :     // Perform the implicit ToObject for primitives here.
    2364             :     // Implemented according to ES6 section 7.3.2 GetV (V, P).
    2365             :     Handle<JSFunction> constructor;
    2366       20918 :     if (Map::GetConstructorFunction(map, native_context())
    2367       41836 :             .ToHandle(&constructor)) {
    2368        2589 :       map = handle(constructor->initial_map(), isolate());
    2369             :     }
    2370       20918 :     dependencies()->AssumePrototypeMapsStable(map, holder);
    2371             :   }
    2372       20304 : }
    2373             : 
    2374        3147 : bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
    2375        4763 :     std::vector<Handle<Map>> const& receiver_maps) {
    2376             :   // Check if the array prototype chain is intact.
    2377        3147 :   if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false;
    2378             : 
    2379             :   // Make sure both the initial Array and Object prototypes are stable.
    2380             :   Handle<JSObject> initial_array_prototype(
    2381             :       native_context()->initial_array_prototype(), isolate());
    2382             :   Handle<JSObject> initial_object_prototype(
    2383             :       native_context()->initial_object_prototype(), isolate());
    2384        6130 :   if (!initial_array_prototype->map()->is_stable() ||
    2385             :       !initial_object_prototype->map()->is_stable()) {
    2386             :     return false;
    2387             :   }
    2388             : 
    2389             :   // Check if all {receiver_maps} either have the initial Array.prototype
    2390             :   // or the initial Object.prototype as their prototype, as those are
    2391             :   // guarded by the array protector cell.
    2392        8593 :   for (Handle<Map> map : receiver_maps) {
    2393        4536 :     if (map->prototype() != *initial_array_prototype &&
    2394             :         map->prototype() != *initial_object_prototype) {
    2395             :       return false;
    2396             :     }
    2397             :   }
    2398             : 
    2399             :   // Install code dependencies on the prototype maps.
    2400        7250 :   for (Handle<Map> map : receiver_maps) {
    2401        2487 :     dependencies()->AssumePrototypeMapsStable(map, initial_object_prototype);
    2402             :   }
    2403             : 
    2404             :   // Install code dependency on the array protector cell.
    2405             :   dependencies()->AssumePropertyCell(factory()->array_protector());
    2406        2276 :   return true;
    2407             : }
    2408             : 
    2409             : JSNativeContextSpecialization::InferHasInPrototypeChainResult
    2410        1000 : JSNativeContextSpecialization::InferHasInPrototypeChain(
    2411             :     Node* receiver, Node* effect, Handle<JSReceiver> prototype) {
    2412             :   ZoneHandleSet<Map> receiver_maps;
    2413             :   NodeProperties::InferReceiverMapsResult result =
    2414        1000 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
    2415        1000 :   if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
    2416             : 
    2417             :   // Check if either all or none of the {receiver_maps} have the given
    2418             :   // {prototype} in their prototype chain.
    2419             :   bool all = true;
    2420             :   bool none = true;
    2421          36 :   for (size_t i = 0; i < receiver_maps.size(); ++i) {
    2422             :     Handle<Map> receiver_map = receiver_maps[i];
    2423          12 :     if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
    2424             :       return kMayBeInPrototypeChain;
    2425             :     }
    2426          12 :     if (result == NodeProperties::kUnreliableReceiverMaps) {
    2427             :       // In case of an unreliable {result} we need to ensure that all
    2428             :       // {receiver_maps} are stable, because otherwise we cannot trust
    2429             :       // the {receiver_maps} information, since arbitrary side-effects
    2430             :       // may have happened.
    2431           5 :       if (!receiver_map->is_stable()) {
    2432             :         return kMayBeInPrototypeChain;
    2433             :       }
    2434             :     }
    2435          15 :     for (PrototypeIterator j(receiver_map);; j.Advance()) {
    2436          15 :       if (j.IsAtEnd()) {
    2437             :         all = false;
    2438             :         break;
    2439             :       }
    2440             :       Handle<JSReceiver> const current =
    2441             :           PrototypeIterator::GetCurrent<JSReceiver>(j);
    2442          14 :       if (current.is_identical_to(prototype)) {
    2443             :         none = false;
    2444             :         break;
    2445             :       }
    2446           6 :       if (!current->map()->is_stable() ||
    2447           3 :           current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
    2448             :         return kMayBeInPrototypeChain;
    2449             :       }
    2450             :     }
    2451             :   }
    2452             :   DCHECK_IMPLIES(all, !none);
    2453             :   DCHECK_IMPLIES(none, !all);
    2454             : 
    2455          12 :   if (all) return kIsInPrototypeChain;
    2456           1 :   if (none) return kIsNotInPrototypeChain;
    2457           0 :   return kMayBeInPrototypeChain;
    2458             : }
    2459             : 
    2460      147460 : bool JSNativeContextSpecialization::ExtractReceiverMaps(
    2461             :     Node* receiver, Node* effect, FeedbackNexus const& nexus,
    2462        2240 :     MapHandleList* receiver_maps) {
    2463             :   DCHECK_EQ(0, receiver_maps->length());
    2464             :   // See if we can infer a concrete type for the {receiver}.
    2465      147460 :   if (InferReceiverMaps(receiver, effect, receiver_maps)) {
    2466             :     // We can assume that the {receiver} still has the infered {receiver_maps}.
    2467             :     return true;
    2468             :   }
    2469             :   // Try to extract some maps from the {nexus}.
    2470       75774 :   if (nexus.ExtractMaps(receiver_maps) != 0) {
    2471             :     // Try to filter impossible candidates based on infered root map.
    2472             :     Handle<Map> receiver_map;
    2473       89288 :     if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
    2474        6752 :       for (int i = receiver_maps->length(); --i >= 0;) {
    2475        4544 :         if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
    2476          32 :           receiver_maps->Remove(i);
    2477             :         }
    2478             :       }
    2479             :     }
    2480             :     return true;
    2481             :   }
    2482             :   return false;
    2483             : }
    2484             : 
    2485      147460 : bool JSNativeContextSpecialization::InferReceiverMaps(
    2486             :     Node* receiver, Node* effect, MapHandleList* receiver_maps) {
    2487             :   ZoneHandleSet<Map> maps;
    2488             :   NodeProperties::InferReceiverMapsResult result =
    2489      147460 :       NodeProperties::InferReceiverMaps(receiver, effect, &maps);
    2490      147460 :   if (result == NodeProperties::kReliableReceiverMaps) {
    2491       52321 :     for (size_t i = 0; i < maps.size(); ++i) {
    2492       17746 :       receiver_maps->Add(maps[i]);
    2493             :     }
    2494             :     return true;
    2495      130631 :   } else if (result == NodeProperties::kUnreliableReceiverMaps) {
    2496             :     // For untrusted receiver maps, we can still use the information
    2497             :     // if the maps are stable.
    2498      169824 :     for (size_t i = 0; i < maps.size(); ++i) {
    2499       59854 :       if (!maps[i]->is_stable()) return false;
    2500             :     }
    2501      164741 :     for (size_t i = 0; i < maps.size(); ++i) {
    2502       54942 :       receiver_maps->Add(maps[i]);
    2503             :     }
    2504             :     return true;
    2505             :   }
    2506             :   return false;
    2507             : }
    2508             : 
    2509       44644 : MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
    2510             :     Node* receiver) {
    2511             :   HeapObjectMatcher m(receiver);
    2512       44644 :   if (m.HasValue()) {
    2513        2025 :     return handle(m.Value()->map()->FindRootMap(), isolate());
    2514       42619 :   } else if (m.IsJSCreate()) {
    2515             :     HeapObjectMatcher mtarget(m.InputAt(0));
    2516             :     HeapObjectMatcher mnewtarget(m.InputAt(1));
    2517         215 :     if (mtarget.HasValue() && mnewtarget.HasValue()) {
    2518             :       Handle<JSFunction> constructor =
    2519             :           Handle<JSFunction>::cast(mtarget.Value());
    2520         215 :       if (constructor->has_initial_map()) {
    2521             :         Handle<Map> initial_map(constructor->initial_map(), isolate());
    2522         215 :         if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
    2523             :           DCHECK_EQ(*initial_map, initial_map->FindRootMap());
    2524             :           return initial_map;
    2525             :         }
    2526             :       }
    2527             :     }
    2528             :   }
    2529             :   return MaybeHandle<Map>();
    2530             : }
    2531             : 
    2532      560656 : bool JSNativeContextSpecialization::LookupInScriptContextTable(
    2533             :     Handle<Name> name, ScriptContextTableLookupResult* result) {
    2534      560656 :   if (!name->IsString()) return false;
    2535             :   Handle<ScriptContextTable> script_context_table(
    2536             :       global_object()->native_context()->script_context_table(), isolate());
    2537             :   ScriptContextTable::LookupResult lookup_result;
    2538      560656 :   if (!ScriptContextTable::Lookup(script_context_table,
    2539      560656 :                                   Handle<String>::cast(name), &lookup_result)) {
    2540             :     return false;
    2541             :   }
    2542             :   Handle<Context> script_context = ScriptContextTable::GetContext(
    2543        6598 :       script_context_table, lookup_result.context_index);
    2544        6598 :   result->context = script_context;
    2545        6598 :   result->immutable = lookup_result.mode == CONST;
    2546        6598 :   result->index = lookup_result.slot_index;
    2547        6598 :   return true;
    2548             : }
    2549             : 
    2550      649952 : Graph* JSNativeContextSpecialization::graph() const {
    2551      650970 :   return jsgraph()->graph();
    2552             : }
    2553             : 
    2554     1168249 : Isolate* JSNativeContextSpecialization::isolate() const {
    2555     1168250 :   return jsgraph()->isolate();
    2556             : }
    2557             : 
    2558           0 : Factory* JSNativeContextSpecialization::factory() const {
    2559           0 :   return isolate()->factory();
    2560             : }
    2561             : 
    2562           0 : MachineOperatorBuilder* JSNativeContextSpecialization::machine() const {
    2563           0 :   return jsgraph()->machine();
    2564             : }
    2565             : 
    2566       84112 : CommonOperatorBuilder* JSNativeContextSpecialization::common() const {
    2567       84112 :   return jsgraph()->common();
    2568             : }
    2569             : 
    2570       10903 : JSOperatorBuilder* JSNativeContextSpecialization::javascript() const {
    2571       10903 :   return jsgraph()->javascript();
    2572             : }
    2573             : 
    2574      368210 : SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
    2575      375949 :   return jsgraph()->simplified();
    2576             : }
    2577             : 
    2578             : }  // namespace compiler
    2579             : }  // namespace internal
    2580             : }  // namespace v8

Generated by: LCOV version 1.10