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