LCOV - code coverage report
Current view: top level - src/compiler - js-native-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1169 1212 96.5 %
Date: 2019-03-21 Functions: 61 67 91.0 %

          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-inl.h"
       9             : #include "src/code-factory.h"
      10             : #include "src/compiler/access-builder.h"
      11             : #include "src/compiler/access-info.h"
      12             : #include "src/compiler/allocation-builder.h"
      13             : #include "src/compiler/compilation-dependencies.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/dtoa.h"
      21             : #include "src/feedback-vector.h"
      22             : #include "src/field-index-inl.h"
      23             : #include "src/isolate-inl.h"
      24             : #include "src/objects/heap-number.h"
      25             : #include "src/objects/js-array-buffer-inl.h"
      26             : #include "src/objects/js-array-inl.h"
      27             : #include "src/objects/templates.h"
      28             : #include "src/string-constants.h"
      29             : #include "src/vector-slot-pair.h"
      30             : 
      31             : namespace v8 {
      32             : namespace internal {
      33             : namespace compiler {
      34             : 
      35             : // This is needed for gc_mole which will compile this file without the full set
      36             : // of GN defined macros.
      37             : #ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
      38             : #define V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP 64
      39             : #endif
      40             : 
      41             : namespace {
      42             : 
      43      133507 : bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
      44      273220 :   for (auto map : maps) {
      45             :     MapRef map_ref(broker, map);
      46      139892 :     if (map_ref.IsHeapNumberMap()) return true;
      47             :   }
      48             :   return false;
      49             : }
      50             : 
      51       15781 : bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) {
      52       31004 :   for (auto map : maps) {
      53             :     MapRef map_ref(broker, map);
      54       16979 :     if (!map_ref.IsJSArrayMap()) return false;
      55             :   }
      56             :   return true;
      57             : }
      58             : 
      59             : }  // namespace
      60             : 
      61      463856 : JSNativeContextSpecialization::JSNativeContextSpecialization(
      62             :     Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker, Flags flags,
      63             :     Handle<Context> native_context, CompilationDependencies* dependencies,
      64             :     Zone* zone, Zone* shared_zone)
      65             :     : AdvancedReducer(editor),
      66             :       jsgraph_(jsgraph),
      67             :       broker_(broker),
      68             :       flags_(flags),
      69             :       global_object_(native_context->global_object(), jsgraph->isolate()),
      70             :       global_proxy_(native_context->global_proxy(), jsgraph->isolate()),
      71             :       dependencies_(dependencies),
      72             :       zone_(zone),
      73             :       shared_zone_(shared_zone),
      74     2319343 :       type_cache_(TypeCache::Get()) {}
      75             : 
      76    35260492 : Reduction JSNativeContextSpecialization::Reduce(Node* node) {
      77    35260492 :   switch (node->opcode()) {
      78             :     case IrOpcode::kJSAdd:
      79       92664 :       return ReduceJSAdd(node);
      80             :     case IrOpcode::kJSAsyncFunctionEnter:
      81        1250 :       return ReduceJSAsyncFunctionEnter(node);
      82             :     case IrOpcode::kJSAsyncFunctionReject:
      83        1204 :       return ReduceJSAsyncFunctionReject(node);
      84             :     case IrOpcode::kJSAsyncFunctionResolve:
      85        1112 :       return ReduceJSAsyncFunctionResolve(node);
      86             :     case IrOpcode::kJSGetSuperConstructor:
      87        2438 :       return ReduceJSGetSuperConstructor(node);
      88             :     case IrOpcode::kJSInstanceOf:
      89        3800 :       return ReduceJSInstanceOf(node);
      90             :     case IrOpcode::kJSHasInPrototypeChain:
      91         889 :       return ReduceJSHasInPrototypeChain(node);
      92             :     case IrOpcode::kJSOrdinaryHasInstance:
      93        1064 :       return ReduceJSOrdinaryHasInstance(node);
      94             :     case IrOpcode::kJSPromiseResolve:
      95         190 :       return ReduceJSPromiseResolve(node);
      96             :     case IrOpcode::kJSResolvePromise:
      97        1047 :       return ReduceJSResolvePromise(node);
      98             :     case IrOpcode::kJSLoadContext:
      99      545005 :       return ReduceJSLoadContext(node);
     100             :     case IrOpcode::kJSLoadGlobal:
     101     1000369 :       return ReduceJSLoadGlobal(node);
     102             :     case IrOpcode::kJSStoreGlobal:
     103      219047 :       return ReduceJSStoreGlobal(node);
     104             :     case IrOpcode::kJSLoadNamed:
     105      544244 :       return ReduceJSLoadNamed(node);
     106             :     case IrOpcode::kJSStoreNamed:
     107      106481 :       return ReduceJSStoreNamed(node);
     108             :     case IrOpcode::kJSHasProperty:
     109        1586 :       return ReduceJSHasProperty(node);
     110             :     case IrOpcode::kJSLoadProperty:
     111       45066 :       return ReduceJSLoadProperty(node);
     112             :     case IrOpcode::kJSStoreProperty:
     113       12435 :       return ReduceJSStoreProperty(node);
     114             :     case IrOpcode::kJSStoreNamedOwn:
     115       36034 :       return ReduceJSStoreNamedOwn(node);
     116             :     case IrOpcode::kJSStoreDataPropertyInLiteral:
     117         540 :       return ReduceJSStoreDataPropertyInLiteral(node);
     118             :     case IrOpcode::kJSStoreInArrayLiteral:
     119       49848 :       return ReduceJSStoreInArrayLiteral(node);
     120             :     case IrOpcode::kJSToObject:
     121        1999 :       return ReduceJSToObject(node);
     122             :     case IrOpcode::kJSToString:
     123        2790 :       return ReduceJSToString(node);
     124             :     default:
     125             :       break;
     126             :   }
     127             :   return NoChange();
     128             : }
     129             : 
     130             : // static
     131      185330 : base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength(
     132             :     JSHeapBroker* broker, Node* node) {
     133      185330 :   if (node->opcode() == IrOpcode::kDelayedStringConstant) {
     134        3776 :     return StringConstantBaseOf(node->op())->GetMaxStringConstantLength();
     135             :   }
     136             : 
     137             :   HeapObjectMatcher matcher(node);
     138      226340 :   if (matcher.HasValue() && matcher.Ref(broker).IsString()) {
     139       44358 :     StringRef input = matcher.Ref(broker).AsString();
     140       88716 :     return input.length();
     141             :   }
     142             : 
     143             :   NumberMatcher number_matcher(node);
     144      137196 :   if (number_matcher.HasValue()) {
     145       19919 :     return kBase10MaximalLength + 1;
     146             :   }
     147             : 
     148             :   // We don't support objects with possibly monkey-patched prototype.toString
     149             :   // as it might have side-effects, so we shouldn't attempt lowering them.
     150      117277 :   return base::nullopt;
     151             : }
     152             : 
     153        2790 : Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) {
     154             :   DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
     155             :   Node* const input = node->InputAt(0);
     156             :   Reduction reduction;
     157             : 
     158             :   HeapObjectMatcher matcher(input);
     159        3441 :   if (matcher.HasValue() && matcher.Ref(broker()).IsString()) {
     160             :     reduction = Changed(input);  // JSToString(x:string) => x
     161             :     ReplaceWithValue(node, reduction.replacement());
     162         646 :     return reduction;
     163             :   }
     164             : 
     165             :   // TODO(turbofan): This optimization is weaker than what we used to have
     166             :   // in js-typed-lowering for OrderedNumbers. We don't have types here though,
     167             :   // so alternative approach should be designed if this causes performance
     168             :   // regressions and the stronger optimization should be re-implemented.
     169             :   NumberMatcher number_matcher(input);
     170        2144 :   if (number_matcher.HasValue()) {
     171             :     const StringConstantBase* base =
     172             :         new (shared_zone()) NumberToStringConstant(number_matcher.Value());
     173             :     reduction =
     174           9 :         Replace(graph()->NewNode(common()->DelayedStringConstant(base)));
     175             :     ReplaceWithValue(node, reduction.replacement());
     176           9 :     return reduction;
     177             :   }
     178             : 
     179             :   return NoChange();
     180             : }
     181             : 
     182             : const StringConstantBase*
     183       10038 : JSNativeContextSpecialization::CreateDelayedStringConstant(Node* node) {
     184       10038 :   if (node->opcode() == IrOpcode::kDelayedStringConstant) {
     185        3115 :     return StringConstantBaseOf(node->op());
     186             :   } else {
     187             :     NumberMatcher number_matcher(node);
     188        6923 :     if (number_matcher.HasValue()) {
     189         260 :       return new (shared_zone()) NumberToStringConstant(number_matcher.Value());
     190             :     } else {
     191             :       HeapObjectMatcher matcher(node);
     192       13326 :       if (matcher.HasValue() && matcher.Ref(broker()).IsString()) {
     193        6663 :         StringRef s = matcher.Ref(broker()).AsString();
     194             :         return new (shared_zone())
     195       13326 :             StringLiteral(s.object(), static_cast<size_t>(s.length()));
     196             :       } else {
     197           0 :         UNREACHABLE();
     198             :       }
     199             :     }
     200             :   }
     201             : }
     202             : 
     203             : namespace {
     204        7732 : bool IsStringConstant(JSHeapBroker* broker, Node* node) {
     205        7732 :   if (node->opcode() == IrOpcode::kDelayedStringConstant) {
     206             :     return true;
     207             :   }
     208             : 
     209             :   HeapObjectMatcher matcher(node);
     210        6545 :   return matcher.HasValue() && matcher.Ref(broker).IsString();
     211             : }
     212             : }  // namespace
     213             : 
     214        1250 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionEnter(
     215             :     Node* node) {
     216             :   DCHECK_EQ(IrOpcode::kJSAsyncFunctionEnter, node->opcode());
     217        1250 :   Node* closure = NodeProperties::GetValueInput(node, 0);
     218        1250 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     219        1250 :   Node* context = NodeProperties::GetContextInput(node);
     220        1250 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     221        1250 :   Node* effect = NodeProperties::GetEffectInput(node);
     222        1250 :   Node* control = NodeProperties::GetControlInput(node);
     223             : 
     224        1250 :   if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
     225             : 
     226             :   // Create the promise for the async function.
     227             :   Node* promise = effect =
     228        1127 :       graph()->NewNode(javascript()->CreatePromise(), context, effect);
     229             : 
     230             :   // Create the JSAsyncFunctionObject based on the SharedFunctionInfo
     231             :   // extracted from the top-most frame in {frame_state}.
     232             :   Handle<SharedFunctionInfo> shared =
     233        1127 :       FrameStateInfoOf(frame_state->op()).shared_info().ToHandleChecked();
     234             :   DCHECK(shared->is_compiled());
     235        1127 :   int register_count = shared->internal_formal_parameter_count() +
     236        2254 :                        shared->GetBytecodeArray()->register_count();
     237             :   Node* value = effect =
     238        1127 :       graph()->NewNode(javascript()->CreateAsyncFunctionObject(register_count),
     239             :                        closure, receiver, promise, context, effect, control);
     240             :   ReplaceWithValue(node, value, effect, control);
     241             :   return Replace(value);
     242             : }
     243             : 
     244        1204 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionReject(
     245             :     Node* node) {
     246             :   DCHECK_EQ(IrOpcode::kJSAsyncFunctionReject, node->opcode());
     247        1204 :   Node* async_function_object = NodeProperties::GetValueInput(node, 0);
     248        1204 :   Node* reason = NodeProperties::GetValueInput(node, 1);
     249        1204 :   Node* context = NodeProperties::GetContextInput(node);
     250        1204 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     251        1204 :   Node* effect = NodeProperties::GetEffectInput(node);
     252        1204 :   Node* control = NodeProperties::GetControlInput(node);
     253             : 
     254        1204 :   if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
     255             : 
     256             :   // Load the promise from the {async_function_object}.
     257        1084 :   Node* promise = effect = graph()->NewNode(
     258        2168 :       simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()),
     259             :       async_function_object, effect, control);
     260             : 
     261             :   // Create a nested frame state inside the current method's most-recent
     262             :   // {frame_state} that will ensure that lazy deoptimizations at this
     263             :   // point will still return the {promise} instead of the result of the
     264             :   // JSRejectPromise operation (which yields undefined).
     265        1084 :   Node* parameters[] = {promise};
     266             :   frame_state = CreateStubBuiltinContinuationFrameState(
     267             :       jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context,
     268             :       parameters, arraysize(parameters), frame_state,
     269        1084 :       ContinuationFrameStateMode::LAZY);
     270             : 
     271             :   // Disable the additional debug event for the rejection since a
     272             :   // debug event already happend for the exception that got us here.
     273        1084 :   Node* debug_event = jsgraph()->FalseConstant();
     274        1084 :   effect = graph()->NewNode(javascript()->RejectPromise(), promise, reason,
     275             :                             debug_event, context, frame_state, effect, control);
     276             :   ReplaceWithValue(node, promise, effect, control);
     277             :   return Replace(promise);
     278             : }
     279             : 
     280        1112 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve(
     281             :     Node* node) {
     282             :   DCHECK_EQ(IrOpcode::kJSAsyncFunctionResolve, node->opcode());
     283        1112 :   Node* async_function_object = NodeProperties::GetValueInput(node, 0);
     284        1112 :   Node* value = NodeProperties::GetValueInput(node, 1);
     285        1112 :   Node* context = NodeProperties::GetContextInput(node);
     286        1112 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     287        1112 :   Node* effect = NodeProperties::GetEffectInput(node);
     288        1112 :   Node* control = NodeProperties::GetControlInput(node);
     289             : 
     290        1112 :   if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
     291             : 
     292             :   // Load the promise from the {async_function_object}.
     293        1001 :   Node* promise = effect = graph()->NewNode(
     294        2002 :       simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()),
     295             :       async_function_object, effect, control);
     296             : 
     297             :   // Create a nested frame state inside the current method's most-recent
     298             :   // {frame_state} that will ensure that lazy deoptimizations at this
     299             :   // point will still return the {promise} instead of the result of the
     300             :   // JSResolvePromise operation (which yields undefined).
     301        1001 :   Node* parameters[] = {promise};
     302             :   frame_state = CreateStubBuiltinContinuationFrameState(
     303             :       jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context,
     304             :       parameters, arraysize(parameters), frame_state,
     305        1001 :       ContinuationFrameStateMode::LAZY);
     306             : 
     307        1001 :   effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value,
     308             :                             context, frame_state, effect, control);
     309             :   ReplaceWithValue(node, promise, effect, control);
     310             :   return Replace(promise);
     311             : }
     312             : 
     313       92664 : Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
     314             :   // TODO(turbofan): This has to run together with the inlining and
     315             :   // native context specialization to be able to leverage the string
     316             :   // constant-folding for optimizing property access, but we should
     317             :   // nevertheless find a better home for this at some point.
     318             :   DCHECK_EQ(IrOpcode::kJSAdd, node->opcode());
     319             : 
     320             :   Node* const lhs = node->InputAt(0);
     321             :   Node* const rhs = node->InputAt(1);
     322             : 
     323       92664 :   base::Optional<size_t> lhs_len = GetMaxStringLength(broker(), lhs);
     324       92664 :   base::Optional<size_t> rhs_len = GetMaxStringLength(broker(), rhs);
     325       92664 :   if (!lhs_len || !rhs_len) {
     326             :     return NoChange();
     327             :   }
     328             : 
     329             :   // Fold into DelayedStringConstant if at least one of the parameters is a
     330             :   // string constant and the addition won't throw due to too long result.
     331       19077 :   if (*lhs_len + *rhs_len <= String::kMaxLength &&
     332        7732 :       (IsStringConstant(broker(), lhs) || IsStringConstant(broker(), rhs))) {
     333        5019 :     const StringConstantBase* left = CreateDelayedStringConstant(lhs);
     334        5019 :     const StringConstantBase* right = CreateDelayedStringConstant(rhs);
     335             :     const StringConstantBase* cons =
     336             :         new (shared_zone()) StringCons(left, right);
     337             : 
     338        5019 :     Node* reduced = graph()->NewNode(common()->DelayedStringConstant(cons));
     339             :     ReplaceWithValue(node, reduced);
     340             :     return Replace(reduced);
     341             :   }
     342             : 
     343             :   return NoChange();
     344             : }
     345             : 
     346        2438 : Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
     347             :     Node* node) {
     348             :   DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode());
     349        2438 :   Node* constructor = NodeProperties::GetValueInput(node, 0);
     350             : 
     351             :   // Check if the input is a known JSFunction.
     352             :   HeapObjectMatcher m(constructor);
     353        2438 :   if (!m.HasValue()) return NoChange();
     354        2413 :   JSFunctionRef function = m.Ref(broker()).AsJSFunction();
     355        2413 :   MapRef function_map = function.map();
     356             :   // TODO(neis): Remove SerializePrototype call once brokerization is complete.
     357        2413 :   function_map.SerializePrototype();
     358        2413 :   ObjectRef function_prototype = function_map.prototype();
     359             : 
     360             :   // We can constant-fold the super constructor access if the
     361             :   // {function}s map is stable, i.e. we can use a code dependency
     362             :   // to guard against [[Prototype]] changes of {function}.
     363        7239 :   if (function_map.is_stable() && function_prototype.IsHeapObject() &&
     364        7181 :       function_prototype.AsHeapObject().map().is_constructor()) {
     365        2362 :     dependencies()->DependOnStableMap(function_map);
     366        2362 :     Node* value = jsgraph()->Constant(function_prototype);
     367             :     ReplaceWithValue(node, value);
     368             :     return Replace(value);
     369             :   }
     370             : 
     371             :   return NoChange();
     372             : }
     373             : 
     374        3807 : Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
     375             :   DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
     376        3807 :   FeedbackParameter const& p = FeedbackParameterOf(node->op());
     377        3807 :   Node* object = NodeProperties::GetValueInput(node, 0);
     378        3807 :   Node* constructor = NodeProperties::GetValueInput(node, 1);
     379        3807 :   Node* context = NodeProperties::GetContextInput(node);
     380        3807 :   Node* effect = NodeProperties::GetEffectInput(node);
     381        3807 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     382        3807 :   Node* control = NodeProperties::GetControlInput(node);
     383             : 
     384             :   // Check if the right hand side is a known {receiver}, or
     385             :   // we have feedback from the InstanceOfIC.
     386             :   Handle<JSObject> receiver;
     387             :   HeapObjectMatcher m(constructor);
     388        4789 :   if (m.HasValue() && m.Value()->IsJSObject()) {
     389             :     receiver = Handle<JSObject>::cast(m.Value());
     390        2835 :   } else if (p.feedback().IsValid()) {
     391             :     FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
     392        5670 :     if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
     393             :   } else {
     394             :     return NoChange();
     395             :   }
     396             :   Handle<Map> receiver_map(receiver->map(), isolate());
     397             : 
     398             :   // Compute property access info for @@hasInstance on the constructor.
     399        1003 :   PropertyAccessInfo access_info;
     400             :   AccessInfoFactory access_info_factory(broker(), dependencies(),
     401        1003 :                                         graph()->zone());
     402        1003 :   if (!access_info_factory.ComputePropertyAccessInfo(
     403             :           receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad,
     404             :           &access_info)) {
     405             :     return NoChange();
     406             :   }
     407             :   DCHECK_EQ(access_info.receiver_maps().size(), 1);
     408             :   DCHECK_EQ(access_info.receiver_maps()[0].address(), receiver_map.address());
     409             : 
     410             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
     411             : 
     412         987 :   if (access_info.IsNotFound()) {
     413             :     // If there's no @@hasInstance handler, the OrdinaryHasInstance operation
     414             :     // takes over, but that requires the constructor to be callable.
     415          15 :     if (!receiver_map->is_callable()) return NoChange();
     416             : 
     417             :     // Determine actual holder and perform prototype chain checks.
     418             :     Handle<JSObject> holder;
     419          15 :     if (access_info.holder().ToHandle(&holder)) {
     420           0 :       dependencies()->DependOnStablePrototypeChains(
     421           0 :           access_info.receiver_maps(), JSObjectRef(broker(), holder));
     422             :     }
     423             : 
     424             :     // Monomorphic property access.
     425             :     constructor =
     426          15 :         access_builder.BuildCheckHeapObject(constructor, &effect, control);
     427             :     access_builder.BuildCheckMaps(constructor, &effect, control,
     428          15 :                                   access_info.receiver_maps());
     429             : 
     430             :     // Lower to OrdinaryHasInstance(C, O).
     431          15 :     NodeProperties::ReplaceValueInput(node, constructor, 0);
     432          15 :     NodeProperties::ReplaceValueInput(node, object, 1);
     433          15 :     NodeProperties::ReplaceEffectInput(node, effect);
     434          15 :     NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
     435          15 :     Reduction const reduction = ReduceJSOrdinaryHasInstance(node);
     436          15 :     return reduction.Changed() ? reduction : Changed(node);
     437             :   }
     438             : 
     439         972 :   if (access_info.IsDataConstant() || access_info.IsDataConstantField()) {
     440             :     // Determine actual holder.
     441             :     Handle<JSObject> holder;
     442             :     bool found_on_proto = access_info.holder().ToHandle(&holder);
     443         956 :     if (!found_on_proto) holder = receiver;
     444             : 
     445             :     Handle<Object> constant;
     446         956 :     if (access_info.IsDataConstant()) {
     447             :       DCHECK(!FLAG_track_constant_fields);
     448             :       constant = access_info.constant();
     449             :     } else {
     450             :       DCHECK(FLAG_track_constant_fields);
     451             :       DCHECK(access_info.IsDataConstantField());
     452         956 :       FieldIndex field_index = access_info.field_index();
     453             :       constant = JSObject::FastPropertyAt(holder, Representation::Tagged(),
     454         956 :                                           field_index);
     455         956 :       if (!constant->IsCallable()) {
     456           1 :         return NoChange();
     457             :       }
     458             : 
     459             :       // Install dependency on constness. Unfortunately, access_info does not
     460             :       // track descriptor index, so we have to search for it.
     461             :       MapRef holder_map(broker(), handle(holder->map(), isolate()));
     462             :       Handle<DescriptorArray> descriptors(
     463        1910 :           holder_map.object()->instance_descriptors(), isolate());
     464        1910 :       int descriptor_index = descriptors->Search(
     465        1910 :           *(factory()->has_instance_symbol()), *(holder_map.object()));
     466         955 :       CHECK_NE(descriptor_index, DescriptorArray::kNotFound);
     467         955 :       holder_map.SerializeOwnDescriptors();
     468         955 :       if (dependencies()->DependOnFieldConstness(
     469             :               holder_map, descriptor_index) != PropertyConstness::kConst) {
     470             :         return NoChange();
     471             :       }
     472             :     }
     473             : 
     474         955 :     if (found_on_proto) {
     475         924 :       dependencies()->DependOnStablePrototypeChains(
     476         924 :           access_info.receiver_maps(), JSObjectRef(broker(), holder));
     477             :     }
     478             : 
     479             :     DCHECK(constant->IsCallable());
     480             : 
     481             :     // Check that {constructor} is actually {receiver}.
     482             :     constructor =
     483         955 :         access_builder.BuildCheckValue(constructor, &effect, control, receiver);
     484             : 
     485             :     // Monomorphic property access.
     486             :     access_builder.BuildCheckMaps(constructor, &effect, control,
     487         955 :                                   access_info.receiver_maps());
     488             : 
     489             :     // Create a nested frame state inside the current method's most-recent frame
     490             :     // state that will ensure that deopts that happen after this point will not
     491             :     // fallback to the last Checkpoint--which would completely re-execute the
     492             :     // instanceof logic--but rather create an activation of a version of the
     493             :     // ToBoolean stub that finishes the remaining work of instanceof and returns
     494             :     // to the caller without duplicating side-effects upon a lazy deopt.
     495             :     Node* continuation_frame_state = CreateStubBuiltinContinuationFrameState(
     496             :         jsgraph(), Builtins::kToBooleanLazyDeoptContinuation, context, nullptr,
     497         955 :         0, frame_state, ContinuationFrameStateMode::LAZY);
     498             : 
     499             :     // Call the @@hasInstance handler.
     500         955 :     Node* target = jsgraph()->Constant(constant);
     501         955 :     node->InsertInput(graph()->zone(), 0, target);
     502         955 :     node->ReplaceInput(1, constructor);
     503         955 :     node->ReplaceInput(2, object);
     504         955 :     node->ReplaceInput(4, continuation_frame_state);
     505         955 :     node->ReplaceInput(5, effect);
     506        2865 :     NodeProperties::ChangeOp(
     507             :         node, javascript()->Call(3, CallFrequency(), VectorSlotPair(),
     508         955 :                                  ConvertReceiverMode::kNotNullOrUndefined));
     509             : 
     510             :     // Rewire the value uses of {node} to ToBoolean conversion of the result.
     511         955 :     Node* value = graph()->NewNode(simplified()->ToBoolean(), node);
     512       10317 :     for (Edge edge : node->use_edges()) {
     513        6601 :       if (NodeProperties::IsValueEdge(edge) && edge.from() != value) {
     514         965 :         edge.UpdateTo(value);
     515             :         Revisit(edge.from());
     516             :       }
     517             :     }
     518             :     return Changed(node);
     519             :   }
     520             : 
     521             :   return NoChange();
     522             : }
     523             : 
     524             : JSNativeContextSpecialization::InferHasInPrototypeChainResult
     525        1647 : JSNativeContextSpecialization::InferHasInPrototypeChain(
     526             :     Node* receiver, Node* effect, Handle<HeapObject> prototype) {
     527             :   ZoneHandleSet<Map> receiver_maps;
     528             :   NodeProperties::InferReceiverMapsResult result =
     529             :       NodeProperties::InferReceiverMaps(broker(), receiver, effect,
     530        1647 :                                         &receiver_maps);
     531        1647 :   if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
     532             : 
     533             :   // Check if either all or none of the {receiver_maps} have the given
     534             :   // {prototype} in their prototype chain.
     535             :   bool all = true;
     536             :   bool none = true;
     537         370 :   for (size_t i = 0; i < receiver_maps.size(); ++i) {
     538             :     Handle<Map> receiver_map = receiver_maps[i];
     539         298 :     if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
     540             :       return kMayBeInPrototypeChain;
     541             :     }
     542          44 :     if (result == NodeProperties::kUnreliableReceiverMaps) {
     543             :       // In case of an unreliable {result} we need to ensure that all
     544             :       // {receiver_maps} are stable, because otherwise we cannot trust
     545             :       // the {receiver_maps} information, since arbitrary side-effects
     546             :       // may have happened.
     547          23 :       if (!receiver_map->is_stable()) {
     548             :         return kMayBeInPrototypeChain;
     549             :       }
     550             :     }
     551          58 :     for (PrototypeIterator j(isolate(), receiver_map);; j.Advance()) {
     552          58 :       if (j.IsAtEnd()) {
     553             :         all = false;
     554             :         break;
     555             :       }
     556             :       Handle<HeapObject> const current =
     557             :           PrototypeIterator::GetCurrent<HeapObject>(j);
     558          51 :       if (current.is_identical_to(prototype)) {
     559             :         none = false;
     560             :         break;
     561             :       }
     562          36 :       if (!current->map()->is_stable() ||
     563             :           current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
     564             :         return kMayBeInPrototypeChain;
     565             :       }
     566             :     }
     567             :   }
     568             :   DCHECK_IMPLIES(all, !none);
     569             : 
     570          36 :   if (all) return kIsInPrototypeChain;
     571           7 :   if (none) return kIsNotInPrototypeChain;
     572           0 :   return kMayBeInPrototypeChain;
     573             : }
     574             : 
     575        1647 : Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
     576             :     Node* node) {
     577             :   DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
     578        1647 :   Node* value = NodeProperties::GetValueInput(node, 0);
     579        1647 :   Node* prototype = NodeProperties::GetValueInput(node, 1);
     580        1647 :   Node* effect = NodeProperties::GetEffectInput(node);
     581             : 
     582             :   // Check if we can constant-fold the prototype chain walk
     583             :   // for the given {value} and the {prototype}.
     584             :   HeapObjectMatcher m(prototype);
     585        1647 :   if (m.HasValue()) {
     586             :     InferHasInPrototypeChainResult result =
     587        1647 :         InferHasInPrototypeChain(value, effect, m.Value());
     588        1647 :     if (result != kMayBeInPrototypeChain) {
     589             :       Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
     590             :       ReplaceWithValue(node, value);
     591             :       return Replace(value);
     592             :     }
     593             :   }
     594             : 
     595             :   return NoChange();
     596             : }
     597             : 
     598        1079 : Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
     599             :     Node* node) {
     600             :   DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
     601        1079 :   Node* constructor = NodeProperties::GetValueInput(node, 0);
     602        1079 :   Node* object = NodeProperties::GetValueInput(node, 1);
     603             : 
     604             :   // Check if the {constructor} is known at compile time.
     605             :   HeapObjectMatcher m(constructor);
     606        1079 :   if (!m.HasValue()) return NoChange();
     607             : 
     608             :   // Check if the {constructor} is a JSBoundFunction.
     609        1065 :   if (m.Value()->IsJSBoundFunction()) {
     610             :     // OrdinaryHasInstance on bound functions turns into a recursive
     611             :     // invocation of the instanceof operator again.
     612             :     // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
     613             :     Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
     614             :     Handle<JSReceiver> bound_target_function(function->bound_target_function(),
     615             :                                              isolate());
     616           7 :     NodeProperties::ReplaceValueInput(node, object, 0);
     617          14 :     NodeProperties::ReplaceValueInput(
     618           7 :         node, jsgraph()->HeapConstant(bound_target_function), 1);
     619           7 :     NodeProperties::ChangeOp(node, javascript()->InstanceOf(VectorSlotPair()));
     620           7 :     Reduction const reduction = ReduceJSInstanceOf(node);
     621           7 :     return reduction.Changed() ? reduction : Changed(node);
     622             :   }
     623             : 
     624             :   // Optimize if we currently know the "prototype" property.
     625        1058 :   if (m.Value()->IsJSFunction()) {
     626        1044 :     JSFunctionRef function = m.Ref(broker()).AsJSFunction();
     627             :     // TODO(neis): This is a temporary hack needed because the copy reducer
     628             :     // runs only after this pass.
     629        1044 :     function.Serialize();
     630             :     // TODO(neis): Remove the has_prototype_slot condition once the broker is
     631             :     // always enabled.
     632        1932 :     if (!function.map().has_prototype_slot() || !function.has_prototype() ||
     633         888 :         function.PrototypeRequiresRuntimeLookup()) {
     634             :       return NoChange();
     635             :     }
     636         758 :     ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
     637         758 :     Node* prototype_constant = jsgraph()->Constant(prototype);
     638             : 
     639             :     // Lower the {node} to JSHasInPrototypeChain.
     640         758 :     NodeProperties::ReplaceValueInput(node, object, 0);
     641         758 :     NodeProperties::ReplaceValueInput(node, prototype_constant, 1);
     642         758 :     NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
     643         758 :     Reduction const reduction = ReduceJSHasInPrototypeChain(node);
     644         758 :     return reduction.Changed() ? reduction : Changed(node);
     645             :   }
     646             : 
     647             :   return NoChange();
     648             : }
     649             : 
     650             : // ES section #sec-promise-resolve
     651         190 : Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) {
     652             :   DCHECK_EQ(IrOpcode::kJSPromiseResolve, node->opcode());
     653         190 :   Node* constructor = NodeProperties::GetValueInput(node, 0);
     654         190 :   Node* value = NodeProperties::GetValueInput(node, 1);
     655         190 :   Node* context = NodeProperties::GetContextInput(node);
     656         190 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     657         190 :   Node* effect = NodeProperties::GetEffectInput(node);
     658         190 :   Node* control = NodeProperties::GetControlInput(node);
     659             : 
     660             :   // Check if the {constructor} is the %Promise% function.
     661             :   HeapObjectMatcher m(constructor);
     662         570 :   if (!m.HasValue() ||
     663         760 :       !m.Ref(broker()).equals(broker()->native_context().promise_function())) {
     664             :     return NoChange();
     665             :   }
     666             : 
     667             :   // Check if we know something about the {value}.
     668             :   ZoneHandleSet<Map> value_maps;
     669             :   NodeProperties::InferReceiverMapsResult result =
     670          94 :       NodeProperties::InferReceiverMaps(broker(), value, effect, &value_maps);
     671          94 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
     672             :   DCHECK_NE(0, value_maps.size());
     673             : 
     674             :   // Check that the {value} cannot be a JSPromise.
     675          84 :   for (Handle<Map> const value_map : value_maps) {
     676          42 :     if (value_map->IsJSPromiseMap()) return NoChange();
     677             :   }
     678             : 
     679          42 :   if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
     680             : 
     681             :   // Create a %Promise% instance and resolve it with {value}.
     682             :   Node* promise = effect =
     683          36 :       graph()->NewNode(javascript()->CreatePromise(), context, effect);
     684          36 :   effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value,
     685             :                             context, frame_state, effect, control);
     686             :   ReplaceWithValue(node, promise, effect, control);
     687             :   return Replace(promise);
     688             : }
     689             : 
     690             : // ES section #sec-promise-resolve-functions
     691        1047 : Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
     692             :   DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
     693        1047 :   Node* promise = NodeProperties::GetValueInput(node, 0);
     694        1047 :   Node* resolution = NodeProperties::GetValueInput(node, 1);
     695        1047 :   Node* context = NodeProperties::GetContextInput(node);
     696        1047 :   Node* effect = NodeProperties::GetEffectInput(node);
     697        1047 :   Node* control = NodeProperties::GetControlInput(node);
     698             : 
     699             :   // Check if we know something about the {resolution}.
     700             :   ZoneHandleSet<Map> resolution_maps;
     701             :   NodeProperties::InferReceiverMapsResult result =
     702             :       NodeProperties::InferReceiverMaps(broker(), resolution, effect,
     703        1047 :                                         &resolution_maps);
     704        1047 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
     705             :   DCHECK_NE(0, resolution_maps.size());
     706             : 
     707             :   // When the {resolution_maps} information is unreliable, we can
     708             :   // still optimize if all individual {resolution_maps} are stable.
     709         718 :   if (result == NodeProperties::kUnreliableReceiverMaps) {
     710        1420 :     for (Handle<Map> resolution_map : resolution_maps) {
     711         710 :       if (!resolution_map->is_stable()) return NoChange();
     712             :     }
     713             :   }
     714             : 
     715             :   // Compute property access info for "then" on {resolution}.
     716         718 :   PropertyAccessInfo access_info;
     717             :   AccessInfoFactory access_info_factory(broker(), dependencies(),
     718         718 :                                         graph()->zone());
     719        2154 :   if (!access_info_factory.ComputePropertyAccessInfo(
     720         718 :           MapHandles(resolution_maps.begin(), resolution_maps.end()),
     721             :           factory()->then_string(), AccessMode::kLoad, &access_info)) {
     722             :     return NoChange();
     723             :   }
     724             : 
     725             :   // We can further optimize the case where {resolution}
     726             :   // definitely doesn't have a "then" property.
     727          28 :   if (!access_info.IsNotFound()) return NoChange();
     728             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
     729             : 
     730             :   // Add proper dependencies on the {resolution}s [[Prototype]]s.
     731             :   Handle<JSObject> holder;
     732          28 :   if (access_info.holder().ToHandle(&holder)) {
     733          28 :     dependencies()->DependOnStablePrototypeChains(
     734          28 :         access_info.receiver_maps(), JSObjectRef(broker(), holder));
     735             :   }
     736             : 
     737             :   // Add stability dependencies on the {resolution_maps}.
     738          28 :   if (result == NodeProperties::kUnreliableReceiverMaps) {
     739          40 :     for (Handle<Map> resolution_map : resolution_maps) {
     740          20 :       dependencies()->DependOnStableMap(MapRef(broker(), resolution_map));
     741             :     }
     742             :   }
     743             : 
     744             :   // Simply fulfill the {promise} with the {resolution}.
     745             :   Node* value = effect =
     746          28 :       graph()->NewNode(javascript()->FulfillPromise(), promise, resolution,
     747             :                        context, effect, control);
     748             :   ReplaceWithValue(node, value, effect, control);
     749             :   return Replace(value);
     750             : }
     751             : 
     752      545005 : Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
     753             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     754      545005 :   ContextAccess const& access = ContextAccessOf(node->op());
     755             :   // Specialize JSLoadContext(NATIVE_CONTEXT_INDEX) to the known native
     756             :   // context (if any), so we can constant-fold those fields, which is
     757             :   // safe, since the NATIVE_CONTEXT_INDEX slot is always immutable.
     758      545005 :   if (access.index() == Context::NATIVE_CONTEXT_INDEX) {
     759         172 :     Node* value = jsgraph()->Constant(native_context());
     760             :     ReplaceWithValue(node, value);
     761             :     return Replace(value);
     762             :   }
     763             :   return NoChange();
     764             : }
     765             : 
     766             : namespace {
     767             : 
     768             : FieldAccess ForPropertyCellValue(MachineRepresentation representation,
     769             :                                  Type type, MaybeHandle<Map> map,
     770             :                                  Handle<Name> name) {
     771             :   WriteBarrierKind kind = kFullWriteBarrier;
     772       39501 :   if (representation == MachineRepresentation::kTaggedSigned) {
     773             :     kind = kNoWriteBarrier;
     774        9987 :   } else if (representation == MachineRepresentation::kTaggedPointer) {
     775             :     kind = kPointerWriteBarrier;
     776             :   }
     777       41688 :   MachineType r = MachineType::TypeForRepresentation(representation);
     778             :   FieldAccess access = {
     779             :       kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
     780             :   return access;
     781             : }
     782             : 
     783             : }  // namespace
     784             : 
     785         278 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
     786             :     Node* node, Node* receiver, Node* value, Handle<Name> name,
     787             :     AccessMode access_mode, Node* index) {
     788             :   // Lookup on the global object. We only deal with own data properties
     789             :   // of the global object here (represented as PropertyCell).
     790         278 :   LookupIterator it(isolate(), global_object(), name, LookupIterator::OWN);
     791         278 :   it.TryLookupCachedProperty();
     792         278 :   if (it.state() != LookupIterator::DATA) return NoChange();
     793         251 :   if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
     794         251 :   PropertyCellRef property_cell(broker(), it.GetPropertyCell());
     795         251 :   property_cell.Serialize();
     796             :   return ReduceGlobalAccess(node, receiver, value, name, access_mode, index,
     797         251 :                             property_cell);
     798             : }
     799             : 
     800      192987 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
     801             :     Node* node, Node* receiver, Node* value, Handle<Name> name,
     802             :     AccessMode access_mode, Node* index, PropertyCellRef const& property_cell) {
     803      192987 :   Node* effect = NodeProperties::GetEffectInput(node);
     804      192987 :   Node* control = NodeProperties::GetControlInput(node);
     805             : 
     806      192987 :   ObjectRef property_cell_value = property_cell.value();
     807      578961 :   if (property_cell_value.IsHeapObject() &&
     808      516019 :       property_cell_value.AsHeapObject().map().oddball_type() ==
     809             :           OddballType::kHole) {
     810             :     // The property cell is no longer valid.
     811             :     return NoChange();
     812             :   }
     813             : 
     814      192959 :   PropertyDetails property_details = property_cell.property_details();
     815             :   PropertyCellType property_cell_type = property_details.cell_type();
     816             :   DCHECK_EQ(kData, property_details.kind());
     817             : 
     818             :   // We have additional constraints for stores.
     819      192959 :   if (access_mode == AccessMode::kStore) {
     820       16272 :     if (property_details.IsReadOnly()) {
     821             :       // Don't even bother trying to lower stores to read-only data properties.
     822             :       return NoChange();
     823       16272 :     } else if (property_cell_type == PropertyCellType::kUndefined) {
     824             :       // There's no fast-path for dealing with undefined property cells.
     825             :       return NoChange();
     826       16272 :     } else if (property_cell_type == PropertyCellType::kConstantType) {
     827             :       // There's also no fast-path to store to a global cell which pretended
     828             :       // to be stable, but is no longer stable now.
     829       41706 :       if (property_cell_value.IsHeapObject() &&
     830       15380 :           !property_cell_value.AsHeapObject().map().is_stable()) {
     831             :         return NoChange();
     832             :       }
     833             :     }
     834      176687 :   } else if (access_mode == AccessMode::kHas) {
     835             :     // has checks cannot follow the fast-path used by loads when these
     836             :     // conditions hold.
     837          84 :     if ((property_details.IsConfigurable() || !property_details.IsReadOnly()) &&
     838          63 :         property_details.cell_type() != PropertyCellType::kConstant &&
     839             :         property_details.cell_type() != PropertyCellType::kUndefined)
     840             :       return NoChange();
     841             :   }
     842             : 
     843             :   // Ensure that {index} matches the specified {name} (if {index} is given).
     844      192945 :   if (index != nullptr) {
     845           8 :     effect = BuildCheckEqualsName(name, index, effect, control);
     846             :   }
     847             : 
     848             :   // Check if we have a {receiver} to validate. If so, we need to check that
     849             :   // the {receiver} is actually the JSGlobalProxy for the native context that
     850             :   // we are specializing to.
     851      192945 :   if (receiver != nullptr) {
     852         422 :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
     853             :                                    jsgraph()->HeapConstant(global_proxy()));
     854         422 :     effect = graph()->NewNode(
     855             :         simplified()->CheckIf(DeoptimizeReason::kReceiverNotAGlobalProxy),
     856             :         check, effect, control);
     857             :   }
     858             : 
     859      192945 :   if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
     860             :     // Load from non-configurable, read-only data property on the global
     861             :     // object can be constant-folded, even without deoptimization support.
     862      287060 :     if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
     863             :       value = access_mode == AccessMode::kHas
     864             :                   ? jsgraph()->TrueConstant()
     865        4091 :                   : jsgraph()->Constant(property_cell_value);
     866             :     } else {
     867             :       // Record a code dependency on the cell if we can benefit from the
     868             :       // additional feedback, or the global property is configurable (i.e.
     869             :       // can be deleted or reconfigured to an accessor property).
     870      172582 :       if (property_details.cell_type() != PropertyCellType::kMutable ||
     871             :           property_details.IsConfigurable()) {
     872      167936 :         dependencies()->DependOnGlobalProperty(property_cell);
     873             :       }
     874             : 
     875             :       // Load from constant/undefined global property can be constant-folded.
     876      172582 :       if (property_details.cell_type() == PropertyCellType::kConstant ||
     877             :           property_details.cell_type() == PropertyCellType::kUndefined) {
     878             :         value = access_mode == AccessMode::kHas
     879             :                     ? jsgraph()->TrueConstant()
     880      146983 :                     : jsgraph()->Constant(property_cell_value);
     881             :         DCHECK(!property_cell_value.IsHeapObject() ||
     882             :                property_cell_value.AsHeapObject().map().oddball_type() !=
     883             :                    OddballType::kHole);
     884             :       } else {
     885             :         DCHECK_NE(AccessMode::kHas, access_mode);
     886             : 
     887             :         // Load from constant type cell can benefit from type feedback.
     888             :         MaybeHandle<Map> map;
     889             :         Type property_cell_value_type = Type::NonInternal();
     890             :         MachineRepresentation representation = MachineRepresentation::kTagged;
     891       25599 :         if (property_details.cell_type() == PropertyCellType::kConstantType) {
     892             :           // Compute proper type based on the current value in the cell.
     893       18944 :           if (property_cell_value.IsSmi()) {
     894             :             property_cell_value_type = Type::SignedSmall();
     895             :             representation = MachineRepresentation::kTaggedSigned;
     896        2593 :           } else if (property_cell_value.IsHeapNumber()) {
     897             :             property_cell_value_type = Type::Number();
     898             :             representation = MachineRepresentation::kTaggedPointer;
     899             :           } else {
     900             :             MapRef property_cell_value_map =
     901        1421 :                 property_cell_value.AsHeapObject().map();
     902        1421 :             property_cell_value_type = Type::For(property_cell_value_map);
     903             :             representation = MachineRepresentation::kTaggedPointer;
     904             : 
     905             :             // We can only use the property cell value map for map check
     906             :             // elimination if it's stable, i.e. the HeapObject wasn't
     907             :             // mutated without the cell state being updated.
     908        1421 :             if (property_cell_value_map.is_stable()) {
     909        1417 :               dependencies()->DependOnStableMap(property_cell_value_map);
     910        1417 :               map = property_cell_value_map.object();
     911             :             }
     912             :           }
     913             :         }
     914       51198 :         value = effect = graph()->NewNode(
     915       25599 :             simplified()->LoadField(ForPropertyCellValue(
     916             :                 representation, property_cell_value_type, map, name)),
     917             :             jsgraph()->Constant(property_cell), effect, control);
     918             :       }
     919             :     }
     920             :   } else {
     921             :     DCHECK_EQ(AccessMode::kStore, access_mode);
     922             :     DCHECK(!property_details.IsReadOnly());
     923       16272 :     switch (property_details.cell_type()) {
     924             :       case PropertyCellType::kUndefined: {
     925           0 :         UNREACHABLE();
     926             :         break;
     927             :       }
     928             :       case PropertyCellType::kConstant: {
     929             :         // Record a code dependency on the cell, and just deoptimize if the new
     930             :         // value doesn't match the previous value stored inside the cell.
     931         183 :         dependencies()->DependOnGlobalProperty(property_cell);
     932             :         Node* check =
     933         183 :             graph()->NewNode(simplified()->ReferenceEqual(), value,
     934             :                              jsgraph()->Constant(property_cell_value));
     935         366 :         effect = graph()->NewNode(
     936             :             simplified()->CheckIf(DeoptimizeReason::kValueMismatch), check,
     937             :             effect, control);
     938         183 :         break;
     939             :       }
     940             :       case PropertyCellType::kConstantType: {
     941             :         // Record a code dependency on the cell, and just deoptimize if the new
     942             :         // values' type doesn't match the type of the previous value in the
     943             :         // cell.
     944       13902 :         dependencies()->DependOnGlobalProperty(property_cell);
     945             :         Type property_cell_value_type;
     946             :         MachineRepresentation representation = MachineRepresentation::kTagged;
     947       13902 :         if (property_cell_value.IsHeapObject()) {
     948             :           // We cannot do anything if the {property_cell_value}s map is no
     949             :           // longer stable.
     950             :           MapRef property_cell_value_map =
     951         739 :               property_cell_value.AsHeapObject().map();
     952         739 :           dependencies()->DependOnStableMap(property_cell_value_map);
     953             : 
     954             :           // Check that the {value} is a HeapObject.
     955         739 :           value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
     956             :                                             value, effect, control);
     957             : 
     958             :           // Check {value} map against the {property_cell} map.
     959        2217 :           effect = graph()->NewNode(
     960             :               simplified()->CheckMaps(
     961             :                   CheckMapsFlag::kNone,
     962             :                   ZoneHandleSet<Map>(property_cell_value_map.object())),
     963             :               value, effect, control);
     964             :           property_cell_value_type = Type::OtherInternal();
     965             :           representation = MachineRepresentation::kTaggedPointer;
     966             :         } else {
     967             :           // Check that the {value} is a Smi.
     968       26326 :           value = effect = graph()->NewNode(
     969             :               simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
     970             :           property_cell_value_type = Type::SignedSmall();
     971             :           representation = MachineRepresentation::kTaggedSigned;
     972             :         }
     973       41706 :         effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
     974             :                                       representation, property_cell_value_type,
     975             :                                       MaybeHandle<Map>(), name)),
     976             :                                   jsgraph()->Constant(property_cell), value,
     977             :                                   effect, control);
     978             :         break;
     979             :       }
     980             :       case PropertyCellType::kMutable: {
     981             :         // Record a code dependency on the cell, and just deoptimize if the
     982             :         // property ever becomes read-only.
     983        2187 :         dependencies()->DependOnGlobalProperty(property_cell);
     984        4374 :         effect = graph()->NewNode(
     985        2187 :             simplified()->StoreField(ForPropertyCellValue(
     986             :                 MachineRepresentation::kTagged, Type::NonInternal(),
     987             :                 MaybeHandle<Map>(), name)),
     988             :             jsgraph()->Constant(property_cell), value, effect, control);
     989        2187 :         break;
     990             :       }
     991             :     }
     992             :   }
     993             : 
     994             :   ReplaceWithValue(node, value, effect, control);
     995             :   return Replace(value);
     996             : }
     997             : 
     998     1000369 : Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
     999             :   DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
    1000             :   DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
    1001             : 
    1002     1000369 :   LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
    1003     1000370 :   if (!p.feedback().IsValid()) return NoChange();
    1004     1000370 :   FeedbackSource source(p.feedback());
    1005             : 
    1006             :   GlobalAccessFeedback const* processed;
    1007     1000371 :   if (FLAG_concurrent_inlining) {
    1008          16 :     processed = broker()->GetGlobalAccessFeedback(source);
    1009          16 :     TRACE_BROKER(broker(), "ReduceJSLoadGlobal: using preprocessed feedback "
    1010             :                                << "(slot " << p.feedback().slot()
    1011             :                                << " of feedback vector handle "
    1012             :                                << p.feedback().vector().address() << ").\n");
    1013             :   } else {
    1014     1000355 :     processed = broker()->ProcessFeedbackForGlobalAccess(source);
    1015             :   }
    1016             : 
    1017     1000370 :   if (processed == nullptr) return NoChange();
    1018             : 
    1019      176584 :   if (processed->IsScriptContextSlot()) {
    1020         105 :     Node* effect = NodeProperties::GetEffectInput(node);
    1021         105 :     Node* script_context = jsgraph()->Constant(processed->script_context());
    1022             :     Node* value = effect =
    1023         105 :         graph()->NewNode(javascript()->LoadContext(0, processed->slot_index(),
    1024         105 :                                                    processed->immutable()),
    1025             :                          script_context, effect);
    1026             :     ReplaceWithValue(node, value, effect);
    1027             :     return Replace(value);
    1028             :   }
    1029             : 
    1030      176479 :   CHECK(processed->IsPropertyCell());
    1031             :   return ReduceGlobalAccess(node, nullptr, nullptr, p.name(), AccessMode::kLoad,
    1032      352958 :                             nullptr, processed->property_cell());
    1033             : }
    1034             : 
    1035      219047 : Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
    1036             :   DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
    1037             :   DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
    1038             : 
    1039      219047 :   Node* value = NodeProperties::GetValueInput(node, 0);
    1040             : 
    1041      219047 :   StoreGlobalParameters const& p = StoreGlobalParametersOf(node->op());
    1042      219047 :   if (!p.feedback().IsValid()) return NoChange();
    1043      219047 :   FeedbackSource source(p.feedback());
    1044             : 
    1045             :   GlobalAccessFeedback const* processed;
    1046      219047 :   if (FLAG_concurrent_inlining) {
    1047          35 :     processed = broker()->GetGlobalAccessFeedback(source);
    1048          35 :     TRACE_BROKER(broker(), "ReduceJSStoreGlobal: using preprocessed feedback "
    1049             :                                << "(slot " << p.feedback().slot()
    1050             :                                << " of feedback vector handle "
    1051             :                                << p.feedback().vector().address() << ").\n");
    1052             :   } else {
    1053      219012 :     processed = broker()->ProcessFeedbackForGlobalAccess(source);
    1054             :   }
    1055             : 
    1056      219047 :   if (processed == nullptr) return NoChange();
    1057             : 
    1058       16266 :   if (processed->IsScriptContextSlot()) {
    1059           9 :     if (processed->immutable()) return NoChange();
    1060           9 :     Node* effect = NodeProperties::GetEffectInput(node);
    1061           9 :     Node* control = NodeProperties::GetControlInput(node);
    1062           9 :     Node* script_context = jsgraph()->Constant(processed->script_context());
    1063             :     effect =
    1064           9 :         graph()->NewNode(javascript()->StoreContext(0, processed->slot_index()),
    1065             :                          value, script_context, effect, control);
    1066             :     ReplaceWithValue(node, value, effect, control);
    1067             :     return Replace(value);
    1068             :   }
    1069             : 
    1070       16257 :   if (processed->IsPropertyCell()) {
    1071             :     return ReduceGlobalAccess(node, nullptr, value, p.name(),
    1072             :                               AccessMode::kStore, nullptr,
    1073       32514 :                               processed->property_cell());
    1074             :   }
    1075             : 
    1076           0 :   UNREACHABLE();
    1077             : }
    1078             : 
    1079      138609 : Reduction JSNativeContextSpecialization::ReduceNamedAccess(
    1080             :     Node* node, Node* value, MapHandles const& receiver_maps, Handle<Name> name,
    1081             :     AccessMode access_mode, Node* index) {
    1082             :   DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
    1083             :          node->opcode() == IrOpcode::kJSStoreNamed ||
    1084             :          node->opcode() == IrOpcode::kJSLoadProperty ||
    1085             :          node->opcode() == IrOpcode::kJSStoreProperty ||
    1086             :          node->opcode() == IrOpcode::kJSStoreNamedOwn ||
    1087             :          node->opcode() == IrOpcode::kJSHasProperty);
    1088      138609 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1089      138609 :   Node* context = NodeProperties::GetContextInput(node);
    1090      138609 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
    1091      138609 :   Node* effect = NodeProperties::GetEffectInput(node);
    1092      138609 :   Node* control = NodeProperties::GetControlInput(node);
    1093             : 
    1094             :   // Check if we have an access o.x or o.x=v where o is the current
    1095             :   // native contexts' global proxy, and turn that into a direct access
    1096             :   // to the current native contexts' global object instead.
    1097      138609 :   if (receiver_maps.size() == 1) {
    1098      123609 :     Handle<Map> receiver_map = receiver_maps.front();
    1099      123609 :     if (receiver_map->IsJSGlobalProxyMap()) {
    1100         251 :       Object maybe_constructor = receiver_map->GetConstructor();
    1101             :       // Detached global proxies have |null| as their constructor.
    1102         753 :       if (maybe_constructor->IsJSFunction() &&
    1103         502 :           JSFunction::cast(maybe_constructor)->native_context() ==
    1104         753 :               *native_context().object()) {
    1105             :         return ReduceGlobalAccess(node, receiver, value, name, access_mode,
    1106         251 :                                   index);
    1107             :       }
    1108             :     }
    1109             :   }
    1110             : 
    1111             :   // Compute property access infos for the receiver maps.
    1112             :   AccessInfoFactory access_info_factory(broker(), dependencies(),
    1113      138358 :                                         graph()->zone());
    1114             :   ZoneVector<PropertyAccessInfo> access_infos(zone());
    1115      138358 :   if (!access_info_factory.ComputePropertyAccessInfos(
    1116             :           receiver_maps, name, access_mode, &access_infos)) {
    1117             :     return NoChange();
    1118             :   }
    1119             : 
    1120             :   // Nothing to do if we have no non-deprecated maps.
    1121      124455 :   if (access_infos.empty()) {
    1122             :     return ReduceSoftDeoptimize(
    1123           0 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
    1124             :   }
    1125             : 
    1126             :   // Ensure that {index} matches the specified {name} (if {index} is given).
    1127      124455 :   if (index != nullptr) {
    1128         147 :     effect = BuildCheckEqualsName(name, index, effect, control);
    1129             :   }
    1130             : 
    1131             :   // Collect call nodes to rewire exception edges.
    1132             :   ZoneVector<Node*> if_exception_nodes(zone());
    1133             :   ZoneVector<Node*>* if_exceptions = nullptr;
    1134      124455 :   Node* if_exception = nullptr;
    1135      124455 :   if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
    1136             :     if_exceptions = &if_exception_nodes;
    1137             :   }
    1138             : 
    1139             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
    1140             : 
    1141             :   // Check for the monomorphic cases.
    1142      124455 :   if (access_infos.size() == 1) {
    1143      118915 :     PropertyAccessInfo access_info = access_infos.front();
    1144             :     // Try to build string check or number check if possible.
    1145             :     // Otherwise build a map check.
    1146      237830 :     if (!access_builder.TryBuildStringCheck(broker(),
    1147             :                                             access_info.receiver_maps(),
    1148      230637 :                                             &receiver, &effect, control) &&
    1149      111722 :         !access_builder.TryBuildNumberCheck(broker(),
    1150             :                                             access_info.receiver_maps(),
    1151             :                                             &receiver, &effect, control)) {
    1152      110432 :       if (HasNumberMaps(broker(), access_info.receiver_maps())) {
    1153             :         // We need to also let Smi {receiver}s through in this case, so
    1154             :         // we construct a diamond, guarded by the Sminess of the {receiver}
    1155             :         // and if {receiver} is not a Smi just emit a sequence of map checks.
    1156           7 :         Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
    1157           7 :         Node* branch = graph()->NewNode(common()->Branch(), check, control);
    1158             : 
    1159           7 :         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    1160           7 :         Node* etrue = effect;
    1161             : 
    1162           7 :         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    1163           7 :         Node* efalse = effect;
    1164             :         {
    1165             :           access_builder.BuildCheckMaps(receiver, &efalse, if_false,
    1166           7 :                                         access_info.receiver_maps());
    1167             :         }
    1168             : 
    1169          14 :         control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    1170             :         effect =
    1171          14 :             graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    1172             :       } else {
    1173             :         receiver =
    1174      110425 :             access_builder.BuildCheckHeapObject(receiver, &effect, control);
    1175             :         access_builder.BuildCheckMaps(receiver, &effect, control,
    1176      110425 :                                       access_info.receiver_maps());
    1177             :       }
    1178             :     }
    1179             : 
    1180             :     // Generate the actual property access.
    1181             :     ValueEffectControl continuation = BuildPropertyAccess(
    1182             :         receiver, value, context, frame_state, effect, control, name,
    1183      118915 :         if_exceptions, access_info, access_mode);
    1184             :     value = continuation.value();
    1185      118915 :     effect = continuation.effect();
    1186      118915 :     control = continuation.control();
    1187             :   } else {
    1188             :     // The final states for every polymorphic branch. We join them with
    1189             :     // Merge+Phi+EffectPhi at the bottom.
    1190             :     ZoneVector<Node*> values(zone());
    1191             :     ZoneVector<Node*> effects(zone());
    1192             :     ZoneVector<Node*> controls(zone());
    1193             : 
    1194             :     // Check if {receiver} may be a number.
    1195             :     bool receiverissmi_possible = false;
    1196       16940 :     for (PropertyAccessInfo const& access_info : access_infos) {
    1197       11486 :       if (HasNumberMaps(broker(), access_info.receiver_maps())) {
    1198             :         receiverissmi_possible = true;
    1199             :         break;
    1200             :       }
    1201             :     }
    1202             : 
    1203             :     // Ensure that {receiver} is a heap object.
    1204             :     Node* receiverissmi_control = nullptr;
    1205        5540 :     Node* receiverissmi_effect = effect;
    1206        5540 :     if (receiverissmi_possible) {
    1207          86 :       Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
    1208          86 :       Node* branch = graph()->NewNode(common()->Branch(), check, control);
    1209         172 :       control = graph()->NewNode(common()->IfFalse(), branch);
    1210          86 :       receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
    1211          86 :       receiverissmi_effect = effect;
    1212             :     } else {
    1213             :       receiver =
    1214        5454 :           access_builder.BuildCheckHeapObject(receiver, &effect, control);
    1215             :     }
    1216             : 
    1217             :     // Generate code for the various different property access patterns.
    1218        5540 :     Node* fallthrough_control = control;
    1219       28718 :     for (size_t j = 0; j < access_infos.size(); ++j) {
    1220             :       PropertyAccessInfo const& access_info = access_infos[j];
    1221             :       Node* this_value = value;
    1222       11589 :       Node* this_receiver = receiver;
    1223       11589 :       Node* this_effect = effect;
    1224             :       Node* this_control = fallthrough_control;
    1225             : 
    1226             :       // Perform map check on {receiver}.
    1227             :       MapHandles const& receiver_maps = access_info.receiver_maps();
    1228             :       {
    1229             :         // Whether to insert a dedicated MapGuard node into the
    1230             :         // effect to be able to learn from the control flow.
    1231             :         bool insert_map_guard = true;
    1232             : 
    1233             :         // Check maps for the {receiver}s.
    1234       11589 :         if (j == access_infos.size() - 1) {
    1235             :           // Last map check on the fallthrough control path, do a
    1236             :           // conditional eager deoptimization exit here.
    1237             :           access_builder.BuildCheckMaps(receiver, &this_effect, this_control,
    1238        5540 :                                         receiver_maps);
    1239             :           fallthrough_control = nullptr;
    1240             : 
    1241             :           // Don't insert a MapGuard in this case, as the CheckMaps
    1242             :           // node already gives you all the information you need
    1243             :           // along the effect chain.
    1244             :           insert_map_guard = false;
    1245             :         } else {
    1246             :           // Explicitly branch on the {receiver_maps}.
    1247             :           ZoneHandleSet<Map> maps;
    1248       12228 :           for (Handle<Map> map : receiver_maps) {
    1249        6179 :             maps.insert(map, graph()->zone());
    1250             :           }
    1251             :           Node* check = this_effect =
    1252        6049 :               graph()->NewNode(simplified()->CompareMaps(maps), receiver,
    1253        6049 :                                this_effect, this_control);
    1254             :           Node* branch =
    1255        6049 :               graph()->NewNode(common()->Branch(), check, this_control);
    1256        6049 :           fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
    1257        6049 :           this_control = graph()->NewNode(common()->IfTrue(), branch);
    1258             :         }
    1259             : 
    1260             :         // The Number case requires special treatment to also deal with Smis.
    1261       11589 :         if (HasNumberMaps(broker(), receiver_maps)) {
    1262             :           // Join this check with the "receiver is smi" check above.
    1263             :           DCHECK_NOT_NULL(receiverissmi_effect);
    1264             :           DCHECK_NOT_NULL(receiverissmi_control);
    1265          86 :           this_control = graph()->NewNode(common()->Merge(2), this_control,
    1266             :                                           receiverissmi_control);
    1267          86 :           this_effect = graph()->NewNode(common()->EffectPhi(2), this_effect,
    1268          86 :                                          receiverissmi_effect, this_control);
    1269             :           receiverissmi_effect = receiverissmi_control = nullptr;
    1270             : 
    1271             :           // The {receiver} can also be a Smi in this case, so
    1272             :           // a MapGuard doesn't make sense for this at all.
    1273             :           insert_map_guard = false;
    1274             :         }
    1275             : 
    1276             :         // Introduce a MapGuard to learn from this on the effect chain.
    1277       11589 :         if (insert_map_guard) {
    1278             :           ZoneHandleSet<Map> maps;
    1279       12086 :           for (auto receiver_map : receiver_maps) {
    1280        6108 :             maps.insert(receiver_map, graph()->zone());
    1281             :           }
    1282        5978 :           this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
    1283        5978 :                                          this_effect, this_control);
    1284             :         }
    1285             : 
    1286             :         // If all {receiver_maps} are Strings we also need to rename the
    1287             :         // {receiver} here to make sure that TurboFan knows that along this
    1288             :         // path the {this_receiver} is a String. This is because we want
    1289             :         // strict checking of types, for example for StringLength operators.
    1290       11589 :         if (HasOnlyStringMaps(broker(), receiver_maps)) {
    1291             :           this_receiver = this_effect =
    1292         100 :               graph()->NewNode(common()->TypeGuard(Type::String()), receiver,
    1293         100 :                                this_effect, this_control);
    1294             :         }
    1295             :       }
    1296             : 
    1297             :       // Generate the actual property access.
    1298             :       ValueEffectControl continuation = BuildPropertyAccess(
    1299             :           this_receiver, this_value, context, frame_state, this_effect,
    1300       11589 :           this_control, name, if_exceptions, access_info, access_mode);
    1301       23178 :       values.push_back(continuation.value());
    1302       23178 :       effects.push_back(continuation.effect());
    1303       23178 :       controls.push_back(continuation.control());
    1304             :     }
    1305             : 
    1306             :     DCHECK_NULL(fallthrough_control);
    1307             : 
    1308             :     // Generate the final merge point for all (polymorphic) branches.
    1309        5540 :     int const control_count = static_cast<int>(controls.size());
    1310        5540 :     if (control_count == 0) {
    1311           0 :       value = effect = control = jsgraph()->Dead();
    1312        5540 :     } else if (control_count == 1) {
    1313           0 :       value = values.front();
    1314           0 :       effect = effects.front();
    1315           0 :       control = controls.front();
    1316             :     } else {
    1317        5540 :       control = graph()->NewNode(common()->Merge(control_count), control_count,
    1318        5540 :                                  &controls.front());
    1319        5540 :       values.push_back(control);
    1320        5540 :       value = graph()->NewNode(
    1321             :           common()->Phi(MachineRepresentation::kTagged, control_count),
    1322        5540 :           control_count + 1, &values.front());
    1323        5540 :       effects.push_back(control);
    1324        5540 :       effect = graph()->NewNode(common()->EffectPhi(control_count),
    1325        5540 :                                 control_count + 1, &effects.front());
    1326             :     }
    1327             :   }
    1328             : 
    1329             :   // Properly rewire IfException edges if {node} is inside a try-block.
    1330      124455 :   if (!if_exception_nodes.empty()) {
    1331             :     DCHECK_NOT_NULL(if_exception);
    1332             :     DCHECK_EQ(if_exceptions, &if_exception_nodes);
    1333         261 :     int const if_exception_count = static_cast<int>(if_exceptions->size());
    1334         261 :     Node* merge = graph()->NewNode(common()->Merge(if_exception_count),
    1335         261 :                                    if_exception_count, &if_exceptions->front());
    1336         261 :     if_exceptions->push_back(merge);
    1337             :     Node* ephi =
    1338         261 :         graph()->NewNode(common()->EffectPhi(if_exception_count),
    1339         261 :                          if_exception_count + 1, &if_exceptions->front());
    1340         261 :     Node* phi = graph()->NewNode(
    1341             :         common()->Phi(MachineRepresentation::kTagged, if_exception_count),
    1342         261 :         if_exception_count + 1, &if_exceptions->front());
    1343         261 :     ReplaceWithValue(if_exception, phi, ephi, merge);
    1344             :   }
    1345             : 
    1346      124455 :   ReplaceWithValue(node, value, effect, control);
    1347             :   return Replace(value);
    1348             : }
    1349             : 
    1350      483986 : Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
    1351             :     Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
    1352             :     AccessMode access_mode) {
    1353             :   DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
    1354             :          node->opcode() == IrOpcode::kJSStoreNamed ||
    1355             :          node->opcode() == IrOpcode::kJSStoreNamedOwn);
    1356      483986 :   Node* const receiver = NodeProperties::GetValueInput(node, 0);
    1357      483986 :   Node* const effect = NodeProperties::GetEffectInput(node);
    1358             : 
    1359             :   // Check if we are accessing the current native contexts' global proxy.
    1360             :   HeapObjectMatcher m(receiver);
    1361      547595 :   if (m.HasValue() && m.Value().is_identical_to(global_proxy())) {
    1362             :     // Optimize accesses to the current native contexts' global proxy.
    1363          27 :     return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
    1364             :   }
    1365             : 
    1366             :   // Extract receiver maps from the IC using the {nexus}.
    1367             :   MapHandles receiver_maps;
    1368      483960 :   if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
    1369             :     return NoChange();
    1370      477156 :   } else if (receiver_maps.empty()) {
    1371             :     return ReduceSoftDeoptimize(
    1372      339606 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
    1373             :   }
    1374             :   DCHECK(!nexus.IsUninitialized());
    1375             : 
    1376             :   // Try to lower the named access based on the {receiver_maps}.
    1377      137550 :   return ReduceNamedAccess(node, value, receiver_maps, name, access_mode);
    1378             : }
    1379             : 
    1380      544244 : Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
    1381             :   DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
    1382      544244 :   NamedAccess const& p = NamedAccessOf(node->op());
    1383      544245 :   Node* const receiver = NodeProperties::GetValueInput(node, 0);
    1384             : 
    1385             :   // Check if we have a constant receiver.
    1386             :   HeapObjectMatcher m(receiver);
    1387      544245 :   if (m.HasValue()) {
    1388       65799 :     ObjectRef object = m.Ref(broker());
    1389             :     NameRef name(broker(), p.name());
    1390      136918 :     if (object.IsJSFunction() &&
    1391       71119 :         name.equals(ObjectRef(broker(), factory()->prototype_string()))) {
    1392             :       // Optimize "prototype" property of functions.
    1393         570 :       JSFunctionRef function = object.AsJSFunction();
    1394             :       // TODO(neis): This is a temporary hack needed because the copy reducer
    1395             :       // runs only after this pass.
    1396         570 :       function.Serialize();
    1397             :       // TODO(neis): Remove the has_prototype_slot condition once the broker is
    1398             :       // always enabled.
    1399        1138 :       if (!function.map().has_prototype_slot() || !function.has_prototype() ||
    1400         568 :           function.PrototypeRequiresRuntimeLookup()) {
    1401             :         return NoChange();
    1402             :       }
    1403         561 :       ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
    1404         561 :       Node* value = jsgraph()->Constant(prototype);
    1405             :       ReplaceWithValue(node, value);
    1406             :       return Replace(value);
    1407      134044 :     } else if (object.IsString() &&
    1408       68815 :                name.equals(ObjectRef(broker(), factory()->length_string()))) {
    1409             :       // Constant-fold "length" property on constant strings.
    1410         276 :       Node* value = jsgraph()->Constant(object.AsString().length());
    1411             :       ReplaceWithValue(node, value);
    1412             :       return Replace(value);
    1413             :     }
    1414             :   }
    1415             : 
    1416             :   // Extract receiver maps from the load IC using the FeedbackNexus.
    1417      543399 :   if (!p.feedback().IsValid()) return NoChange();
    1418             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    1419             : 
    1420             :   // Try to lower the named access based on the {receiver_maps}.
    1421             :   return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, p.name(),
    1422      360670 :                                     AccessMode::kLoad);
    1423             : }
    1424             : 
    1425      106481 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
    1426             :   DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
    1427      106481 :   NamedAccess const& p = NamedAccessOf(node->op());
    1428      106481 :   Node* const value = NodeProperties::GetValueInput(node, 1);
    1429             : 
    1430             :   // Extract receiver maps from the store IC using the FeedbackNexus.
    1431      106481 :   if (!p.feedback().IsValid()) return NoChange();
    1432             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    1433             : 
    1434             :   // Try to lower the named access based on the {receiver_maps}.
    1435             :   return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
    1436       87282 :                                     AccessMode::kStore);
    1437             : }
    1438             : 
    1439       36033 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
    1440             :   DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
    1441       36033 :   StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
    1442       36033 :   Node* const value = NodeProperties::GetValueInput(node, 1);
    1443             : 
    1444             :   // Extract receiver maps from the IC using the FeedbackNexus.
    1445       36034 :   if (!p.feedback().IsValid()) return NoChange();
    1446             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    1447             : 
    1448             :   // Try to lower the creation of a named property based on the {receiver_maps}.
    1449             :   return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
    1450       36034 :                                     AccessMode::kStoreInLiteral);
    1451             : }
    1452             : 
    1453         377 : Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
    1454             :     Node* node, Node* index, Node* value, AccessMode access_mode,
    1455             :     KeyedAccessLoadMode load_mode) {
    1456         377 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1457         377 :   Node* effect = NodeProperties::GetEffectInput(node);
    1458         377 :   Node* control = NodeProperties::GetControlInput(node);
    1459             : 
    1460             :   // Strings are immutable in JavaScript.
    1461         377 :   if (access_mode == AccessMode::kStore) return NoChange();
    1462             : 
    1463             :   // `in` cannot be used on strings.
    1464         377 :   if (access_mode == AccessMode::kHas) return NoChange();
    1465             : 
    1466             :   // Ensure that the {receiver} is actually a String.
    1467         726 :   receiver = effect = graph()->NewNode(
    1468         363 :       simplified()->CheckString(VectorSlotPair()), receiver, effect, control);
    1469             : 
    1470             :   // Determine the {receiver} length.
    1471         363 :   Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
    1472             : 
    1473             :   // Load the single character string from {receiver} or yield undefined
    1474             :   // if the {index} is out of bounds (depending on the {load_mode}).
    1475             :   value = BuildIndexedStringLoad(receiver, index, length, &effect, &control,
    1476         363 :                                  load_mode);
    1477             : 
    1478         363 :   ReplaceWithValue(node, value, effect, control);
    1479             :   return Replace(value);
    1480             : }
    1481             : 
    1482             : namespace {
    1483       13808 : base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
    1484             :                                                       Node* receiver) {
    1485             :   HeapObjectMatcher m(receiver);
    1486       13808 :   if (!m.HasValue()) return base::nullopt;
    1487        4172 :   ObjectRef object = m.Ref(broker);
    1488        4172 :   if (!object.IsJSTypedArray()) return base::nullopt;
    1489        4172 :   JSTypedArrayRef typed_array = object.AsJSTypedArray();
    1490        4172 :   if (typed_array.is_on_heap()) return base::nullopt;
    1491             :   return typed_array;
    1492             : }
    1493             : }  // namespace
    1494             : 
    1495       23524 : Reduction JSNativeContextSpecialization::ReduceElementAccess(
    1496             :     Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
    1497             :     MapHandles const& receiver_maps, AccessMode access_mode,
    1498             :     KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
    1499             :   DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
    1500             : 
    1501             :   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
    1502             :          node->opcode() == IrOpcode::kJSStoreProperty ||
    1503             :          node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
    1504             :          node->opcode() == IrOpcode::kJSHasProperty);
    1505       23524 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1506       23524 :   Node* effect = NodeProperties::GetEffectInput(node);
    1507       23524 :   Node* control = NodeProperties::GetControlInput(node);
    1508       23524 :   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    1509             : 
    1510       23524 :   if (HasOnlyStringMaps(broker(), receiver_maps)) {
    1511             :     return ReduceElementAccessOnString(node, index, value, access_mode,
    1512         377 :                                        load_mode);
    1513             :   }
    1514             : 
    1515             :   // Compute element access infos for the receiver maps.
    1516             :   AccessInfoFactory access_info_factory(broker(), dependencies(),
    1517       23147 :                                         graph()->zone());
    1518             :   ZoneVector<ElementAccessInfo> access_infos(zone());
    1519       23147 :   if (!access_info_factory.ComputeElementAccessInfos(
    1520             :           nexus, receiver_maps, access_mode, &access_infos)) {
    1521             :     return NoChange();
    1522             :   }
    1523             : 
    1524             :   // Nothing to do if we have no non-deprecated maps.
    1525       22079 :   if (access_infos.empty()) {
    1526             :     return ReduceSoftDeoptimize(
    1527           0 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    1528             :   }
    1529             : 
    1530             :   // For holey stores or growing stores, we need to check that the prototype
    1531             :   // chain contains no setters for elements, and we need to guard those checks
    1532             :   // via code dependencies on the relevant prototype maps.
    1533       22079 :   if (access_mode == AccessMode::kStore) {
    1534             :     // TODO(turbofan): We could have a fast path here, that checks for the
    1535             :     // common case of Array or Object prototype only and therefore avoids
    1536             :     // the zone allocation of this vector.
    1537             :     ZoneVector<MapRef> prototype_maps(zone());
    1538       11349 :     for (ElementAccessInfo const& access_info : access_infos) {
    1539       11617 :       for (Handle<Map> map : access_info.receiver_maps()) {
    1540             :         MapRef receiver_map(broker(), map);
    1541             :         // If the {receiver_map} has a prototype and its elements backing
    1542             :         // store is either holey, or we have a potentially growing store,
    1543             :         // then we need to check that all prototypes have stable maps with
    1544             :         // fast elements (and we need to guard against changes to that below).
    1545       15761 :         if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) ||
    1546        7769 :              IsGrowStoreMode(store_mode)) &&
    1547        1957 :             !receiver_map.HasOnlyStablePrototypesWithFastElements(
    1548             :                 &prototype_maps)) {
    1549           7 :           return NoChange();
    1550             :         }
    1551             :       }
    1552             :     }
    1553        9339 :     for (MapRef const& prototype_map : prototype_maps) {
    1554        3802 :       dependencies()->DependOnStableMap(prototype_map);
    1555             :     }
    1556       16535 :   } else if (access_mode == AccessMode::kHas) {
    1557             :     // If we have any fast arrays, we need to check and depend on
    1558             :     // NoElementsProtector.
    1559          58 :     for (ElementAccessInfo const& access_info : access_infos) {
    1560          50 :       if (IsFastElementsKind(access_info.elements_kind())) {
    1561          42 :         if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
    1562          34 :         dependencies()->DependOnProtector(
    1563          34 :             PropertyCellRef(broker(), factory()->no_elements_protector()));
    1564          34 :         break;
    1565             :       }
    1566             :     }
    1567             :   }
    1568             : 
    1569             :   // Ensure that {receiver} is a heap object.
    1570             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
    1571       22064 :   receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control);
    1572             : 
    1573             :   // Check if we have the necessary data for building element accesses.
    1574       44749 :   for (ElementAccessInfo const& access_info : access_infos) {
    1575       38466 :     if (!IsFixedTypedArrayElementsKind(access_info.elements_kind())) continue;
    1576             :     base::Optional<JSTypedArrayRef> typed_array =
    1577        6904 :         GetTypedArrayConstant(broker(), receiver);
    1578        6904 :     if (typed_array.has_value()) {
    1579        1327 :       if (!FLAG_concurrent_inlining) {
    1580        1327 :         typed_array->Serialize();
    1581           0 :       } else if (!typed_array->serialized()) {
    1582           0 :         TRACE_BROKER(broker(),
    1583             :                      "ReduceElementAccess: missing data for typed array "
    1584             :                          << typed_array->object().address() << "\n");
    1585           0 :         return NoChange();
    1586             :       }
    1587             :     }
    1588             :   }
    1589             : 
    1590             :   // Check for the monomorphic case.
    1591       22064 :   if (access_infos.size() == 1) {
    1592       21597 :     ElementAccessInfo access_info = access_infos.front();
    1593             : 
    1594             :     // Perform possible elements kind transitions.
    1595             :     MapRef transition_target(broker(), access_info.receiver_maps().front());
    1596       22081 :     for (auto source : access_info.transition_sources()) {
    1597             :       DCHECK_EQ(access_info.receiver_maps().size(), 1);
    1598             :       MapRef transition_source(broker(), source);
    1599        1936 :       effect = graph()->NewNode(
    1600             :           simplified()->TransitionElementsKind(ElementsTransition(
    1601         484 :               IsSimpleMapChangeTransition(transition_source.elements_kind(),
    1602         484 :                                           transition_target.elements_kind())
    1603             :                   ? ElementsTransition::kFastTransition
    1604             :                   : ElementsTransition::kSlowTransition,
    1605             :               transition_source.object(), transition_target.object())),
    1606         484 :           receiver, effect, control);
    1607             :     }
    1608             : 
    1609             :     // TODO(turbofan): The effect/control linearization will not find a
    1610             :     // FrameState after the StoreField or Call that is generated for the
    1611             :     // elements kind transition above. This is because those operators
    1612             :     // don't have the kNoWrite flag on it, even though they are not
    1613             :     // observable by JavaScript.
    1614             :     effect =
    1615       43194 :         graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
    1616             : 
    1617             :     // Perform map check on the {receiver}.
    1618             :     access_builder.BuildCheckMaps(receiver, &effect, control,
    1619       21597 :                                   access_info.receiver_maps());
    1620             : 
    1621             :     // Access the actual element.
    1622             :     ValueEffectControl continuation =
    1623             :         BuildElementAccess(receiver, index, value, effect, control, access_info,
    1624       21597 :                            access_mode, load_mode, store_mode);
    1625             :     value = continuation.value();
    1626       21597 :     effect = continuation.effect();
    1627       21597 :     control = continuation.control();
    1628             :   } else {
    1629             :     // The final states for every polymorphic branch. We join them with
    1630             :     // Merge+Phi+EffectPhi at the bottom.
    1631             :     ZoneVector<Node*> values(zone());
    1632             :     ZoneVector<Node*> effects(zone());
    1633             :     ZoneVector<Node*> controls(zone());
    1634             : 
    1635             :     // Generate code for the various different element access patterns.
    1636         467 :     Node* fallthrough_control = control;
    1637        2643 :     for (size_t j = 0; j < access_infos.size(); ++j) {
    1638             :       ElementAccessInfo const& access_info = access_infos[j];
    1639             :       Node* this_receiver = receiver;
    1640             :       Node* this_value = value;
    1641             :       Node* this_index = index;
    1642        1088 :       Node* this_effect = effect;
    1643             :       Node* this_control = fallthrough_control;
    1644             : 
    1645             :       // Perform possible elements kind transitions.
    1646             :       MapRef transition_target(broker(), access_info.receiver_maps().front());
    1647        1174 :       for (auto source : access_info.transition_sources()) {
    1648             :         MapRef transition_source(broker(), source);
    1649             :         DCHECK_EQ(access_info.receiver_maps().size(), 1);
    1650         344 :         this_effect = graph()->NewNode(
    1651             :             simplified()->TransitionElementsKind(ElementsTransition(
    1652          86 :                 IsSimpleMapChangeTransition(transition_source.elements_kind(),
    1653          86 :                                             transition_target.elements_kind())
    1654             :                     ? ElementsTransition::kFastTransition
    1655             :                     : ElementsTransition::kSlowTransition,
    1656             :                 transition_source.object(), transition_target.object())),
    1657          86 :             receiver, effect, control);
    1658             :       }
    1659             : 
    1660             :       // Perform map check(s) on {receiver}.
    1661             :       MapHandles const& receiver_maps = access_info.receiver_maps();
    1662        1088 :       if (j == access_infos.size() - 1) {
    1663             :         // Last map check on the fallthrough control path, do a
    1664             :         // conditional eager deoptimization exit here.
    1665             :         access_builder.BuildCheckMaps(receiver, &this_effect, this_control,
    1666         467 :                                       receiver_maps);
    1667             :         fallthrough_control = nullptr;
    1668             :       } else {
    1669             :         // Explicitly branch on the {receiver_maps}.
    1670             :         ZoneHandleSet<Map> maps;
    1671        1242 :         for (Handle<Map> map : receiver_maps) {
    1672         621 :           maps.insert(map, graph()->zone());
    1673             :         }
    1674             :         Node* check = this_effect =
    1675         621 :             graph()->NewNode(simplified()->CompareMaps(maps), receiver,
    1676         621 :                              this_effect, fallthrough_control);
    1677             :         Node* branch =
    1678         621 :             graph()->NewNode(common()->Branch(), check, fallthrough_control);
    1679         621 :         fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
    1680         621 :         this_control = graph()->NewNode(common()->IfTrue(), branch);
    1681             : 
    1682             :         // Introduce a MapGuard to learn from this on the effect chain.
    1683         621 :         this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
    1684         621 :                                        this_effect, this_control);
    1685             :       }
    1686             : 
    1687             :       // Access the actual element.
    1688             :       ValueEffectControl continuation = BuildElementAccess(
    1689             :           this_receiver, this_index, this_value, this_effect, this_control,
    1690        1088 :           access_info, access_mode, load_mode, store_mode);
    1691        2176 :       values.push_back(continuation.value());
    1692        2176 :       effects.push_back(continuation.effect());
    1693        2176 :       controls.push_back(continuation.control());
    1694             :     }
    1695             : 
    1696             :     DCHECK_NULL(fallthrough_control);
    1697             : 
    1698             :     // Generate the final merge point for all (polymorphic) branches.
    1699         467 :     int const control_count = static_cast<int>(controls.size());
    1700         467 :     if (control_count == 0) {
    1701           0 :       value = effect = control = jsgraph()->Dead();
    1702         467 :     } else if (control_count == 1) {
    1703           0 :       value = values.front();
    1704           0 :       effect = effects.front();
    1705           0 :       control = controls.front();
    1706             :     } else {
    1707         467 :       control = graph()->NewNode(common()->Merge(control_count), control_count,
    1708         467 :                                  &controls.front());
    1709         467 :       values.push_back(control);
    1710         467 :       value = graph()->NewNode(
    1711             :           common()->Phi(MachineRepresentation::kTagged, control_count),
    1712         467 :           control_count + 1, &values.front());
    1713         467 :       effects.push_back(control);
    1714         467 :       effect = graph()->NewNode(common()->EffectPhi(control_count),
    1715         467 :                                 control_count + 1, &effects.front());
    1716             :     }
    1717             :   }
    1718             : 
    1719       22064 :   ReplaceWithValue(node, value, effect, control);
    1720             :   return Replace(value);
    1721             : }
    1722             : 
    1723        5470 : Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
    1724             :     Node* node, Node* index, FeedbackNexus const& nexus, AccessMode access_mode,
    1725             :     KeyedAccessLoadMode load_mode) {
    1726             :   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
    1727             :          node->opcode() == IrOpcode::kJSHasProperty);
    1728        5470 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1729        5470 :   Node* effect = NodeProperties::GetEffectInput(node);
    1730        5470 :   Node* control = NodeProperties::GetControlInput(node);
    1731             : 
    1732             :   HeapObjectMatcher mreceiver(receiver);
    1733        5470 :   HeapObjectRef receiver_ref = mreceiver.Ref(broker()).AsHeapObject();
    1734       16406 :   if (receiver_ref.map().oddball_type() == OddballType::kHole ||
    1735       16182 :       receiver_ref.map().oddball_type() == OddballType::kNull ||
    1736       21368 :       receiver_ref.map().oddball_type() == OddballType::kUndefined ||
    1737        5447 :       (receiver_ref.IsString() && access_mode == AccessMode::kHas)) {
    1738             :     return NoChange();
    1739             :   }
    1740             : 
    1741             :   // Check whether we're accessing a known element on the {receiver}
    1742             :   // that is non-configurable, non-writable (e.g. the {receiver} was
    1743             :   // frozen using Object.freeze).
    1744             :   NumberMatcher mindex(index);
    1745        6722 :   if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32 - 1.0)) {
    1746             :     LookupIterator it(isolate(), receiver_ref.object(),
    1747             :                       static_cast<uint32_t>(mindex.Value()),
    1748        3078 :                       LookupIterator::OWN);
    1749        1539 :     if (it.state() == LookupIterator::DATA) {
    1750        1371 :       if (it.IsReadOnly() && !it.IsConfigurable()) {
    1751             :         // We can safely constant-fold the {index} access to {receiver},
    1752             :         // since the element is non-configurable, non-writable and thus
    1753             :         // cannot change anymore.
    1754             :         Node* value = access_mode == AccessMode::kHas
    1755             :                           ? jsgraph()->TrueConstant()
    1756          24 :                           : jsgraph()->Constant(it.GetDataValue());
    1757          24 :         ReplaceWithValue(node, value, effect, control);
    1758          88 :         return Replace(value);
    1759             :       }
    1760             : 
    1761             :       // Check if the {receiver} is a known constant with a copy-on-write
    1762             :       // backing store, and whether {index} is within the appropriate
    1763             :       // bounds. In that case we can constant-fold the access and only
    1764             :       // check that the {elements} didn't change. This is sufficient as
    1765             :       // the backing store of a copy-on-write JSArray is defensively
    1766             :       // copied whenever the length or the elements (might) change.
    1767             :       //
    1768             :       // What's interesting here is that we don't need to map check the
    1769             :       // {receiver}, since JSArray's will always have their elements in
    1770             :       // the backing store.
    1771        1323 :       if (receiver_ref.IsJSArray()) {
    1772         894 :         Handle<JSArray> array = receiver_ref.AsJSArray().object();
    1773         894 :         if (array->elements()->IsCowArray()) {
    1774         128 :           Node* elements = effect = graph()->NewNode(
    1775         128 :               simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
    1776          64 :               receiver, effect, control);
    1777             :           Handle<FixedArray> array_elements(FixedArray::cast(array->elements()),
    1778             :                                             isolate());
    1779             :           Node* check =
    1780         128 :               graph()->NewNode(simplified()->ReferenceEqual(), elements,
    1781             :                                jsgraph()->HeapConstant(array_elements));
    1782         128 :           effect = graph()->NewNode(
    1783             :               simplified()->CheckIf(DeoptimizeReason::kCowArrayElementsChanged),
    1784          64 :               check, effect, control);
    1785             :           Node* value = access_mode == AccessMode::kHas
    1786             :                             ? jsgraph()->TrueConstant()
    1787          64 :                             : jsgraph()->Constant(it.GetDataValue());
    1788          64 :           ReplaceWithValue(node, value, effect, control);
    1789             :           return Replace(value);
    1790             :         }
    1791             :       }
    1792             :     }
    1793             :   }
    1794             : 
    1795             :   // For constant Strings we can eagerly strength-reduce the keyed
    1796             :   // accesses using the known length, which doesn't change.
    1797        5084 :   if (receiver_ref.IsString() && access_mode != AccessMode::kHas) {
    1798             :     // We can only assume that the {index} is a valid array index if the
    1799             :     // IC is in element access mode and not MEGAMORPHIC, otherwise there's
    1800             :     // no guard for the bounds check below.
    1801         239 :     if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
    1802             :       // Ensure that {index} is less than {receiver} length.
    1803         216 :       Node* length = jsgraph()->Constant(receiver_ref.AsString().length());
    1804             : 
    1805             :       // Load the single character string from {receiver} or yield
    1806             :       // undefined if the {index} is out of bounds (depending on the
    1807             :       // {load_mode}).
    1808             :       Node* value = BuildIndexedStringLoad(receiver, index, length, &effect,
    1809         216 :                                            &control, load_mode);
    1810         216 :       ReplaceWithValue(node, value, effect, control);
    1811             :       return Replace(value);
    1812             :     }
    1813             :   }
    1814             : 
    1815             :   return NoChange();
    1816             : }
    1817             : 
    1818       58736 : Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
    1819             :     Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
    1820             :     AccessMode access_mode, KeyedAccessLoadMode load_mode,
    1821             :     KeyedAccessStoreMode store_mode) {
    1822             :   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
    1823             :          node->opcode() == IrOpcode::kJSStoreProperty ||
    1824             :          node->opcode() == IrOpcode::kJSHasProperty);
    1825             : 
    1826       58736 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1827       58736 :   Node* effect = NodeProperties::GetEffectInput(node);
    1828             : 
    1829      105037 :   if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
    1830             :       receiver->opcode() == IrOpcode::kHeapConstant) {
    1831             :     Reduction reduction = ReduceKeyedLoadFromHeapConstant(
    1832        5470 :         node, index, nexus, access_mode, load_mode);
    1833        5470 :     if (reduction.Changed()) return reduction;
    1834             :   }
    1835             : 
    1836             :   // Extract receiver maps from the {nexus}.
    1837             :   MapHandles receiver_maps;
    1838       58432 :   if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
    1839             :     return NoChange();
    1840       52622 :   } else if (receiver_maps.empty()) {
    1841             :     return ReduceSoftDeoptimize(
    1842       29710 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    1843             :   }
    1844             :   DCHECK(!nexus.IsUninitialized());
    1845             : 
    1846             :   // Optimize access for constant {index}.
    1847             :   HeapObjectMatcher mindex(index);
    1848       22912 :   if (mindex.HasValue()) {
    1849         703 :     ObjectRef name = mindex.Ref(broker());
    1850         703 :     if (name.IsSymbol()) {
    1851             :       return ReduceNamedAccess(node, value, receiver_maps,
    1852         254 :                                name.AsName().object(), access_mode);
    1853             :     }
    1854         449 :     if (name.IsInternalizedString()) {
    1855         449 :       uint32_t array_index = name.AsInternalizedString().array_index();
    1856         449 :       if (array_index != InternalizedStringRef::kNotAnArrayIndex) {
    1857           0 :         index = jsgraph()->Constant(static_cast<double>(array_index));
    1858             :       } else {
    1859             :         return ReduceNamedAccess(node, value, receiver_maps,
    1860         449 :                                  name.AsName().object(), access_mode);
    1861             :       }
    1862             :     }
    1863             :   }
    1864             : 
    1865             :   // Check if we have feedback for a named access.
    1866       22209 :   Name name = nexus.GetName();
    1867       22209 :   if (!name.is_null()) {
    1868             :     return ReduceNamedAccess(node, value, receiver_maps,
    1869         356 :                              handle(name, isolate()), access_mode, index);
    1870       21853 :   } else if (nexus.GetKeyType() != ELEMENT) {
    1871             :     // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
    1872             :     // that the {index} is a valid array index, thus we just let the IC continue
    1873             :     // to deal with this load/store.
    1874             :     return NoChange();
    1875       21818 :   } else if (nexus.ic_state() == MEGAMORPHIC) {
    1876             :     // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption
    1877             :     // that a numeric {index} is within the valid bounds for {receiver}, i.e.
    1878             :     // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus
    1879             :     // we cannot continue here if the IC state is MEGAMORPHIC.
    1880             :     return NoChange();
    1881             :   }
    1882             : 
    1883             :   // Try to lower the element access based on the {receiver_maps}.
    1884             :   return ReduceElementAccess(node, index, value, nexus, receiver_maps,
    1885       20600 :                              access_mode, load_mode, store_mode);
    1886             : }
    1887             : 
    1888      416241 : Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
    1889             :     Node* node, DeoptimizeReason reason) {
    1890      416241 :   if (flags() & kBailoutOnUninitialized) {
    1891         284 :     Node* effect = NodeProperties::GetEffectInput(node);
    1892         284 :     Node* control = NodeProperties::GetControlInput(node);
    1893         284 :     Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    1894         568 :     Node* deoptimize = graph()->NewNode(
    1895             :         common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()),
    1896             :         frame_state, effect, control);
    1897             :     // TODO(bmeurer): This should be on the AdvancedReducer somehow.
    1898         284 :     NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
    1899             :     Revisit(graph()->end());
    1900         284 :     node->TrimInputCount(0);
    1901         284 :     NodeProperties::ChangeOp(node, common()->Dead());
    1902             :     return Changed(node);
    1903             :   }
    1904             :   return NoChange();
    1905             : }
    1906             : 
    1907        1586 : Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
    1908             :   DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode());
    1909        1586 :   PropertyAccess const& p = PropertyAccessOf(node->op());
    1910        1586 :   Node* index = NodeProperties::GetValueInput(node, 1);
    1911        1586 :   Node* value = jsgraph()->Dead();
    1912             : 
    1913             :   // Extract receiver maps from the has property IC using the FeedbackNexus.
    1914        1586 :   if (!p.feedback().IsValid()) return NoChange();
    1915             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    1916             : 
    1917             :   // Extract the keyed access load mode from the keyed load IC.
    1918        1546 :   KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
    1919             : 
    1920             :   // Try to lower the keyed access based on the {nexus}.
    1921             :   return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kHas,
    1922        1546 :                            load_mode, STANDARD_STORE);
    1923             : }
    1924             : 
    1925        1258 : Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
    1926             :     Node* node) {
    1927             :   // We can optimize a property load if it's being used inside a for..in:
    1928             :   //   for (name in receiver) {
    1929             :   //     value = receiver[name];
    1930             :   //     ...
    1931             :   //   }
    1932             :   //
    1933             :   // If the for..in is in fast-mode, we know that the {receiver} has {name}
    1934             :   // as own property, otherwise the enumeration wouldn't include it. The graph
    1935             :   // constructed by the BytecodeGraphBuilder in this case looks like this:
    1936             : 
    1937             :   // receiver
    1938             :   //  ^    ^
    1939             :   //  |    |
    1940             :   //  |    +-+
    1941             :   //  |      |
    1942             :   //  |   JSToObject
    1943             :   //  |      ^
    1944             :   //  |      |
    1945             :   //  |      |
    1946             :   //  |  JSForInNext
    1947             :   //  |      ^
    1948             :   //  |      |
    1949             :   //  +----+ |
    1950             :   //       | |
    1951             :   //       | |
    1952             :   //   JSLoadProperty
    1953             : 
    1954             :   // If the for..in has only seen maps with enum cache consisting of keys
    1955             :   // and indices so far, we can turn the {JSLoadProperty} into a map check
    1956             :   // on the {receiver} and then just load the field value dynamically via
    1957             :   // the {LoadFieldByIndex} operator. The map check is only necessary when
    1958             :   // TurboFan cannot prove that there is no observable side effect between
    1959             :   // the {JSForInNext} and the {JSLoadProperty} node.
    1960             :   //
    1961             :   // Also note that it's safe to look through the {JSToObject}, since the
    1962             :   // [[Get]] operation does an implicit ToObject anyway, and these operations
    1963             :   // are not observable.
    1964             : 
    1965             :   DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
    1966        1258 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    1967        1258 :   Node* name = NodeProperties::GetValueInput(node, 1);
    1968             :   DCHECK_EQ(IrOpcode::kJSForInNext, name->opcode());
    1969        1258 :   Node* effect = NodeProperties::GetEffectInput(node);
    1970        1258 :   Node* control = NodeProperties::GetControlInput(node);
    1971             : 
    1972        1258 :   if (ForInModeOf(name->op()) != ForInMode::kUseEnumCacheKeysAndIndices) {
    1973             :     return NoChange();
    1974             :   }
    1975             : 
    1976         683 :   Node* object = NodeProperties::GetValueInput(name, 0);
    1977         683 :   Node* enumerator = NodeProperties::GetValueInput(name, 2);
    1978         683 :   Node* index = NodeProperties::GetValueInput(name, 3);
    1979         683 :   if (object->opcode() == IrOpcode::kJSToObject) {
    1980         613 :     object = NodeProperties::GetValueInput(object, 0);
    1981             :   }
    1982         683 :   if (object != receiver) return NoChange();
    1983             : 
    1984             :   // No need to repeat the map check if we can prove that there's no
    1985             :   // observable side effect between {effect} and {name].
    1986         311 :   if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
    1987             :     // Check that the {receiver} map is still valid.
    1988             :     Node* receiver_map = effect =
    1989         486 :         graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
    1990             :                          receiver, effect, control);
    1991         243 :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
    1992             :                                    enumerator);
    1993             :     effect =
    1994         486 :         graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
    1995             :                          check, effect, control);
    1996             :   }
    1997             : 
    1998             :   // Load the enum cache indices from the {cache_type}.
    1999         311 :   Node* descriptor_array = effect = graph()->NewNode(
    2000         622 :       simplified()->LoadField(AccessBuilder::ForMapDescriptors()), enumerator,
    2001             :       effect, control);
    2002         311 :   Node* enum_cache = effect = graph()->NewNode(
    2003         622 :       simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
    2004             :       descriptor_array, effect, control);
    2005         311 :   Node* enum_indices = effect = graph()->NewNode(
    2006         622 :       simplified()->LoadField(AccessBuilder::ForEnumCacheIndices()), enum_cache,
    2007             :       effect, control);
    2008             : 
    2009             :   // Ensure that the {enum_indices} are valid.
    2010         622 :   Node* check = graph()->NewNode(
    2011             :       simplified()->BooleanNot(),
    2012             :       graph()->NewNode(simplified()->ReferenceEqual(), enum_indices,
    2013             :                        jsgraph()->EmptyFixedArrayConstant()));
    2014         622 :   effect = graph()->NewNode(
    2015             :       simplified()->CheckIf(DeoptimizeReason::kWrongEnumIndices), check, effect,
    2016             :       control);
    2017             : 
    2018             :   // Determine the index from the {enum_indices}.
    2019         311 :   index = effect = graph()->NewNode(
    2020             :       simplified()->LoadElement(
    2021         622 :           AccessBuilder::ForFixedArrayElement(PACKED_SMI_ELEMENTS)),
    2022             :       enum_indices, index, effect, control);
    2023             : 
    2024             :   // Load the actual field value.
    2025         311 :   Node* value = effect = graph()->NewNode(simplified()->LoadFieldByIndex(),
    2026             :                                           receiver, index, effect, control);
    2027             :   ReplaceWithValue(node, value, effect, control);
    2028             :   return Replace(value);
    2029             : }
    2030             : 
    2031       45066 : Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
    2032             :   DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
    2033       45066 :   PropertyAccess const& p = PropertyAccessOf(node->op());
    2034       45066 :   Node* name = NodeProperties::GetValueInput(node, 1);
    2035             : 
    2036       45066 :   if (name->opcode() == IrOpcode::kJSForInNext) {
    2037        1258 :     Reduction reduction = ReduceJSLoadPropertyWithEnumeratedKey(node);
    2038        1258 :     if (reduction.Changed()) return reduction;
    2039             :   }
    2040             : 
    2041             :   // Extract receiver maps from the keyed load IC using the FeedbackNexus.
    2042       44755 :   if (!p.feedback().IsValid()) return NoChange();
    2043             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    2044             : 
    2045             :   // Extract the keyed access load mode from the keyed load IC.
    2046       44755 :   KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
    2047             : 
    2048             :   // Try to lower the keyed access based on the {nexus}.
    2049       44755 :   Node* value = jsgraph()->Dead();
    2050             :   return ReduceKeyedAccess(node, name, value, nexus, AccessMode::kLoad,
    2051       44755 :                            load_mode, STANDARD_STORE);
    2052             : }
    2053             : 
    2054       12435 : Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
    2055             :   DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
    2056       12435 :   PropertyAccess const& p = PropertyAccessOf(node->op());
    2057       12435 :   Node* const index = NodeProperties::GetValueInput(node, 1);
    2058       12435 :   Node* const value = NodeProperties::GetValueInput(node, 2);
    2059             : 
    2060             :   // Extract receiver maps from the keyed store IC using the FeedbackNexus.
    2061       12435 :   if (!p.feedback().IsValid()) return NoChange();
    2062             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    2063             : 
    2064             :   // Extract the keyed access store mode from the keyed store IC.
    2065       12435 :   KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
    2066             : 
    2067             :   // Try to lower the keyed access based on the {nexus}.
    2068             :   return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
    2069       12435 :                            STANDARD_LOAD, store_mode);
    2070             : }
    2071             : 
    2072        2416 : Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
    2073             :     Node* receiver, Node* context, Node* frame_state, Node** effect,
    2074             :     Node** control, ZoneVector<Node*>* if_exceptions,
    2075             :     PropertyAccessInfo const& access_info) {
    2076        2416 :   Node* target = jsgraph()->Constant(access_info.constant());
    2077        2416 :   FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
    2078             :   Handle<SharedFunctionInfo> shared_info =
    2079        2416 :       frame_info.shared_info().ToHandleChecked();
    2080             :   // Introduce the call to the getter function.
    2081             :   Node* value;
    2082        2416 :   if (access_info.constant()->IsJSFunction()) {
    2083        7056 :     value = *effect = *control = graph()->NewNode(
    2084             :         jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
    2085             :                                       ConvertReceiverMode::kNotNullOrUndefined),
    2086        2352 :         target, receiver, context, frame_state, *effect, *control);
    2087             :   } else {
    2088             :     DCHECK(access_info.constant()->IsFunctionTemplateInfo());
    2089             :     Handle<FunctionTemplateInfo> function_template_info(
    2090          64 :         Handle<FunctionTemplateInfo>::cast(access_info.constant()));
    2091             :     DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
    2092             :     Node* holder =
    2093             :         access_info.holder().is_null()
    2094             :             ? receiver
    2095          64 :             : jsgraph()->Constant(access_info.holder().ToHandleChecked());
    2096             :     value = InlineApiCall(receiver, holder, frame_state, nullptr, effect,
    2097          64 :                           control, shared_info, function_template_info);
    2098             :   }
    2099             :   // Remember to rewire the IfException edge if this is inside a try-block.
    2100        2416 :   if (if_exceptions != nullptr) {
    2101             :     // Create the appropriate IfException/IfSuccess projections.
    2102             :     Node* const if_exception =
    2103         460 :         graph()->NewNode(common()->IfException(), *control, *effect);
    2104         230 :     Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control);
    2105         230 :     if_exceptions->push_back(if_exception);
    2106         230 :     *control = if_success;
    2107             :   }
    2108        2416 :   return value;
    2109             : }
    2110             : 
    2111         850 : void JSNativeContextSpecialization::InlinePropertySetterCall(
    2112             :     Node* receiver, Node* value, Node* context, Node* frame_state,
    2113             :     Node** effect, Node** control, ZoneVector<Node*>* if_exceptions,
    2114             :     PropertyAccessInfo const& access_info) {
    2115         850 :   Node* target = jsgraph()->Constant(access_info.constant());
    2116         850 :   FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
    2117             :   Handle<SharedFunctionInfo> shared_info =
    2118         850 :       frame_info.shared_info().ToHandleChecked();
    2119             :   // Introduce the call to the setter function.
    2120         850 :   if (access_info.constant()->IsJSFunction()) {
    2121        2358 :     *effect = *control = graph()->NewNode(
    2122             :         jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
    2123             :                                       ConvertReceiverMode::kNotNullOrUndefined),
    2124         786 :         target, receiver, value, context, frame_state, *effect, *control);
    2125             :   } else {
    2126             :     DCHECK(access_info.constant()->IsFunctionTemplateInfo());
    2127             :     Handle<FunctionTemplateInfo> function_template_info(
    2128          64 :         Handle<FunctionTemplateInfo>::cast(access_info.constant()));
    2129             :     DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
    2130             :     Node* holder =
    2131             :         access_info.holder().is_null()
    2132             :             ? receiver
    2133          64 :             : jsgraph()->Constant(access_info.holder().ToHandleChecked());
    2134             :     InlineApiCall(receiver, holder, frame_state, value, effect, control,
    2135          64 :                   shared_info, function_template_info);
    2136             :   }
    2137             :   // Remember to rewire the IfException edge if this is inside a try-block.
    2138         850 :   if (if_exceptions != nullptr) {
    2139             :     // Create the appropriate IfException/IfSuccess projections.
    2140             :     Node* const if_exception =
    2141          62 :         graph()->NewNode(common()->IfException(), *control, *effect);
    2142          31 :     Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control);
    2143          31 :     if_exceptions->push_back(if_exception);
    2144          31 :     *control = if_success;
    2145             :   }
    2146         850 : }
    2147             : 
    2148         128 : Node* JSNativeContextSpecialization::InlineApiCall(
    2149             :     Node* receiver, Node* holder, Node* frame_state, Node* value, Node** effect,
    2150             :     Node** control, Handle<SharedFunctionInfo> shared_info,
    2151             :     Handle<FunctionTemplateInfo> function_template_info) {
    2152             :   Handle<CallHandlerInfo> call_handler_info = handle(
    2153             :       CallHandlerInfo::cast(function_template_info->call_code()), isolate());
    2154             :   Handle<Object> call_data_object(call_handler_info->data(), isolate());
    2155             : 
    2156             :   // Only setters have a value.
    2157         128 :   int const argc = value == nullptr ? 0 : 1;
    2158             :   // The stub always expects the receiver as the first param on the stack.
    2159         128 :   Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
    2160             :   CallInterfaceDescriptor call_interface_descriptor =
    2161             :       call_api_callback.descriptor();
    2162         256 :   auto call_descriptor = Linkage::GetStubCallDescriptor(
    2163             :       graph()->zone(), call_interface_descriptor,
    2164         128 :       call_interface_descriptor.GetStackParameterCount() + argc +
    2165             :           1 /* implicit receiver */,
    2166         128 :       CallDescriptor::kNeedsFrameState);
    2167             : 
    2168         128 :   Node* data = jsgraph()->Constant(call_data_object);
    2169             :   ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
    2170             :   Node* function_reference =
    2171         256 :       graph()->NewNode(common()->ExternalConstant(ExternalReference::Create(
    2172             :           &function, ExternalReference::DIRECT_API_CALL)));
    2173         128 :   Node* code = jsgraph()->HeapConstant(call_api_callback.code());
    2174             : 
    2175             :   // Add CallApiCallbackStub's register argument as well.
    2176         128 :   Node* context = jsgraph()->Constant(native_context());
    2177             :   Node* inputs[11] = {
    2178         128 :       code,    function_reference, jsgraph()->Constant(argc), data, holder,
    2179         256 :       receiver};
    2180         128 :   int index = 6 + argc;
    2181         128 :   inputs[index++] = context;
    2182         128 :   inputs[index++] = frame_state;
    2183         128 :   inputs[index++] = *effect;
    2184         128 :   inputs[index++] = *control;
    2185             :   // This needs to stay here because of the edge case described in
    2186             :   // http://crbug.com/675648.
    2187         128 :   if (value != nullptr) {
    2188          64 :     inputs[6] = value;
    2189             :   }
    2190             : 
    2191             :   return *effect = *control =
    2192         256 :              graph()->NewNode(common()->Call(call_descriptor), index, inputs);
    2193             : }
    2194             : 
    2195             : JSNativeContextSpecialization::ValueEffectControl
    2196      102342 : JSNativeContextSpecialization::BuildPropertyLoad(
    2197             :     Node* receiver, Node* context, Node* frame_state, Node* effect,
    2198             :     Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
    2199             :     PropertyAccessInfo const& access_info) {
    2200             :   // Determine actual holder and perform prototype chain checks.
    2201             :   Handle<JSObject> holder;
    2202             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
    2203      102342 :   if (access_info.holder().ToHandle(&holder)) {
    2204       27680 :     dependencies()->DependOnStablePrototypeChains(
    2205       27680 :         access_info.receiver_maps(), JSObjectRef(broker(), holder));
    2206             :   }
    2207             : 
    2208             :   // Generate the actual property access.
    2209             :   Node* value;
    2210      102342 :   if (access_info.IsNotFound()) {
    2211        3201 :     value = jsgraph()->UndefinedConstant();
    2212       99141 :   } else if (access_info.IsDataConstant()) {
    2213             :     DCHECK(!FLAG_track_constant_fields);
    2214           0 :     value = jsgraph()->Constant(access_info.constant());
    2215       99141 :   } else if (access_info.IsAccessorConstant()) {
    2216             :     value = InlinePropertyGetterCall(receiver, context, frame_state, &effect,
    2217        2416 :                                      &control, if_exceptions, access_info);
    2218       96725 :   } else if (access_info.IsModuleExport()) {
    2219          14 :     Node* cell = jsgraph()->Constant(access_info.export_cell());
    2220             :     value = effect =
    2221          14 :         graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
    2222           7 :                          cell, effect, control);
    2223       96718 :   } else if (access_info.IsStringLength()) {
    2224        1817 :     value = graph()->NewNode(simplified()->StringLength(), receiver);
    2225             :   } else {
    2226             :     DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
    2227             :     value = access_builder.BuildLoadDataField(name, access_info, receiver,
    2228       94901 :                                               &effect, &control);
    2229             :   }
    2230             : 
    2231      204684 :   return ValueEffectControl(value, effect, control);
    2232             : }
    2233             : 
    2234             : JSNativeContextSpecialization::ValueEffectControl
    2235         242 : JSNativeContextSpecialization::BuildPropertyTest(
    2236             :     Node* effect, Node* control, PropertyAccessInfo const& access_info) {
    2237             :   // Determine actual holder and perform prototype chain checks.
    2238             :   Handle<JSObject> holder;
    2239         242 :   if (access_info.holder().ToHandle(&holder)) {
    2240         173 :     dependencies()->DependOnStablePrototypeChains(
    2241         173 :         access_info.receiver_maps(), JSObjectRef(broker(), holder));
    2242             :   }
    2243             : 
    2244             :   Node* value = access_info.IsNotFound() ? jsgraph()->FalseConstant()
    2245         242 :                                          : jsgraph()->TrueConstant();
    2246             : 
    2247         242 :   return ValueEffectControl(value, effect, control);
    2248             : }
    2249             : 
    2250             : JSNativeContextSpecialization::ValueEffectControl
    2251      130601 : JSNativeContextSpecialization::BuildPropertyAccess(
    2252             :     Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
    2253             :     Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
    2254             :     PropertyAccessInfo const& access_info, AccessMode access_mode) {
    2255      130601 :   switch (access_mode) {
    2256             :     case AccessMode::kLoad:
    2257             :       return BuildPropertyLoad(receiver, context, frame_state, effect, control,
    2258      102342 :                                name, if_exceptions, access_info);
    2259             :     case AccessMode::kStore:
    2260             :     case AccessMode::kStoreInLiteral:
    2261             :       return BuildPropertyStore(receiver, value, context, frame_state, effect,
    2262             :                                 control, name, if_exceptions, access_info,
    2263       28017 :                                 access_mode);
    2264             :     case AccessMode::kHas:
    2265         242 :       return BuildPropertyTest(effect, control, access_info);
    2266             :   }
    2267           0 :   UNREACHABLE();
    2268             :   return ValueEffectControl();
    2269             : }
    2270             : 
    2271             : JSNativeContextSpecialization::ValueEffectControl
    2272       28017 : JSNativeContextSpecialization::BuildPropertyStore(
    2273             :     Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
    2274             :     Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
    2275             :     PropertyAccessInfo const& access_info, AccessMode access_mode) {
    2276             :   // Determine actual holder and perform prototype chain checks.
    2277             :   Handle<JSObject> holder;
    2278             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
    2279       28017 :   if (access_info.holder().ToHandle(&holder)) {
    2280             :     DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
    2281       21735 :     dependencies()->DependOnStablePrototypeChains(
    2282       21735 :         access_info.receiver_maps(), JSObjectRef(broker(), holder));
    2283             :   }
    2284             : 
    2285             :   DCHECK(!access_info.IsNotFound());
    2286             : 
    2287             :   // Generate the actual property access.
    2288       28017 :   if (access_info.IsDataConstant()) {
    2289             :     DCHECK(!FLAG_track_constant_fields);
    2290           0 :     Node* constant_value = jsgraph()->Constant(access_info.constant());
    2291             :     Node* check =
    2292           0 :         graph()->NewNode(simplified()->ReferenceEqual(), value, constant_value);
    2293             :     effect =
    2294           0 :         graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
    2295           0 :                          check, effect, control);
    2296             :     value = constant_value;
    2297       28017 :   } else if (access_info.IsAccessorConstant()) {
    2298             :     InlinePropertySetterCall(receiver, value, context, frame_state, &effect,
    2299         850 :                              &control, if_exceptions, access_info);
    2300             :   } else {
    2301             :     DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
    2302             :     FieldIndex const field_index = access_info.field_index();
    2303             :     Type const field_type = access_info.field_type();
    2304             :     MachineRepresentation const field_representation =
    2305       27167 :         access_info.field_representation();
    2306             :     Node* storage = receiver;
    2307       27167 :     if (!field_index.is_inobject()) {
    2308       13354 :       storage = effect = graph()->NewNode(
    2309       13354 :           simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
    2310        6677 :           storage, effect, control);
    2311             :     }
    2312             :     FieldAccess field_access = {
    2313             :         kTaggedBase,
    2314             :         field_index.offset(),
    2315             :         name,
    2316             :         MaybeHandle<Map>(),
    2317             :         field_type,
    2318             :         MachineType::TypeForRepresentation(field_representation),
    2319       27167 :         kFullWriteBarrier};
    2320             :     bool store_to_constant_field = FLAG_track_constant_fields &&
    2321       27167 :                                    (access_mode == AccessMode::kStore) &&
    2322             :                                    access_info.IsDataConstantField();
    2323             : 
    2324             :     DCHECK(access_mode == AccessMode::kStore ||
    2325             :            access_mode == AccessMode::kStoreInLiteral);
    2326       27167 :     switch (field_representation) {
    2327             :       case MachineRepresentation::kFloat64: {
    2328             :         value = effect =
    2329         640 :             graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
    2330         320 :                              effect, control);
    2331             :         if (!field_index.is_inobject() || field_index.is_hidden_field() ||
    2332             :             !FLAG_unbox_double_fields) {
    2333         320 :           if (access_info.HasTransitionMap()) {
    2334             :             // Allocate a MutableHeapNumber for the new property.
    2335         155 :             AllocationBuilder a(jsgraph(), effect, control);
    2336             :             a.Allocate(HeapNumber::kSize, AllocationType::kYoung,
    2337         155 :                        Type::OtherInternal());
    2338         310 :             a.Store(AccessBuilder::ForMap(),
    2339         155 :                     factory()->mutable_heap_number_map());
    2340         155 :             a.Store(AccessBuilder::ForHeapNumberValue(), value);
    2341         155 :             value = effect = a.Finish();
    2342             : 
    2343         155 :             field_access.type = Type::Any();
    2344         155 :             field_access.machine_type = MachineType::TaggedPointer();
    2345         155 :             field_access.write_barrier_kind = kPointerWriteBarrier;
    2346             :           } else {
    2347             :             // We just store directly to the MutableHeapNumber.
    2348             :             FieldAccess const storage_access = {kTaggedBase,
    2349             :                                                 field_index.offset(),
    2350             :                                                 name,
    2351             :                                                 MaybeHandle<Map>(),
    2352             :                                                 Type::OtherInternal(),
    2353             :                                                 MachineType::TaggedPointer(),
    2354             :                                                 kPointerWriteBarrier};
    2355             :             storage = effect =
    2356         165 :                 graph()->NewNode(simplified()->LoadField(storage_access),
    2357         165 :                                  storage, effect, control);
    2358         165 :             field_access.offset = HeapNumber::kValueOffset;
    2359         165 :             field_access.name = MaybeHandle<Name>();
    2360         165 :             field_access.machine_type = MachineType::Float64();
    2361             :           }
    2362             :         }
    2363         320 :         if (store_to_constant_field) {
    2364             :           DCHECK(!access_info.HasTransitionMap());
    2365             :           // If the field is constant check that the value we are going
    2366             :           // to store matches current value.
    2367          39 :           Node* current_value = effect = graph()->NewNode(
    2368          39 :               simplified()->LoadField(field_access), storage, effect, control);
    2369             : 
    2370          39 :           Node* check = graph()->NewNode(simplified()->NumberEqual(),
    2371             :                                          current_value, value);
    2372          78 :           effect = graph()->NewNode(
    2373             :               simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
    2374          39 :               effect, control);
    2375         297 :           return ValueEffectControl(value, effect, control);
    2376             :         }
    2377             :         break;
    2378             :       }
    2379             :       case MachineRepresentation::kTaggedSigned:
    2380             :       case MachineRepresentation::kTaggedPointer:
    2381             :       case MachineRepresentation::kTagged:
    2382       26847 :         if (store_to_constant_field) {
    2383             :           DCHECK(!access_info.HasTransitionMap());
    2384             :           // If the field is constant check that the value we are going
    2385             :           // to store matches current value.
    2386         219 :           Node* current_value = effect = graph()->NewNode(
    2387         219 :               simplified()->LoadField(field_access), storage, effect, control);
    2388             : 
    2389         219 :           Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
    2390             :                                          current_value, value);
    2391         438 :           effect = graph()->NewNode(
    2392             :               simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
    2393         219 :               effect, control);
    2394         219 :           return ValueEffectControl(value, effect, control);
    2395             :         }
    2396             : 
    2397       26628 :         if (field_representation == MachineRepresentation::kTaggedSigned) {
    2398       40168 :           value = effect = graph()->NewNode(
    2399       20084 :               simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
    2400       20084 :           field_access.write_barrier_kind = kNoWriteBarrier;
    2401             : 
    2402        6544 :         } else if (field_representation ==
    2403             :                    MachineRepresentation::kTaggedPointer) {
    2404             :           // Ensure that {value} is a HeapObject.
    2405        3385 :           value = access_builder.BuildCheckHeapObject(value, &effect, control);
    2406             :           Handle<Map> field_map;
    2407        3385 :           if (access_info.field_map().ToHandle(&field_map)) {
    2408             :             // Emit a map check for the value.
    2409         783 :             effect = graph()->NewNode(
    2410             :                 simplified()->CheckMaps(CheckMapsFlag::kNone,
    2411             :                                         ZoneHandleSet<Map>(field_map)),
    2412         261 :                 value, effect, control);
    2413             :           }
    2414        3385 :           field_access.write_barrier_kind = kPointerWriteBarrier;
    2415             : 
    2416             :         } else {
    2417             :           DCHECK_EQ(MachineRepresentation::kTagged, field_representation);
    2418             :         }
    2419             :         break;
    2420             :       case MachineRepresentation::kNone:
    2421             :       case MachineRepresentation::kBit:
    2422             :       case MachineRepresentation::kWord8:
    2423             :       case MachineRepresentation::kWord16:
    2424             :       case MachineRepresentation::kWord32:
    2425             :       case MachineRepresentation::kWord64:
    2426             :       case MachineRepresentation::kFloat32:
    2427             :       case MachineRepresentation::kSimd128:
    2428             :       // TODO(solanes): Create the code for the compressed values
    2429             :       case MachineRepresentation::kCompressedSigned:
    2430             :       case MachineRepresentation::kCompressedPointer:
    2431             :       case MachineRepresentation::kCompressed:
    2432           0 :         UNREACHABLE();
    2433             :         break;
    2434             :     }
    2435             :     // Check if we need to perform a transitioning store.
    2436             :     Handle<Map> transition_map;
    2437       26909 :     if (access_info.transition_map().ToHandle(&transition_map)) {
    2438             :       // Check if we need to grow the properties backing store
    2439             :       // with this transitioning store.
    2440             :       Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
    2441       42904 :                                isolate());
    2442       21452 :       if (original_map->UnusedPropertyFields() == 0) {
    2443             :         DCHECK(!field_index.is_inobject());
    2444             : 
    2445             :         // Reallocate the properties {storage}.
    2446        6894 :         storage = effect = BuildExtendPropertiesBackingStore(
    2447        2298 :             MapRef(broker(), original_map), storage, effect, control);
    2448             : 
    2449             :         // Perform the actual store.
    2450        2298 :         effect = graph()->NewNode(simplified()->StoreField(field_access),
    2451        2298 :                                   storage, value, effect, control);
    2452             : 
    2453             :         // Atomically switch to the new properties below.
    2454        2298 :         field_access = AccessBuilder::ForJSObjectPropertiesOrHash();
    2455             :         value = storage;
    2456             :         storage = receiver;
    2457             :       }
    2458       21452 :       effect = graph()->NewNode(
    2459       21452 :           common()->BeginRegion(RegionObservability::kObservable), effect);
    2460       85808 :       effect = graph()->NewNode(
    2461       42904 :           simplified()->StoreField(AccessBuilder::ForMap()), receiver,
    2462       21452 :           jsgraph()->Constant(transition_map), effect, control);
    2463       21452 :       effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
    2464       21452 :                                 value, effect, control);
    2465       21452 :       effect = graph()->NewNode(common()->FinishRegion(),
    2466       21452 :                                 jsgraph()->UndefinedConstant(), effect);
    2467             :     } else {
    2468             :       // Regular non-transitioning field store.
    2469        5457 :       effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
    2470        5457 :                                 value, effect, control);
    2471             :     }
    2472             :   }
    2473             : 
    2474       27759 :   return ValueEffectControl(value, effect, control);
    2475             : }
    2476             : 
    2477         540 : Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
    2478             :     Node* node) {
    2479             :   DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
    2480             : 
    2481         540 :   FeedbackParameter const& p = FeedbackParameterOf(node->op());
    2482             : 
    2483         540 :   if (!p.feedback().IsValid()) return NoChange();
    2484             : 
    2485             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    2486         540 :   if (nexus.IsUninitialized()) {
    2487             :     return NoChange();
    2488             :   }
    2489             : 
    2490         144 :   if (nexus.ic_state() == MEGAMORPHIC) {
    2491             :     return NoChange();
    2492             :   }
    2493             : 
    2494             :   DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
    2495             : 
    2496         128 :   Map map = nexus.GetFirstMap();
    2497         128 :   if (map.is_null()) {
    2498             :     // Maps are weakly held in the type feedback vector, we may not have one.
    2499             :     return NoChange();
    2500             :   }
    2501             : 
    2502             :   Handle<Map> receiver_map(map, isolate());
    2503         256 :   if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map))
    2504             :     return NoChange();
    2505             : 
    2506             :   Handle<Name> cached_name(
    2507         256 :       Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
    2508             :       isolate());
    2509             : 
    2510         128 :   PropertyAccessInfo access_info;
    2511             :   AccessInfoFactory access_info_factory(broker(), dependencies(),
    2512         128 :                                         graph()->zone());
    2513         128 :   if (!access_info_factory.ComputePropertyAccessInfo(
    2514             :           receiver_map, cached_name, AccessMode::kStoreInLiteral,
    2515             :           &access_info)) {
    2516             :     return NoChange();
    2517             :   }
    2518             : 
    2519          97 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    2520          97 :   Node* effect = NodeProperties::GetEffectInput(node);
    2521          97 :   Node* control = NodeProperties::GetControlInput(node);
    2522             : 
    2523             :   // Monomorphic property access.
    2524             :   PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
    2525          97 :   receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control);
    2526             :   access_builder.BuildCheckMaps(receiver, &effect, control,
    2527          97 :                                 access_info.receiver_maps());
    2528             : 
    2529             :   // Ensure that {name} matches the cached name.
    2530          97 :   Node* name = NodeProperties::GetValueInput(node, 1);
    2531         194 :   Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
    2532             :                                  jsgraph()->HeapConstant(cached_name));
    2533         194 :   effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongName),
    2534          97 :                             check, effect, control);
    2535             : 
    2536          97 :   Node* value = NodeProperties::GetValueInput(node, 2);
    2537          97 :   Node* context = NodeProperties::GetContextInput(node);
    2538          97 :   Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
    2539             : 
    2540             :   // Generate the actual property access.
    2541             :   ValueEffectControl continuation = BuildPropertyAccess(
    2542             :       receiver, value, context, frame_state_lazy, effect, control, cached_name,
    2543          97 :       nullptr, access_info, AccessMode::kStoreInLiteral);
    2544             :   value = continuation.value();
    2545          97 :   effect = continuation.effect();
    2546             :   control = continuation.control();
    2547             : 
    2548             :   ReplaceWithValue(node, value, effect, control);
    2549             :   return Replace(value);
    2550             : }
    2551             : 
    2552       49847 : Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
    2553             :     Node* node) {
    2554             :   DCHECK_EQ(IrOpcode::kJSStoreInArrayLiteral, node->opcode());
    2555       49847 :   FeedbackParameter const& p = FeedbackParameterOf(node->op());
    2556       49848 :   Node* const receiver = NodeProperties::GetValueInput(node, 0);
    2557       49848 :   Node* const index = NodeProperties::GetValueInput(node, 1);
    2558       49848 :   Node* const value = NodeProperties::GetValueInput(node, 2);
    2559       49848 :   Node* const effect = NodeProperties::GetEffectInput(node);
    2560             : 
    2561             :   // Extract receiver maps from the keyed store IC using the FeedbackNexus.
    2562       49848 :   if (!p.feedback().IsValid()) return NoChange();
    2563             :   FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
    2564             : 
    2565             :   // Extract the keyed access store mode from the keyed store IC.
    2566       49848 :   KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
    2567             : 
    2568             :   // Extract receiver maps from the {nexus}.
    2569             :   MapHandles receiver_maps;
    2570       49847 :   if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
    2571             :     return NoChange();
    2572       49848 :   } else if (receiver_maps.empty()) {
    2573             :     return ReduceSoftDeoptimize(
    2574       46924 :         node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
    2575             :   }
    2576             :   DCHECK(!nexus.IsUninitialized());
    2577             :   DCHECK_EQ(ELEMENT, nexus.GetKeyType());
    2578             : 
    2579        2924 :   if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
    2580             : 
    2581             :   // Try to lower the element access based on the {receiver_maps}.
    2582             :   return ReduceElementAccess(node, index, value, nexus, receiver_maps,
    2583             :                              AccessMode::kStoreInLiteral, STANDARD_LOAD,
    2584        2924 :                              store_mode);
    2585             : }
    2586             : 
    2587        1999 : Reduction JSNativeContextSpecialization::ReduceJSToObject(Node* node) {
    2588             :   DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
    2589        1999 :   Node* receiver = NodeProperties::GetValueInput(node, 0);
    2590        1999 :   Node* effect = NodeProperties::GetEffectInput(node);
    2591             : 
    2592             :   ZoneHandleSet<Map> receiver_maps;
    2593             :   NodeProperties::InferReceiverMapsResult result =
    2594             :       NodeProperties::InferReceiverMaps(broker(), receiver, effect,
    2595        1999 :                                         &receiver_maps);
    2596        1999 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
    2597             : 
    2598         262 :   for (size_t i = 0; i < receiver_maps.size(); ++i) {
    2599         141 :     if (!receiver_maps[i]->IsJSReceiverMap()) return NoChange();
    2600             :   }
    2601             : 
    2602             :   ReplaceWithValue(node, receiver, effect);
    2603             :   return Replace(receiver);
    2604             : }
    2605             : 
    2606             : namespace {
    2607             : 
    2608        6904 : ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
    2609        6904 :   switch (kind) {
    2610             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    2611             :   case TYPE##_ELEMENTS:                           \
    2612             :     return kExternal##Type##Array;
    2613         492 :     TYPED_ARRAYS(TYPED_ARRAY_CASE)
    2614             : #undef TYPED_ARRAY_CASE
    2615             :     default:
    2616             :       break;
    2617             :   }
    2618           0 :   UNREACHABLE();
    2619             : }
    2620             : 
    2621             : }  // namespace
    2622             : 
    2623             : JSNativeContextSpecialization::ValueEffectControl
    2624       22685 : JSNativeContextSpecialization::BuildElementAccess(
    2625             :     Node* receiver, Node* index, Node* value, Node* effect, Node* control,
    2626             :     ElementAccessInfo const& access_info, AccessMode access_mode,
    2627             :     KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
    2628             :   // TODO(bmeurer): We currently specialize based on elements kind. We should
    2629             :   // also be able to properly support strings and other JSObjects here.
    2630             :   ElementsKind elements_kind = access_info.elements_kind();
    2631             :   MapHandles const& receiver_maps = access_info.receiver_maps();
    2632             : 
    2633       22685 :   if (IsFixedTypedArrayElementsKind(elements_kind)) {
    2634             :     Node* buffer;
    2635             :     Node* length;
    2636             :     Node* base_pointer;
    2637             :     Node* external_pointer;
    2638             : 
    2639             :     // Check if we can constant-fold information about the {receiver} (e.g.
    2640             :     // for asm.js-like code patterns).
    2641             :     base::Optional<JSTypedArrayRef> typed_array =
    2642        6904 :         GetTypedArrayConstant(broker(), receiver);
    2643        6904 :     if (typed_array.has_value()) {
    2644        1327 :       buffer = jsgraph()->Constant(typed_array->buffer());
    2645             :       length =
    2646        1327 :           jsgraph()->Constant(static_cast<double>(typed_array->length_value()));
    2647             : 
    2648             :       // Load the (known) base and external pointer for the {receiver}. The
    2649             :       // {external_pointer} might be invalid if the {buffer} was detached, so
    2650             :       // we need to make sure that any access is properly guarded.
    2651        1327 :       base_pointer = jsgraph()->ZeroConstant();
    2652             :       external_pointer =
    2653        1327 :           jsgraph()->PointerConstant(typed_array->elements_external_pointer());
    2654             :     } else {
    2655             :       // Load the {receiver}s length.
    2656        5577 :       length = effect = graph()->NewNode(
    2657       11154 :           simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()),
    2658             :           receiver, effect, control);
    2659             : 
    2660             :       // Load the buffer for the {receiver}.
    2661        5577 :       buffer = effect = graph()->NewNode(
    2662       11154 :           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
    2663             :           receiver, effect, control);
    2664             : 
    2665             :       // Load the elements for the {receiver}.
    2666        5577 :       Node* elements = effect = graph()->NewNode(
    2667       11154 :           simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
    2668             :           receiver, effect, control);
    2669             : 
    2670             :       // Load the base pointer for the {receiver}. This will always be Smi
    2671             :       // zero unless we allow on-heap TypedArrays, which is only the case
    2672             :       // for Chrome. Node and Electron both set this limit to 0. Setting
    2673             :       // the base to Smi zero here allows the EffectControlLinearizer to
    2674             :       // optimize away the tricky part of the access later.
    2675             :       if (V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP == 0) {
    2676             :         base_pointer = jsgraph()->ZeroConstant();
    2677             :       } else {
    2678        5577 :         base_pointer = effect = graph()->NewNode(
    2679             :             simplified()->LoadField(
    2680       11154 :                 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
    2681             :             elements, effect, control);
    2682             :       }
    2683             : 
    2684             :       // Load the external pointer for the {receiver}s {elements}.
    2685        5577 :       external_pointer = effect = graph()->NewNode(
    2686             :           simplified()->LoadField(
    2687       11154 :               AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
    2688             :           elements, effect, control);
    2689             :     }
    2690             : 
    2691             :     // See if we can skip the detaching check.
    2692        6904 :     if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
    2693             :       // Deopt if the {buffer} was detached.
    2694             :       // Note: A detached buffer leads to megamorphic feedback.
    2695         183 :       Node* buffer_bit_field = effect = graph()->NewNode(
    2696         366 :           simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
    2697             :           buffer, effect, control);
    2698         366 :       Node* check = graph()->NewNode(
    2699             :           simplified()->NumberEqual(),
    2700             :           graph()->NewNode(
    2701             :               simplified()->NumberBitwiseAnd(), buffer_bit_field,
    2702             :               jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
    2703             :           jsgraph()->ZeroConstant());
    2704         366 :       effect = graph()->NewNode(
    2705             :           simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached),
    2706             :           check, effect, control);
    2707             :     }
    2708             : 
    2709       13808 :     if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS ||
    2710        6904 :         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
    2711             :       // Only check that the {index} is in SignedSmall range. We do the actual
    2712             :       // bounds check below and just skip the property access if it's out of
    2713             :       // bounds for the {receiver}.
    2714         984 :       index = effect = graph()->NewNode(
    2715             :           simplified()->CheckSmi(VectorSlotPair()), index, effect, control);
    2716             : 
    2717             :       // Cast the {index} to Unsigned32 range, so that the bounds checks
    2718             :       // below are performed on unsigned values, which means that all the
    2719             :       // Negative32 values are treated as out-of-bounds.
    2720         492 :       index = graph()->NewNode(simplified()->NumberToUint32(), index);
    2721        6412 :     } else if (access_mode != AccessMode::kHas) {
    2722             :       // Check that the {index} is in the valid range for the {receiver}.
    2723             :       index = effect =
    2724       12824 :           graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
    2725             :                            length, effect, control);
    2726             :     }
    2727             : 
    2728             :     // Access the actual element.
    2729             :     ExternalArrayType external_array_type =
    2730        6904 :         GetArrayTypeFromElementsKind(elements_kind);
    2731        6904 :     switch (access_mode) {
    2732             :       case AccessMode::kLoad: {
    2733             :         // Check if we can return undefined for out-of-bounds loads.
    2734        3433 :         if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS) {
    2735             :           Node* check =
    2736         314 :               graph()->NewNode(simplified()->NumberLessThan(), index, length);
    2737         314 :           Node* branch = graph()->NewNode(
    2738             :               common()->Branch(BranchHint::kTrue,
    2739             :                                IsSafetyCheck::kCriticalSafetyCheck),
    2740             :               check, control);
    2741             : 
    2742         314 :           Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    2743             :           Node* etrue = effect;
    2744             :           Node* vtrue;
    2745             :           {
    2746             :             // Perform the actual load
    2747         314 :             vtrue = etrue = graph()->NewNode(
    2748             :                 simplified()->LoadTypedElement(external_array_type), buffer,
    2749             :                 base_pointer, external_pointer, index, etrue, if_true);
    2750             :           }
    2751             : 
    2752         314 :           Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    2753             :           Node* efalse = effect;
    2754             :           Node* vfalse;
    2755             :           {
    2756             :             // Materialize undefined for out-of-bounds loads.
    2757         314 :             vfalse = jsgraph()->UndefinedConstant();
    2758             :           }
    2759             : 
    2760         314 :           control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    2761             :           effect =
    2762         314 :               graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    2763             :           value =
    2764         314 :               graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    2765             :                                vtrue, vfalse, control);
    2766             :         } else {
    2767             :           // Perform the actual load.
    2768        3119 :           value = effect = graph()->NewNode(
    2769             :               simplified()->LoadTypedElement(external_array_type), buffer,
    2770             :               base_pointer, external_pointer, index, effect, control);
    2771             :         }
    2772             :         break;
    2773             :       }
    2774             :       case AccessMode::kStoreInLiteral:
    2775           0 :         UNREACHABLE();
    2776             :         break;
    2777             :       case AccessMode::kStore: {
    2778             :         // Ensure that the {value} is actually a Number or an Oddball,
    2779             :         // and truncate it to a Number appropriately.
    2780        6926 :         value = effect = graph()->NewNode(
    2781             :             simplified()->SpeculativeToNumber(
    2782             :                 NumberOperationHint::kNumberOrOddball, VectorSlotPair()),
    2783             :             value, effect, control);
    2784             : 
    2785             :         // Introduce the appropriate truncation for {value}. Currently we
    2786             :         // only need to do this for ClamedUint8Array {receiver}s, as the
    2787             :         // other truncations are implicit in the StoreTypedElement, but we
    2788             :         // might want to change that at some point.
    2789        3463 :         if (external_array_type == kExternalUint8ClampedArray) {
    2790         475 :           value = graph()->NewNode(simplified()->NumberToUint8Clamped(), value);
    2791             :         }
    2792             : 
    2793             :         // Check if we can skip the out-of-bounds store.
    2794        3463 :         if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
    2795             :           Node* check =
    2796         170 :               graph()->NewNode(simplified()->NumberLessThan(), index, length);
    2797         170 :           Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
    2798             :                                           check, control);
    2799             : 
    2800         170 :           Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    2801             :           Node* etrue = effect;
    2802             :           {
    2803             :             // Perform the actual store.
    2804         170 :             etrue = graph()->NewNode(
    2805             :                 simplified()->StoreTypedElement(external_array_type), buffer,
    2806             :                 base_pointer, external_pointer, index, value, etrue, if_true);
    2807             :           }
    2808             : 
    2809         170 :           Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    2810             :           Node* efalse = effect;
    2811             :           {
    2812             :             // Just ignore the out-of-bounds write.
    2813             :           }
    2814             : 
    2815         170 :           control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    2816             :           effect =
    2817         170 :               graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    2818             :         } else {
    2819             :           // Perform the actual store
    2820        3293 :           effect = graph()->NewNode(
    2821             :               simplified()->StoreTypedElement(external_array_type), buffer,
    2822             :               base_pointer, external_pointer, index, value, effect, control);
    2823             :         }
    2824             :         break;
    2825             :       }
    2826             :       case AccessMode::kHas:
    2827             :         // For has property on a typed array, all we need is a bounds check.
    2828             :         value = effect =
    2829           8 :             graph()->NewNode(simplified()->SpeculativeNumberLessThan(
    2830             :                                  NumberOperationHint::kSignedSmall),
    2831             :                              index, length, effect, control);
    2832           8 :         break;
    2833             :     }
    2834             :   } else {
    2835             :     // Load the elements for the {receiver}.
    2836       15781 :     Node* elements = effect = graph()->NewNode(
    2837       31562 :         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
    2838             :         effect, control);
    2839             : 
    2840             :     // Don't try to store to a copy-on-write backing store (unless supported by
    2841             :     // the store mode).
    2842       18123 :     if (access_mode == AccessMode::kStore &&
    2843       17178 :         IsSmiOrObjectElementsKind(elements_kind) &&
    2844             :         !IsCOWHandlingStoreMode(store_mode)) {
    2845        2844 :       effect = graph()->NewNode(
    2846             :           simplified()->CheckMaps(
    2847             :               CheckMapsFlag::kNone,
    2848             :               ZoneHandleSet<Map>(factory()->fixed_array_map())),
    2849             :           elements, effect, control);
    2850             :     }
    2851             : 
    2852             :     // Check if the {receiver} is a JSArray.
    2853       15781 :     bool receiver_is_jsarray = HasOnlyJSArrayMaps(broker(), receiver_maps);
    2854             : 
    2855             :     // Load the length of the {receiver}.
    2856             :     Node* length = effect =
    2857             :         receiver_is_jsarray
    2858       14025 :             ? graph()->NewNode(
    2859             :                   simplified()->LoadField(
    2860       43831 :                       AccessBuilder::ForJSArrayLength(elements_kind)),
    2861             :                   receiver, effect, control)
    2862        1756 :             : graph()->NewNode(
    2863       17537 :                   simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
    2864       17537 :                   elements, effect, control);
    2865             : 
    2866             :     // Check if we might need to grow the {elements} backing store.
    2867       15781 :     if (IsGrowStoreMode(store_mode)) {
    2868             :       // For growing stores we validate the {index} below.
    2869             :       DCHECK(access_mode == AccessMode::kStore ||
    2870             :              access_mode == AccessMode::kStoreInLiteral);
    2871       15258 :     } else if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
    2872         424 :                CanTreatHoleAsUndefined(receiver_maps)) {
    2873             :       // Check that the {index} is a valid array index, we do the actual
    2874             :       // bounds check below and just skip the store below if it's out of
    2875             :       // bounds for the {receiver}.
    2876         804 :       index = effect = graph()->NewNode(
    2877             :           simplified()->CheckBounds(VectorSlotPair()), index,
    2878             :           jsgraph()->Constant(Smi::kMaxValue), effect, control);
    2879             :     } else {
    2880             :       // Check that the {index} is in the valid range for the {receiver}.
    2881             :       index = effect =
    2882       28864 :           graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
    2883             :                            length, effect, control);
    2884             :     }
    2885             : 
    2886             :     // Compute the element access.
    2887             :     Type element_type = Type::NonInternal();
    2888             :     MachineType element_machine_type = MachineType::AnyTagged();
    2889       15781 :     if (IsDoubleElementsKind(elements_kind)) {
    2890             :       element_type = Type::Number();
    2891             :       element_machine_type = MachineType::Float64();
    2892       13240 :     } else if (IsSmiElementsKind(elements_kind)) {
    2893             :       element_type = Type::SignedSmall();
    2894             :       element_machine_type = MachineType::TaggedSigned();
    2895             :     }
    2896             :     ElementAccess element_access = {
    2897             :         kTaggedBase,       FixedArray::kHeaderSize,
    2898             :         element_type,      element_machine_type,
    2899             :         kFullWriteBarrier, LoadSensitivity::kCritical};
    2900             : 
    2901             :     // Access the actual element.
    2902       15781 :     if (access_mode == AccessMode::kLoad) {
    2903             :       // Compute the real element access type, which includes the hole in case
    2904             :       // of holey backing stores.
    2905       10481 :       if (IsHoleyElementsKind(elements_kind)) {
    2906             :         element_access.type =
    2907        2541 :             Type::Union(element_type, Type::Hole(), graph()->zone());
    2908             :       }
    2909       10481 :       if (elements_kind == HOLEY_ELEMENTS ||
    2910             :           elements_kind == HOLEY_SMI_ELEMENTS) {
    2911        1629 :         element_access.machine_type = MachineType::AnyTagged();
    2912             :       }
    2913             : 
    2914             :       // Check if we can return undefined for out-of-bounds loads.
    2915       10880 :       if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
    2916         399 :           CanTreatHoleAsUndefined(receiver_maps)) {
    2917             :         Node* check =
    2918         384 :             graph()->NewNode(simplified()->NumberLessThan(), index, length);
    2919         384 :         Node* branch = graph()->NewNode(
    2920             :             common()->Branch(BranchHint::kTrue,
    2921             :                              IsSafetyCheck::kCriticalSafetyCheck),
    2922             :             check, control);
    2923             : 
    2924         384 :         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    2925             :         Node* etrue = effect;
    2926             :         Node* vtrue;
    2927             :         {
    2928             :           // Perform the actual load
    2929             :           vtrue = etrue =
    2930         384 :               graph()->NewNode(simplified()->LoadElement(element_access),
    2931             :                                elements, index, etrue, if_true);
    2932             : 
    2933             :           // Handle loading from holey backing stores correctly, by either
    2934             :           // mapping the hole to undefined if possible, or deoptimizing
    2935             :           // otherwise.
    2936         384 :           if (elements_kind == HOLEY_ELEMENTS ||
    2937             :               elements_kind == HOLEY_SMI_ELEMENTS) {
    2938             :             // Turn the hole into undefined.
    2939          60 :             vtrue = graph()->NewNode(
    2940             :                 simplified()->ConvertTaggedHoleToUndefined(), vtrue);
    2941         324 :           } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
    2942             :             // Return the signaling NaN hole directly if all uses are
    2943             :             // truncating.
    2944          86 :             vtrue = etrue = graph()->NewNode(
    2945             :                 simplified()->CheckFloat64Hole(
    2946             :                     CheckFloat64HoleMode::kAllowReturnHole, VectorSlotPair()),
    2947             :                 vtrue, etrue, if_true);
    2948             :           }
    2949             :         }
    2950             : 
    2951         384 :         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    2952             :         Node* efalse = effect;
    2953             :         Node* vfalse;
    2954             :         {
    2955             :           // Materialize undefined for out-of-bounds loads.
    2956         384 :           vfalse = jsgraph()->UndefinedConstant();
    2957             :         }
    2958             : 
    2959         384 :         control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    2960             :         effect =
    2961         384 :             graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    2962             :         value =
    2963         384 :             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    2964             :                              vtrue, vfalse, control);
    2965             :       } else {
    2966             :         // Perform the actual load.
    2967             :         value = effect =
    2968       10097 :             graph()->NewNode(simplified()->LoadElement(element_access),
    2969             :                              elements, index, effect, control);
    2970             : 
    2971             :         // Handle loading from holey backing stores correctly, by either mapping
    2972             :         // the hole to undefined if possible, or deoptimizing otherwise.
    2973       10097 :         if (elements_kind == HOLEY_ELEMENTS ||
    2974             :             elements_kind == HOLEY_SMI_ELEMENTS) {
    2975             :           // Check if we are allowed to turn the hole into undefined.
    2976        1569 :           if (CanTreatHoleAsUndefined(receiver_maps)) {
    2977             :             // Turn the hole into undefined.
    2978        1459 :             value = graph()->NewNode(
    2979             :                 simplified()->ConvertTaggedHoleToUndefined(), value);
    2980             :           } else {
    2981             :             // Bailout if we see the hole.
    2982         110 :             value = effect = graph()->NewNode(
    2983             :                 simplified()->CheckNotTaggedHole(), value, effect, control);
    2984             :           }
    2985        8528 :         } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
    2986             :           // Perform the hole check on the result.
    2987             :           CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
    2988             :           // Check if we are allowed to return the hole directly.
    2989         869 :           if (CanTreatHoleAsUndefined(receiver_maps)) {
    2990             :             // Return the signaling NaN hole directly if all uses are
    2991             :             // truncating.
    2992             :             mode = CheckFloat64HoleMode::kAllowReturnHole;
    2993             :           }
    2994        1738 :           value = effect = graph()->NewNode(
    2995             :               simplified()->CheckFloat64Hole(mode, VectorSlotPair()), value,
    2996             :               effect, control);
    2997             :         }
    2998             :       }
    2999        5300 :     } else if (access_mode == AccessMode::kHas) {
    3000             :       // For packed arrays with NoElementsProctector valid, a bound check
    3001             :       // is equivalent to HasProperty.
    3002          41 :       value = effect = graph()->NewNode(simplified()->SpeculativeNumberLessThan(
    3003             :                                             NumberOperationHint::kSignedSmall),
    3004             :                                         index, length, effect, control);
    3005          41 :       if (IsHoleyElementsKind(elements_kind)) {
    3006             :         // If the index is in bounds, do a load and hole check.
    3007             : 
    3008          23 :         Node* branch = graph()->NewNode(common()->Branch(), value, control);
    3009             : 
    3010          23 :         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    3011             :         Node* efalse = effect;
    3012          23 :         Node* vfalse = jsgraph()->FalseConstant();
    3013             : 
    3014             :         element_access.type =
    3015          23 :             Type::Union(element_type, Type::Hole(), graph()->zone());
    3016             : 
    3017          23 :         if (elements_kind == HOLEY_ELEMENTS ||
    3018             :             elements_kind == HOLEY_SMI_ELEMENTS) {
    3019          23 :           element_access.machine_type = MachineType::AnyTagged();
    3020             :         }
    3021             : 
    3022          23 :         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    3023             :         Node* etrue = effect;
    3024             : 
    3025             :         Node* checked = etrue =
    3026          46 :             graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
    3027             :                              length, etrue, if_true);
    3028             : 
    3029             :         Node* element = etrue =
    3030          23 :             graph()->NewNode(simplified()->LoadElement(element_access),
    3031             :                              elements, checked, etrue, if_true);
    3032             : 
    3033             :         Node* vtrue;
    3034          23 :         if (CanTreatHoleAsUndefined(receiver_maps)) {
    3035           7 :           if (elements_kind == HOLEY_ELEMENTS ||
    3036             :               elements_kind == HOLEY_SMI_ELEMENTS) {
    3037             :             // Check if we are allowed to turn the hole into undefined.
    3038             :             // Turn the hole into undefined.
    3039           7 :             vtrue = graph()->NewNode(simplified()->ReferenceEqual(), element,
    3040             :                                      jsgraph()->TheHoleConstant());
    3041             :           } else {
    3042             :             vtrue =
    3043           0 :                 graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
    3044             :           }
    3045             : 
    3046             :           // has == !IsHole
    3047           7 :           vtrue = graph()->NewNode(simplified()->BooleanNot(), vtrue);
    3048             :         } else {
    3049          16 :           if (elements_kind == HOLEY_ELEMENTS ||
    3050             :               elements_kind == HOLEY_SMI_ELEMENTS) {
    3051             :             // Bailout if we see the hole.
    3052          16 :             etrue = graph()->NewNode(simplified()->CheckNotTaggedHole(),
    3053             :                                      element, etrue, if_true);
    3054             :           } else {
    3055           0 :             etrue = graph()->NewNode(
    3056             :                 simplified()->CheckFloat64Hole(
    3057             :                     CheckFloat64HoleMode::kNeverReturnHole, VectorSlotPair()),
    3058             :                 element, etrue, if_true);
    3059             :           }
    3060             : 
    3061          16 :           vtrue = jsgraph()->TrueConstant();
    3062             :         }
    3063             : 
    3064          23 :         control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    3065             :         effect =
    3066          23 :             graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    3067             :         value =
    3068          23 :             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    3069             :                              vtrue, vfalse, control);
    3070             :       }
    3071             :     } else {
    3072             :       DCHECK(access_mode == AccessMode::kStore ||
    3073             :              access_mode == AccessMode::kStoreInLiteral);
    3074        5259 :       if (IsSmiElementsKind(elements_kind)) {
    3075        2978 :         value = effect = graph()->NewNode(
    3076             :             simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
    3077        3770 :       } else if (IsDoubleElementsKind(elements_kind)) {
    3078             :         value = effect =
    3079        2240 :             graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
    3080             :                              effect, control);
    3081             :         // Make sure we do not store signalling NaNs into double arrays.
    3082        1120 :         value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
    3083             :       }
    3084             : 
    3085             :       // Ensure that copy-on-write backing store is writable.
    3086        5259 :       if (IsSmiOrObjectElementsKind(elements_kind) &&
    3087             :           store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
    3088             :         elements = effect =
    3089         168 :             graph()->NewNode(simplified()->EnsureWritableFastElements(),
    3090             :                              receiver, elements, effect, control);
    3091        5091 :       } else if (IsGrowStoreMode(store_mode)) {
    3092             :         // Determine the length of the {elements} backing store.
    3093         947 :         Node* elements_length = effect = graph()->NewNode(
    3094        1894 :             simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
    3095             :             elements, effect, control);
    3096             : 
    3097             :         // Validate the {index} depending on holeyness:
    3098             :         //
    3099             :         // For HOLEY_*_ELEMENTS the {index} must not exceed the {elements}
    3100             :         // backing store capacity plus the maximum allowed gap, as otherwise
    3101             :         // the (potential) backing store growth would normalize and thus
    3102             :         // the elements kind of the {receiver} would change to slow mode.
    3103             :         //
    3104             :         // For PACKED_*_ELEMENTS the {index} must be within the range
    3105             :         // [0,length+1[ to be valid. In case {index} equals {length},
    3106             :         // the {receiver} will be extended, but kept packed.
    3107             :         Node* limit =
    3108             :             IsHoleyElementsKind(elements_kind)
    3109         200 :                 ? graph()->NewNode(simplified()->NumberAdd(), elements_length,
    3110             :                                    jsgraph()->Constant(JSObject::kMaxGap))
    3111         747 :                 : graph()->NewNode(simplified()->NumberAdd(), length,
    3112         947 :                                    jsgraph()->OneConstant());
    3113             :         index = effect =
    3114        1894 :             graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
    3115             :                              limit, effect, control);
    3116             : 
    3117             :         // Grow {elements} backing store if necessary.
    3118             :         GrowFastElementsMode mode =
    3119             :             IsDoubleElementsKind(elements_kind)
    3120             :                 ? GrowFastElementsMode::kDoubleElements
    3121         947 :                 : GrowFastElementsMode::kSmiOrObjectElements;
    3122        1894 :         elements = effect = graph()->NewNode(
    3123             :             simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
    3124             :             receiver, elements, index, elements_length, effect, control);
    3125             : 
    3126             :         // If we didn't grow {elements}, it might still be COW, in which case we
    3127             :         // copy it now.
    3128         947 :         if (IsSmiOrObjectElementsKind(elements_kind) &&
    3129             :             store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) {
    3130             :           elements = effect =
    3131         760 :               graph()->NewNode(simplified()->EnsureWritableFastElements(),
    3132             :                                receiver, elements, effect, control);
    3133             :         }
    3134             : 
    3135             :         // Also update the "length" property if {receiver} is a JSArray.
    3136         947 :         if (receiver_is_jsarray) {
    3137             :           Node* check =
    3138         929 :               graph()->NewNode(simplified()->NumberLessThan(), index, length);
    3139         929 :           Node* branch = graph()->NewNode(common()->Branch(), check, control);
    3140             : 
    3141         929 :           Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    3142             :           Node* etrue = effect;
    3143             :           {
    3144             :             // We don't need to do anything, the {index} is within
    3145             :             // the valid bounds for the JSArray {receiver}.
    3146             :           }
    3147             : 
    3148         929 :           Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    3149             :           Node* efalse = effect;
    3150             :           {
    3151             :             // Update the JSArray::length field. Since this is observable,
    3152             :             // there must be no other check after this.
    3153         929 :             Node* new_length = graph()->NewNode(
    3154             :                 simplified()->NumberAdd(), index, jsgraph()->OneConstant());
    3155         929 :             efalse = graph()->NewNode(
    3156             :                 simplified()->StoreField(
    3157        1858 :                     AccessBuilder::ForJSArrayLength(elements_kind)),
    3158             :                 receiver, new_length, efalse, if_false);
    3159             :           }
    3160             : 
    3161         929 :           control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    3162             :           effect =
    3163         929 :               graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    3164             :         }
    3165             :       }
    3166             : 
    3167             :       // Perform the actual element access.
    3168        5259 :       effect = graph()->NewNode(simplified()->StoreElement(element_access),
    3169             :                                 elements, index, value, effect, control);
    3170             :     }
    3171             :   }
    3172             : 
    3173       22685 :   return ValueEffectControl(value, effect, control);
    3174             : }
    3175             : 
    3176         579 : Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
    3177             :     Node* receiver, Node* index, Node* length, Node** effect, Node** control,
    3178             :     KeyedAccessLoadMode load_mode) {
    3179         627 :   if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
    3180          48 :       dependencies()->DependOnNoElementsProtector()) {
    3181             :     // Ensure that the {index} is a valid String length.
    3182          96 :     index = *effect = graph()->NewNode(
    3183             :         simplified()->CheckBounds(VectorSlotPair()), index,
    3184          48 :         jsgraph()->Constant(String::kMaxLength), *effect, *control);
    3185             : 
    3186             :     // Load the single character string from {receiver} or yield
    3187             :     // undefined if the {index} is not within the valid bounds.
    3188             :     Node* check =
    3189          48 :         graph()->NewNode(simplified()->NumberLessThan(), index, length);
    3190             :     Node* branch =
    3191          48 :         graph()->NewNode(common()->Branch(BranchHint::kTrue,
    3192             :                                           IsSafetyCheck::kCriticalSafetyCheck),
    3193             :                          check, *control);
    3194             : 
    3195          48 :     Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
    3196             : 
    3197          48 :     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    3198             :     Node* etrue;
    3199             :     Node* vtrue = etrue =
    3200          48 :         graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
    3201             :                          masked_index, *effect, if_true);
    3202          48 :     vtrue = graph()->NewNode(simplified()->StringFromSingleCharCode(), vtrue);
    3203             : 
    3204          48 :     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    3205          48 :     Node* vfalse = jsgraph()->UndefinedConstant();
    3206             : 
    3207          96 :     *control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    3208             :     *effect =
    3209          96 :         graph()->NewNode(common()->EffectPhi(2), etrue, *effect, *control);
    3210          48 :     return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    3211          48 :                             vtrue, vfalse, *control);
    3212             :   } else {
    3213             :     // Ensure that {index} is less than {receiver} length.
    3214             :     index = *effect =
    3215        1062 :         graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
    3216         531 :                          length, *effect, *control);
    3217             : 
    3218         531 :     Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
    3219             : 
    3220             :     // Return the character from the {receiver} as single character string.
    3221             :     Node* value = *effect =
    3222         531 :         graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
    3223         531 :                          masked_index, *effect, *control);
    3224         531 :     value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value);
    3225         531 :     return value;
    3226             :   }
    3227             : }
    3228             : 
    3229        2298 : Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
    3230             :     const MapRef& map, Node* properties, Node* effect, Node* control) {
    3231             :   // TODO(bmeurer/jkummerow): Property deletions can undo map transitions
    3232             :   // while keeping the backing store around, meaning that even though the
    3233             :   // map might believe that objects have no unused property fields, there
    3234             :   // might actually be some. It would be nice to not create a new backing
    3235             :   // store in that case (i.e. when properties->length() >= new_length).
    3236             :   // However, introducing branches and Phi nodes here would make it more
    3237             :   // difficult for escape analysis to get rid of the backing stores used
    3238             :   // for intermediate states of chains of property additions. That makes
    3239             :   // it unclear what the best approach is here.
    3240             :   DCHECK_EQ(0, map.UnusedPropertyFields());
    3241             :   // Compute the length of the old {properties} and the new properties.
    3242        2298 :   int length = map.NextFreePropertyIndex() - map.GetInObjectProperties();
    3243        2298 :   int new_length = length + JSObject::kFieldsAdded;
    3244             :   // Collect the field values from the {properties}.
    3245             :   ZoneVector<Node*> values(zone());
    3246        2298 :   values.reserve(new_length);
    3247     1569144 :   for (int i = 0; i < length; ++i) {
    3248      783423 :     Node* value = effect = graph()->NewNode(
    3249     1566846 :         simplified()->LoadField(AccessBuilder::ForFixedArraySlot(i)),
    3250      783423 :         properties, effect, control);
    3251      783423 :     values.push_back(value);
    3252             :   }
    3253             :   // Initialize the new fields to undefined.
    3254       16086 :   for (int i = 0; i < JSObject::kFieldsAdded; ++i) {
    3255       13788 :     values.push_back(jsgraph()->UndefinedConstant());
    3256             :   }
    3257             : 
    3258             :   // Compute new length and hash.
    3259             :   Node* hash;
    3260        2298 :   if (length == 0) {
    3261         474 :     hash = graph()->NewNode(
    3262             :         common()->Select(MachineRepresentation::kTaggedSigned),
    3263             :         graph()->NewNode(simplified()->ObjectIsSmi(), properties), properties,
    3264             :         jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
    3265         237 :     hash = effect = graph()->NewNode(common()->TypeGuard(Type::SignedSmall()),
    3266             :                                      hash, effect, control);
    3267             :     hash =
    3268         237 :         graph()->NewNode(simplified()->NumberShiftLeft(), hash,
    3269             :                          jsgraph()->Constant(PropertyArray::HashField::kShift));
    3270             :   } else {
    3271        2061 :     hash = effect = graph()->NewNode(
    3272        4122 :         simplified()->LoadField(AccessBuilder::ForPropertyArrayLengthAndHash()),
    3273             :         properties, effect, control);
    3274             :     hash =
    3275        2061 :         graph()->NewNode(simplified()->NumberBitwiseAnd(), hash,
    3276             :                          jsgraph()->Constant(PropertyArray::HashField::kMask));
    3277             :   }
    3278        2298 :   Node* new_length_and_hash = graph()->NewNode(
    3279             :       simplified()->NumberBitwiseOr(), jsgraph()->Constant(new_length), hash);
    3280             :   // TDOO(jarin): Fix the typer to infer tighter bound for NumberBitwiseOr.
    3281             :   new_length_and_hash = effect =
    3282        2298 :       graph()->NewNode(common()->TypeGuard(Type::SignedSmall()),
    3283             :                        new_length_and_hash, effect, control);
    3284             : 
    3285             :   // Allocate and initialize the new properties.
    3286             :   AllocationBuilder a(jsgraph(), effect, control);
    3287             :   a.Allocate(PropertyArray::SizeFor(new_length), AllocationType::kYoung,
    3288        2298 :              Type::OtherInternal());
    3289        2298 :   a.Store(AccessBuilder::ForMap(), jsgraph()->PropertyArrayMapConstant());
    3290        2298 :   a.Store(AccessBuilder::ForPropertyArrayLengthAndHash(), new_length_and_hash);
    3291     1582932 :   for (int i = 0; i < new_length; ++i) {
    3292     1580634 :     a.Store(AccessBuilder::ForFixedArraySlot(i), values[i]);
    3293             :   }
    3294        4596 :   return a.Finish();
    3295             : }
    3296             : 
    3297         155 : Node* JSNativeContextSpecialization::BuildCheckEqualsName(Handle<Name> name,
    3298             :                                                           Node* value,
    3299             :                                                           Node* effect,
    3300             :                                                           Node* control) {
    3301             :   DCHECK(name->IsUniqueName());
    3302             :   Operator const* const op =
    3303             :       name->IsSymbol() ? simplified()->CheckEqualsSymbol()
    3304         155 :                        : simplified()->CheckEqualsInternalizedString();
    3305         310 :   return graph()->NewNode(op, jsgraph()->HeapConstant(name), value, effect,
    3306         155 :                           control);
    3307             : }
    3308             : 
    3309        3284 : bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
    3310             :     MapHandles const& receiver_maps) {
    3311             :   // Check if all {receiver_maps} have one of the initial Array.prototype
    3312             :   // or Object.prototype objects as their prototype (in any of the current
    3313             :   // native contexts, as the global Array protector works isolate-wide).
    3314        7022 :   for (Handle<Map> map : receiver_maps) {
    3315             :     MapRef receiver_map(broker(), map);
    3316        3979 :     if (!FLAG_concurrent_inlining) receiver_map.SerializePrototype();
    3317        3979 :     ObjectRef receiver_prototype = receiver_map.prototype();
    3318       11937 :     if (!receiver_prototype.IsJSObject() ||
    3319       11937 :         !broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) {
    3320         241 :       return false;
    3321             :     }
    3322             :   }
    3323             : 
    3324             :   // Check if the array prototype chain is intact.
    3325        3043 :   return dependencies()->DependOnNoElementsProtector();
    3326             : }
    3327             : 
    3328             : namespace {
    3329      163575 : void TryUpdateThenDropDeprecated(Isolate* isolate, MapHandles* maps) {
    3330      346953 :   for (auto it = maps->begin(); it != maps->end();) {
    3331      366756 :     if (Map::TryUpdate(isolate, *it).ToHandle(&*it)) {
    3332             :       DCHECK(!(*it)->is_deprecated());
    3333             :       ++it;
    3334             :     } else {
    3335             :       it = maps->erase(it);
    3336             :     }
    3337             :   }
    3338      163575 : }
    3339             : }  // namespace
    3340             : 
    3341      592240 : bool JSNativeContextSpecialization::ExtractReceiverMaps(
    3342             :     Node* receiver, Node* effect, FeedbackNexus const& nexus,
    3343             :     MapHandles* receiver_maps) {
    3344             :   DCHECK(receiver_maps->empty());
    3345      592241 :   if (nexus.IsUninitialized()) return true;
    3346             : 
    3347             :   // See if we can infer a concrete type for the {receiver}. Solely relying on
    3348             :   // the inference is not safe for keyed stores, because we would potentially
    3349             :   // miss out on transitions that need to be performed.
    3350             :   {
    3351             :     FeedbackSlotKind kind = nexus.kind();
    3352             :     bool use_inference =
    3353      176188 :         !IsKeyedStoreICKind(kind) && !IsStoreInArrayLiteralICKind(kind);
    3354      176188 :     if (use_inference && InferReceiverMaps(receiver, effect, receiver_maps)) {
    3355       78840 :       TryUpdateThenDropDeprecated(isolate(), receiver_maps);
    3356       78840 :       return true;
    3357             :     }
    3358             :   }
    3359             : 
    3360             :   // Try to extract some maps from the {nexus}.
    3361       97348 :   if (nexus.ExtractMaps(receiver_maps) != 0) {
    3362             :     // Try to filter impossible candidates based on inferred root map.
    3363             :     Handle<Map> root_map;
    3364      169470 :     if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
    3365             :       DCHECK(!root_map->is_abandoned_prototype_map());
    3366             :       Isolate* isolate = this->isolate();
    3367             :       receiver_maps->erase(
    3368             :           std::remove_if(receiver_maps->begin(), receiver_maps->end(),
    3369       12018 :                          [root_map, isolate](Handle<Map> map) {
    3370       12018 :                            return map->is_abandoned_prototype_map() ||
    3371        6002 :                                   map->FindRootMap(isolate) != *root_map;
    3372        6016 :                          }),
    3373             :           receiver_maps->end());
    3374             :     }
    3375       84735 :     TryUpdateThenDropDeprecated(isolate(), receiver_maps);
    3376             :     return true;
    3377             :   }
    3378             : 
    3379             :   return false;
    3380             : }
    3381             : 
    3382      166400 : bool JSNativeContextSpecialization::InferReceiverMaps(
    3383             :     Node* receiver, Node* effect, MapHandles* receiver_maps) {
    3384             :   ZoneHandleSet<Map> maps;
    3385             :   NodeProperties::InferReceiverMapsResult result =
    3386      166400 :       NodeProperties::InferReceiverMaps(broker(), receiver, effect, &maps);
    3387      166400 :   if (result == NodeProperties::kReliableReceiverMaps) {
    3388       61812 :     for (size_t i = 0; i < maps.size(); ++i) {
    3389       42238 :       receiver_maps->push_back(maps[i]);
    3390             :     }
    3391             :     return true;
    3392      146826 :   } else if (result == NodeProperties::kUnreliableReceiverMaps) {
    3393             :     // For untrusted receiver maps, we can still use the information
    3394             :     // if the maps are stable.
    3395      185312 :     for (size_t i = 0; i < maps.size(); ++i) {
    3396             :       MapRef map(broker(), maps[i]);
    3397       65992 :       if (!map.is_stable()) return false;
    3398             :     }
    3399      178540 :     for (size_t i = 0; i < maps.size(); ++i) {
    3400      119274 :       receiver_maps->push_back(maps[i]);
    3401             :     }
    3402             :     return true;
    3403             :   }
    3404             :   return false;
    3405             : }
    3406             : 
    3407       84735 : MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
    3408             :     Node* receiver) {
    3409             :   HeapObjectMatcher m(receiver);
    3410       84735 :   if (m.HasValue()) {
    3411       11404 :     return handle(m.Value()->map()->FindRootMap(isolate()), isolate());
    3412       79033 :   } else if (m.IsJSCreate()) {
    3413             :     base::Optional<MapRef> initial_map =
    3414        8287 :         NodeProperties::GetJSCreateMap(broker(), receiver);
    3415        8287 :     if (initial_map.has_value()) {
    3416             :       DCHECK_EQ(*initial_map->object(),
    3417             :                 initial_map->object()->FindRootMap(isolate()));
    3418         207 :       return initial_map->object();
    3419             :     }
    3420             :   }
    3421       78826 :   return MaybeHandle<Map>();
    3422             : }
    3423             : 
    3424           0 : Graph* JSNativeContextSpecialization::graph() const {
    3425           0 :   return jsgraph()->graph();
    3426             : }
    3427             : 
    3428           0 : Isolate* JSNativeContextSpecialization::isolate() const {
    3429           0 :   return jsgraph()->isolate();
    3430             : }
    3431             : 
    3432           0 : Factory* JSNativeContextSpecialization::factory() const {
    3433           0 :   return isolate()->factory();
    3434             : }
    3435             : 
    3436           0 : CommonOperatorBuilder* JSNativeContextSpecialization::common() const {
    3437           0 :   return jsgraph()->common();
    3438             : }
    3439             : 
    3440           0 : JSOperatorBuilder* JSNativeContextSpecialization::javascript() const {
    3441           0 :   return jsgraph()->javascript();
    3442             : }
    3443             : 
    3444           0 : SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
    3445           0 :   return jsgraph()->simplified();
    3446             : }
    3447             : 
    3448             : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
    3449             : 
    3450             : }  // namespace compiler
    3451             : }  // namespace internal
    3452      120216 : }  // namespace v8

Generated by: LCOV version 1.10