LCOV - code coverage report
Current view: top level - src/compiler - js-native-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 804 832 96.6 %
Date: 2017-10-20 Functions: 41 47 87.2 %

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

Generated by: LCOV version 1.10