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