LCOV - code coverage report
Current view: top level - src/compiler - js-native-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1090 1120 97.3 %
Date: 2019-01-20 Functions: 55 61 90.2 %

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

Generated by: LCOV version 1.10