xref: /third_party/node/deps/v8/src/ic/ic.cc (revision 1cb0ef41)
1// Copyright 2012 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/ic/ic.h"
6
7#include "src/api/api-arguments-inl.h"
8#include "src/api/api.h"
9#include "src/ast/ast.h"
10#include "src/base/bits.h"
11#include "src/base/logging.h"
12#include "src/builtins/accessors.h"
13#include "src/common/assert-scope.h"
14#include "src/common/globals.h"
15#include "src/execution/arguments-inl.h"
16#include "src/execution/execution.h"
17#include "src/execution/frames-inl.h"
18#include "src/execution/isolate-inl.h"
19#include "src/execution/protectors-inl.h"
20#include "src/execution/tiering-manager.h"
21#include "src/handles/handles-inl.h"
22#include "src/ic/call-optimization.h"
23#include "src/ic/handler-configuration-inl.h"
24#include "src/ic/ic-inl.h"
25#include "src/ic/ic-stats.h"
26#include "src/ic/stub-cache.h"
27#include "src/numbers/conversions.h"
28#include "src/objects/api-callbacks.h"
29#include "src/objects/data-handler-inl.h"
30#include "src/objects/field-type.h"
31#include "src/objects/hash-table-inl.h"
32#include "src/objects/heap-number-inl.h"
33#include "src/objects/instance-type.h"
34#include "src/objects/js-array-buffer-inl.h"
35#include "src/objects/js-array-inl.h"
36#include "src/objects/megadom-handler.h"
37#include "src/objects/module-inl.h"
38#include "src/objects/property-descriptor.h"
39#include "src/objects/prototype.h"
40#include "src/objects/struct-inl.h"
41#include "src/runtime/runtime-utils.h"
42#include "src/runtime/runtime.h"
43#include "src/tracing/trace-event.h"
44#include "src/tracing/tracing-category-observer.h"
45#include "src/utils/ostreams.h"
46
47#if V8_ENABLE_WEBASSEMBLY
48#include "src/wasm/struct-types.h"
49#endif  // V8_ENABLE_WEBASSEMBLY
50
51namespace v8 {
52namespace internal {
53
54// Aliases to avoid having to repeat the class.
55// With C++20 we can use "using" to introduce scoped enums.
56constexpr InlineCacheState NO_FEEDBACK = InlineCacheState::NO_FEEDBACK;
57constexpr InlineCacheState UNINITIALIZED = InlineCacheState::UNINITIALIZED;
58constexpr InlineCacheState MONOMORPHIC = InlineCacheState::MONOMORPHIC;
59constexpr InlineCacheState RECOMPUTE_HANDLER =
60    InlineCacheState::RECOMPUTE_HANDLER;
61constexpr InlineCacheState POLYMORPHIC = InlineCacheState::POLYMORPHIC;
62constexpr InlineCacheState MEGAMORPHIC = InlineCacheState::MEGAMORPHIC;
63constexpr InlineCacheState MEGADOM = InlineCacheState::MEGADOM;
64constexpr InlineCacheState GENERIC = InlineCacheState::GENERIC;
65
66char IC::TransitionMarkFromState(IC::State state) {
67  switch (state) {
68    case NO_FEEDBACK:
69      return 'X';
70    case UNINITIALIZED:
71      return '0';
72    case MONOMORPHIC:
73      return '1';
74    case RECOMPUTE_HANDLER:
75      return '^';
76    case POLYMORPHIC:
77      return 'P';
78    case MEGAMORPHIC:
79      return 'N';
80    case MEGADOM:
81      return 'D';
82    case GENERIC:
83      return 'G';
84  }
85  UNREACHABLE();
86}
87
88namespace {
89
90const char* GetModifier(KeyedAccessLoadMode mode) {
91  if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB";
92  return "";
93}
94
95const char* GetModifier(KeyedAccessStoreMode mode) {
96  switch (mode) {
97    case STORE_HANDLE_COW:
98      return ".COW";
99    case STORE_AND_GROW_HANDLE_COW:
100      return ".STORE+COW";
101    case STORE_IGNORE_OUT_OF_BOUNDS:
102      return ".IGNORE_OOB";
103    case STANDARD_STORE:
104      return "";
105  }
106  UNREACHABLE();
107}
108
109}  // namespace
110
111void IC::TraceIC(const char* type, Handle<Object> name) {
112  if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return;
113  State new_state =
114      (state() == NO_FEEDBACK) ? NO_FEEDBACK : nexus()->ic_state();
115  TraceIC(type, name, state(), new_state);
116}
117
118void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
119                 State new_state) {
120  if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return;
121
122  Handle<Map> map = lookup_start_object_map();  // Might be empty.
123
124  const char* modifier = "";
125  if (state() == NO_FEEDBACK) {
126    modifier = "";
127  } else if (IsKeyedLoadIC()) {
128    KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
129    modifier = GetModifier(mode);
130  } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralIC() ||
131             IsDefineKeyedOwnIC()) {
132    KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
133    modifier = GetModifier(mode);
134  }
135
136  bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralIC();
137
138  if (!(TracingFlags::ic_stats.load(std::memory_order_relaxed) &
139        v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
140    LOG(isolate(), ICEvent(type, keyed_prefix, map, name,
141                           TransitionMarkFromState(old_state),
142                           TransitionMarkFromState(new_state), modifier,
143                           slow_stub_reason_));
144    return;
145  }
146
147  JavaScriptFrameIterator it(isolate());
148  JavaScriptFrame* frame = it.frame();
149
150  DisallowGarbageCollection no_gc;
151  JSFunction function = frame->function();
152
153  ICStats::instance()->Begin();
154  ICInfo& ic_info = ICStats::instance()->Current();
155  ic_info.type = keyed_prefix ? "Keyed" : "";
156  ic_info.type += type;
157
158  int code_offset = 0;
159  AbstractCode code = function.abstract_code(isolate_);
160  if (function.ActiveTierIsIgnition()) {
161    code_offset = InterpretedFrame::GetBytecodeOffset(frame->fp());
162  } else if (function.ActiveTierIsBaseline()) {
163    // TODO(pthier): AbstractCode should fully support Baseline code.
164    BaselineFrame* baseline_frame = BaselineFrame::cast(frame);
165    code_offset = baseline_frame->GetBytecodeOffset();
166    code = AbstractCode::cast(baseline_frame->GetBytecodeArray());
167  } else {
168    code_offset = static_cast<int>(frame->pc() - function.code_entry_point());
169  }
170  JavaScriptFrame::CollectFunctionAndOffsetForICStats(function, code,
171                                                      code_offset);
172
173  // Reserve enough space for IC transition state, the longest length is 17.
174  ic_info.state.reserve(17);
175  ic_info.state = "(";
176  ic_info.state += TransitionMarkFromState(old_state);
177  ic_info.state += "->";
178  ic_info.state += TransitionMarkFromState(new_state);
179  ic_info.state += modifier;
180  ic_info.state += ")";
181  if (!map.is_null()) {
182    ic_info.map = reinterpret_cast<void*>(map->ptr());
183    ic_info.is_dictionary_map = map->is_dictionary_map();
184    ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
185    ic_info.instance_type = std::to_string(map->instance_type());
186  } else {
187    ic_info.map = nullptr;
188  }
189  // TODO(lpy) Add name as key field in ICStats.
190  ICStats::instance()->End();
191}
192
193IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
194       FeedbackSlotKind kind)
195    : isolate_(isolate),
196      vector_set_(false),
197      kind_(kind),
198      target_maps_set_(false),
199      slow_stub_reason_(nullptr),
200      nexus_(vector, slot) {
201  DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind());
202  state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.ic_state();
203  old_state_ = state_;
204}
205
206static void LookupForRead(LookupIterator* it, bool is_has_property) {
207  for (; it->IsFound(); it->Next()) {
208    switch (it->state()) {
209      case LookupIterator::NOT_FOUND:
210      case LookupIterator::TRANSITION:
211        UNREACHABLE();
212      case LookupIterator::JSPROXY:
213        return;
214      case LookupIterator::INTERCEPTOR: {
215        // If there is a getter, return; otherwise loop to perform the lookup.
216        Handle<JSObject> holder = it->GetHolder<JSObject>();
217        if (!holder->GetNamedInterceptor().getter().IsUndefined(
218                it->isolate())) {
219          return;
220        }
221        if (is_has_property &&
222            !holder->GetNamedInterceptor().query().IsUndefined(it->isolate())) {
223          return;
224        }
225        break;
226      }
227      case LookupIterator::ACCESS_CHECK:
228        // ICs know how to perform access checks on global proxies.
229        if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
230          break;
231        }
232        return;
233      case LookupIterator::ACCESSOR:
234      case LookupIterator::INTEGER_INDEXED_EXOTIC:
235      case LookupIterator::DATA:
236        return;
237    }
238  }
239}
240
241bool IC::ShouldRecomputeHandler(Handle<String> name) {
242  if (!RecomputeHandlerForName(name)) return false;
243
244  // This is a contextual access, always just update the handler and stay
245  // monomorphic.
246  if (IsGlobalIC()) return true;
247
248  MaybeObjectHandle maybe_handler =
249      nexus()->FindHandlerForMap(lookup_start_object_map());
250
251  // The current map wasn't handled yet. There's no reason to stay monomorphic,
252  // *unless* we're moving from a deprecated map to its replacement, or
253  // to a more general elements kind.
254  // TODO(verwaest): Check if the current map is actually what the old map
255  // would transition to.
256  if (maybe_handler.is_null()) {
257    if (!lookup_start_object_map()->IsJSObjectMap()) return false;
258    Map first_map = FirstTargetMap();
259    if (first_map.is_null()) return false;
260    Handle<Map> old_map(first_map, isolate());
261    if (old_map->is_deprecated()) return true;
262    return IsMoreGeneralElementsKindTransition(
263        old_map->elements_kind(), lookup_start_object_map()->elements_kind());
264  }
265
266  return true;
267}
268
269bool IC::RecomputeHandlerForName(Handle<Object> name) {
270  if (is_keyed()) {
271    // Determine whether the failure is due to a name failure.
272    if (!name->IsName()) return false;
273    Name stub_name = nexus()->GetName();
274    if (*name != stub_name) return false;
275  }
276
277  return true;
278}
279
280void IC::UpdateState(Handle<Object> lookup_start_object, Handle<Object> name) {
281  if (state() == NO_FEEDBACK) return;
282  update_lookup_start_object_map(lookup_start_object);
283  if (!name->IsString()) return;
284  if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
285  if (lookup_start_object->IsNullOrUndefined(isolate())) return;
286
287  // Remove the target from the code cache if it became invalid
288  // because of changes in the prototype chain to avoid hitting it
289  // again.
290  if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
291    MarkRecomputeHandler(name);
292  }
293}
294
295MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object,
296                                  Handle<Object> key) {
297  HandleScope scope(isolate());
298  THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
299}
300
301MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
302  HandleScope scope(isolate());
303  THROW_NEW_ERROR(
304      isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
305}
306
307void IC::OnFeedbackChanged(const char* reason) {
308  vector_set_ = true;
309  FeedbackVector vector = nexus()->vector();
310  FeedbackSlot slot = nexus()->slot();
311  OnFeedbackChanged(isolate(), vector, slot, reason);
312}
313
314// static
315void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector vector,
316                           FeedbackSlot slot, const char* reason) {
317  if (FLAG_trace_opt_verbose) {
318    if (vector.profiler_ticks() != 0) {
319      StdoutStream os;
320      os << "[resetting ticks for ";
321      vector.shared_function_info().ShortPrint(os);
322      os << " from " << vector.profiler_ticks()
323         << " due to IC change: " << reason << "]" << std::endl;
324    }
325  }
326  vector.set_profiler_ticks(0);
327
328#ifdef V8_TRACE_FEEDBACK_UPDATES
329  if (FLAG_trace_feedback_updates) {
330    int slot_count = vector.metadata().slot_count();
331    StdoutStream os;
332    if (slot.IsInvalid()) {
333      os << "[Feedback slots in ";
334    } else {
335      os << "[Feedback slot " << slot.ToInt() << "/" << slot_count << " in ";
336    }
337    vector.shared_function_info().ShortPrint(os);
338    if (slot.IsInvalid()) {
339      os << " updated - ";
340    } else {
341      os << " updated to ";
342      vector.FeedbackSlotPrint(os, slot);
343      os << " - ";
344    }
345    os << reason << "]" << std::endl;
346  }
347#endif
348
349  isolate->tiering_manager()->NotifyICChanged();
350}
351
352namespace {
353
354bool MigrateDeprecated(Isolate* isolate, Handle<Object> object) {
355  if (!object->IsJSObject()) return false;
356  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
357  if (!receiver->map().is_deprecated()) return false;
358  JSObject::MigrateInstance(isolate, receiver);
359  return true;
360}
361
362}  // namespace
363
364bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
365  DCHECK_EQ(MEGAMORPHIC, new_state);
366  DCHECK_IMPLIES(!is_keyed(), key->IsName());
367  // Even though we don't change the feedback data, we still want to reset the
368  // profiler ticks. Real-world observations suggest that optimizing these
369  // functions doesn't improve performance.
370  bool changed = nexus()->ConfigureMegamorphic(
371      key->IsName() ? IcCheckType::kProperty : IcCheckType::kElement);
372  OnFeedbackChanged("Megamorphic");
373  return changed;
374}
375
376void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
377                              Handle<Object> handler) {
378  ConfigureVectorState(name, map, MaybeObjectHandle(handler));
379}
380
381void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
382                              const MaybeObjectHandle& handler) {
383  if (IsGlobalIC()) {
384    nexus()->ConfigureHandlerMode(handler);
385  } else {
386    // Non-keyed ICs don't track the name explicitly.
387    if (!is_keyed()) name = Handle<Name>::null();
388    nexus()->ConfigureMonomorphic(name, map, handler);
389  }
390
391  OnFeedbackChanged(IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
392}
393
394void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
395                              MaybeObjectHandles* handlers) {
396  DCHECK(!IsGlobalIC());
397  std::vector<MapAndHandler> maps_and_handlers;
398  DCHECK_EQ(maps.size(), handlers->size());
399  for (size_t i = 0; i < maps.size(); i++) {
400    maps_and_handlers.push_back(MapAndHandler(maps[i], handlers->at(i)));
401  }
402  ConfigureVectorState(name, maps_and_handlers);
403}
404
405void IC::ConfigureVectorState(
406    Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
407  DCHECK(!IsGlobalIC());
408  // Non-keyed ICs don't track the name explicitly.
409  if (!is_keyed()) name = Handle<Name>::null();
410  nexus()->ConfigurePolymorphic(name, maps_and_handlers);
411
412  OnFeedbackChanged("Polymorphic");
413}
414
415MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name,
416                                 bool update_feedback,
417                                 Handle<Object> receiver) {
418  bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic && update_feedback;
419
420  if (receiver.is_null()) {
421    receiver = object;
422  }
423
424  // If the object is undefined or null it's illegal to try to get any
425  // of its properties; throw a TypeError in that case.
426  if (IsAnyHas() ? !object->IsJSReceiver()
427                 : object->IsNullOrUndefined(isolate())) {
428    if (use_ic) {
429      // Ensure the IC state progresses.
430      TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
431      update_lookup_start_object_map(object);
432      SetCache(name, LoadHandler::LoadSlow(isolate()));
433      TraceIC("LoadIC", name);
434    }
435
436    if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
437      return isolate()->Throw<Object>(
438          ErrorUtils::NewIteratorError(isolate(), object));
439    }
440
441    if (IsAnyHas()) {
442      return TypeError(MessageTemplate::kInvalidInOperatorUse, object, name);
443    } else {
444      DCHECK(object->IsNullOrUndefined(isolate()));
445      ErrorUtils::ThrowLoadFromNullOrUndefined(isolate(), object, name);
446      return MaybeHandle<Object>();
447    }
448  }
449
450  // If we encounter an object with a deprecated map, we want to update the
451  // feedback vector with the migrated map.
452  // Mark ourselves as RECOMPUTE_HANDLER so that we don't turn megamorphic due
453  // to seeing the same map and handler.
454  if (MigrateDeprecated(isolate(), object)) {
455    UpdateState(object, name);
456  }
457
458  JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
459  update_lookup_start_object_map(object);
460
461  PropertyKey key(isolate(), name);
462  LookupIterator it = LookupIterator(isolate(), receiver, key, object);
463
464  // Named lookup in the object.
465  LookupForRead(&it, IsAnyHas());
466
467  if (name->IsPrivate()) {
468    Handle<Symbol> private_symbol = Handle<Symbol>::cast(name);
469    if (!IsAnyHas() && private_symbol->is_private_name() && !it.IsFound()) {
470      Handle<String> name_string(String::cast(private_symbol->description()),
471                                 isolate());
472      if (private_symbol->is_private_brand()) {
473        Handle<String> class_name =
474            (name_string->length() == 0)
475                ? isolate()->factory()->anonymous_string()
476                : name_string;
477        return TypeError(MessageTemplate::kInvalidPrivateBrandInstance, object,
478                         class_name);
479      }
480      return TypeError(MessageTemplate::kInvalidPrivateMemberRead, object,
481                       name_string);
482    }
483
484    // IC handling of private symbols/fields lookup on JSProxy is not
485    // supported.
486    if (object->IsJSProxy()) {
487      use_ic = false;
488    }
489  }
490
491  if (it.IsFound() || !ShouldThrowReferenceError()) {
492    // Update inline cache and stub cache.
493    if (use_ic) {
494      UpdateCaches(&it);
495    } else if (state() == NO_FEEDBACK) {
496      // Tracing IC stats
497      IsLoadGlobalIC() ? TraceIC("LoadGlobalIC", name)
498                       : TraceIC("LoadIC", name);
499    }
500
501    if (IsAnyHas()) {
502      // Named lookup in the object.
503      Maybe<bool> maybe = JSReceiver::HasProperty(&it);
504      if (maybe.IsNothing()) return MaybeHandle<Object>();
505      return maybe.FromJust() ? ReadOnlyRoots(isolate()).true_value_handle()
506                              : ReadOnlyRoots(isolate()).false_value_handle();
507    }
508
509    // Get the property.
510    Handle<Object> result;
511
512    ASSIGN_RETURN_ON_EXCEPTION(
513        isolate(), result, Object::GetProperty(&it, IsLoadGlobalIC()), Object);
514    if (it.IsFound()) {
515      return result;
516    } else if (!ShouldThrowReferenceError()) {
517      return result;
518    }
519  }
520  return ReferenceError(name);
521}
522
523MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name,
524                                       bool update_feedback) {
525  Handle<JSGlobalObject> global = isolate()->global_object();
526
527  if (name->IsString()) {
528    // Look up in script context table.
529    Handle<String> str_name = Handle<String>::cast(name);
530    Handle<ScriptContextTable> script_contexts(
531        global->native_context().script_context_table(), isolate());
532
533    VariableLookupResult lookup_result;
534    if (script_contexts->Lookup(str_name, &lookup_result)) {
535      Handle<Context> script_context = ScriptContextTable::GetContext(
536          isolate(), script_contexts, lookup_result.context_index);
537
538      Handle<Object> result(script_context->get(lookup_result.slot_index),
539                            isolate());
540
541      if (result->IsTheHole(isolate())) {
542        // Do not install stubs and stay pre-monomorphic for
543        // uninitialized accesses.
544        THROW_NEW_ERROR(
545            isolate(),
546            NewReferenceError(MessageTemplate::kAccessedUninitializedVariable,
547                              name),
548            Object);
549      }
550
551      bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic && update_feedback;
552      if (use_ic) {
553        // 'const' Variables are mutable if REPL mode is enabled. This disables
554        // compiler inlining for all 'const' variables declared in REPL mode.
555        if (nexus()->ConfigureLexicalVarMode(
556                lookup_result.context_index, lookup_result.slot_index,
557                (lookup_result.mode == VariableMode::kConst &&
558                 !lookup_result.is_repl_mode))) {
559          TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
560        } else {
561          // Given combination of indices can't be encoded, so use slow stub.
562          TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
563          SetCache(name, LoadHandler::LoadSlow(isolate()));
564        }
565        TraceIC("LoadGlobalIC", name);
566      } else if (state() == NO_FEEDBACK) {
567        TraceIC("LoadGlobalIC", name);
568      }
569      return result;
570    }
571  }
572  return LoadIC::Load(global, name, update_feedback);
573}
574
575static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
576                                       Handle<Map> new_receiver_map) {
577  DCHECK(!new_receiver_map.is_null());
578  for (Handle<Map> map : *receiver_maps) {
579    if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
580      return false;
581    }
582  }
583  receiver_maps->push_back(new_receiver_map);
584  return true;
585}
586
587static bool AddOneReceiverMapIfMissing(
588    std::vector<MapAndHandler>* receiver_maps_and_handlers,
589    Handle<Map> new_receiver_map) {
590  DCHECK(!new_receiver_map.is_null());
591  if (new_receiver_map->is_deprecated()) return false;
592  for (MapAndHandler map_and_handler : *receiver_maps_and_handlers) {
593    Handle<Map> map = map_and_handler.first;
594    if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
595      return false;
596    }
597  }
598  receiver_maps_and_handlers->push_back(
599      MapAndHandler(new_receiver_map, MaybeObjectHandle()));
600  return true;
601}
602
603bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
604  if (!FLAG_enable_mega_dom_ic) return false;
605
606  // TODO(gsathya): Enable fuzzing once this feature is more stable.
607  if (FLAG_fuzzing) return false;
608
609  // TODO(gsathya): Support KeyedLoadIC, StoreIC and KeyedStoreIC.
610  if (!IsLoadIC()) return false;
611
612  // Check if DOM protector cell is valid.
613  if (!Protectors::IsMegaDOMIntact(isolate())) return false;
614
615  // Check if current lookup object is an API object
616  Handle<Map> map = lookup_start_object_map();
617  if (!InstanceTypeChecker::IsJSApiObject(map->instance_type())) return false;
618
619  Handle<Object> accessor_obj;
620  // TODO(gsathya): Check if there are overloads possible for this accessor and
621  // transition only if it isn't possible.
622  if (!accessor().ToHandle(&accessor_obj)) return false;
623
624  // TODO(gsathya): This is also created in IC::ComputeHandler, find a way to
625  // reuse it here.
626  CallOptimization call_optimization(isolate(), accessor_obj);
627
628  // Check if accessor is an API function
629  if (!call_optimization.is_simple_api_call()) return false;
630
631  // Check if accessor requires access checks
632  if (call_optimization.accept_any_receiver()) return false;
633
634  // Check if accessor requires signature checks
635  if (!call_optimization.requires_signature_check()) return false;
636
637  // Check if the receiver is the holder
638  CallOptimization::HolderLookup holder_lookup;
639  call_optimization.LookupHolderOfExpectedType(isolate(), map, &holder_lookup);
640  if (holder_lookup != CallOptimization::kHolderIsReceiver) return false;
641
642  Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
643                                   isolate());
644
645  Handle<MegaDomHandler> new_handler = isolate()->factory()->NewMegaDomHandler(
646      MaybeObjectHandle::Weak(accessor_obj),
647      MaybeObjectHandle::Weak(accessor_context));
648  nexus()->ConfigureMegaDOM(MaybeObjectHandle(new_handler));
649  return true;
650}
651
652bool IC::UpdatePolymorphicIC(Handle<Name> name,
653                             const MaybeObjectHandle& handler) {
654  DCHECK(IsHandler(*handler));
655  if (is_keyed() && state() != RECOMPUTE_HANDLER) {
656    if (nexus()->GetName() != *name) return false;
657  }
658  Handle<Map> map = lookup_start_object_map();
659
660  std::vector<MapAndHandler> maps_and_handlers;
661  maps_and_handlers.reserve(FLAG_max_valid_polymorphic_map_count);
662  int deprecated_maps = 0;
663  int handler_to_overwrite = -1;
664
665  {
666    DisallowGarbageCollection no_gc;
667    int i = 0;
668    for (FeedbackIterator it(nexus()); !it.done(); it.Advance()) {
669      if (it.handler()->IsCleared()) continue;
670      MaybeObjectHandle existing_handler = handle(it.handler(), isolate());
671      Handle<Map> existing_map = handle(it.map(), isolate());
672
673      maps_and_handlers.push_back(
674          MapAndHandler(existing_map, existing_handler));
675
676      if (existing_map->is_deprecated()) {
677        // Filter out deprecated maps to ensure their instances get migrated.
678        deprecated_maps++;
679      } else if (map.is_identical_to(existing_map)) {
680        // If both map and handler stayed the same (and the name is also the
681        // same as checked above, for keyed accesses), we're not progressing
682        // in the lattice and need to go MEGAMORPHIC instead. There's one
683        // exception to this rule, which is when we're in RECOMPUTE_HANDLER
684        // state, there we allow to migrate to a new handler.
685        if (handler.is_identical_to(existing_handler) &&
686            state() != RECOMPUTE_HANDLER) {
687          return false;
688        }
689
690        // If the receiver type is already in the polymorphic IC, this indicates
691        // there was a prototoype chain failure. In that case, just overwrite
692        // the handler.
693        handler_to_overwrite = i;
694      } else if (handler_to_overwrite == -1 &&
695                 IsTransitionOfMonomorphicTarget(*existing_map, *map)) {
696        handler_to_overwrite = i;
697      }
698
699      i++;
700    }
701    DCHECK_LE(i, maps_and_handlers.size());
702  }
703
704  int number_of_maps = static_cast<int>(maps_and_handlers.size());
705  int number_of_valid_maps =
706      number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
707
708  if (number_of_valid_maps >= FLAG_max_valid_polymorphic_map_count)
709    return false;
710  if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
711    return false;
712  }
713
714  number_of_valid_maps++;
715  if (number_of_valid_maps == 1) {
716    ConfigureVectorState(name, lookup_start_object_map(), handler);
717  } else {
718    if (is_keyed() && nexus()->GetName() != *name) return false;
719    if (handler_to_overwrite >= 0) {
720      maps_and_handlers[handler_to_overwrite].second = handler;
721      if (!map.is_identical_to(
722              maps_and_handlers.at(handler_to_overwrite).first)) {
723        maps_and_handlers[handler_to_overwrite].first = map;
724      }
725    } else {
726      maps_and_handlers.push_back(MapAndHandler(map, handler));
727    }
728
729    ConfigureVectorState(name, maps_and_handlers);
730  }
731
732  return true;
733}
734
735void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
736                             Handle<Name> name) {
737  DCHECK(IsHandler(*handler));
738  ConfigureVectorState(name, lookup_start_object_map(), handler);
739}
740
741void IC::CopyICToMegamorphicCache(Handle<Name> name) {
742  std::vector<MapAndHandler> maps_and_handlers;
743  nexus()->ExtractMapsAndHandlers(&maps_and_handlers);
744  for (const MapAndHandler& map_and_handler : maps_and_handlers) {
745    UpdateMegamorphicCache(map_and_handler.first, name, map_and_handler.second);
746  }
747}
748
749bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) {
750  if (source_map.is_null()) return true;
751  if (target_map.is_null()) return false;
752  if (source_map.is_abandoned_prototype_map()) return false;
753  ElementsKind target_elements_kind = target_map.elements_kind();
754  bool more_general_transition = IsMoreGeneralElementsKindTransition(
755      source_map.elements_kind(), target_elements_kind);
756  Map transitioned_map;
757  if (more_general_transition) {
758    MapHandles map_list;
759    map_list.push_back(handle(target_map, isolate_));
760    transitioned_map = source_map.FindElementsKindTransitionedMap(
761        isolate(), map_list, ConcurrencyMode::kSynchronous);
762  }
763  return transitioned_map == target_map;
764}
765
766void IC::SetCache(Handle<Name> name, Handle<Object> handler) {
767  SetCache(name, MaybeObjectHandle(handler));
768}
769
770void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) {
771  DCHECK(IsHandler(*handler));
772  // Currently only load and store ICs support non-code handlers.
773  DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas());
774  switch (state()) {
775    case NO_FEEDBACK:
776      UNREACHABLE();
777    case UNINITIALIZED:
778      UpdateMonomorphicIC(handler, name);
779      break;
780    case RECOMPUTE_HANDLER:
781    case MONOMORPHIC:
782      if (IsGlobalIC()) {
783        UpdateMonomorphicIC(handler, name);
784        break;
785      }
786      V8_FALLTHROUGH;
787    case POLYMORPHIC:
788      if (UpdatePolymorphicIC(name, handler)) break;
789      if (UpdateMegaDOMIC(handler, name)) break;
790      if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
791        CopyICToMegamorphicCache(name);
792      }
793      V8_FALLTHROUGH;
794    case MEGADOM:
795      ConfigureVectorState(MEGAMORPHIC, name);
796      V8_FALLTHROUGH;
797    case MEGAMORPHIC:
798      UpdateMegamorphicCache(lookup_start_object_map(), name, handler);
799      // Indicate that we've handled this case.
800      vector_set_ = true;
801      break;
802    case GENERIC:
803      UNREACHABLE();
804  }
805}
806
807void LoadIC::UpdateCaches(LookupIterator* lookup) {
808  Handle<Object> handler;
809  if (lookup->state() == LookupIterator::ACCESS_CHECK) {
810    handler = LoadHandler::LoadSlow(isolate());
811  } else if (!lookup->IsFound()) {
812    TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
813    Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
814    handler = LoadHandler::LoadFullChain(
815        isolate(), lookup_start_object_map(),
816        MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
817  } else if (IsLoadGlobalIC() && lookup->state() == LookupIterator::JSPROXY) {
818    // If there is proxy just install the slow stub since we need to call the
819    // HasProperty trap for global loads. The ProxyGetProperty builtin doesn't
820    // handle this case.
821    handler = LoadHandler::LoadSlow(isolate());
822  } else {
823    if (IsLoadGlobalIC()) {
824      if (lookup->TryLookupCachedProperty()) {
825        DCHECK_EQ(LookupIterator::DATA, lookup->state());
826      }
827      if (lookup->state() == LookupIterator::DATA &&
828          lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
829        DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
830        // Now update the cell in the feedback vector.
831        nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
832        TraceIC("LoadGlobalIC", lookup->name());
833        return;
834      }
835    }
836    handler = ComputeHandler(lookup);
837  }
838  // Can't use {lookup->name()} because the LookupIterator might be in
839  // "elements" mode for keys that are strings representing integers above
840  // JSArray::kMaxIndex.
841  SetCache(lookup->GetName(), handler);
842  TraceIC("LoadIC", lookup->GetName());
843}
844
845StubCache* IC::stub_cache() {
846  // HasICs and each of the store own ICs require its own stub cache.
847  // Until we create them, don't allow accessing the load/store stub caches.
848  DCHECK(!IsAnyHas());
849  DCHECK(!IsAnyDefineOwn());
850  if (IsAnyLoad()) {
851    return isolate()->load_stub_cache();
852  } else {
853    DCHECK(IsAnyStore());
854    return isolate()->store_stub_cache();
855  }
856}
857
858void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
859                                const MaybeObjectHandle& handler) {
860  if (!IsAnyHas() && !IsAnyDefineOwn()) {
861    stub_cache()->Set(*name, *map, *handler);
862  }
863}
864
865namespace {
866
867#if V8_ENABLE_WEBASSEMBLY
868
869inline WasmValueType GetWasmValueType(wasm::ValueType type) {
870#define TYPE_CASE(Name) \
871  case wasm::k##Name:   \
872    return WasmValueType::k##Name;
873
874  switch (type.kind()) {
875    TYPE_CASE(I8)
876    TYPE_CASE(I16)
877    TYPE_CASE(I32)
878    TYPE_CASE(I64)
879    TYPE_CASE(F32)
880    TYPE_CASE(F64)
881    TYPE_CASE(S128)
882    TYPE_CASE(Ref)
883    TYPE_CASE(OptRef)
884
885    case wasm::kRtt:
886      // Rtt values are not supposed to be made available to JavaScript side.
887      UNREACHABLE();
888
889    case wasm::kVoid:
890    case wasm::kBottom:
891      UNREACHABLE();
892  }
893#undef TYPE_CASE
894}
895
896Handle<Smi> MakeLoadWasmStructFieldHandler(Isolate* isolate,
897                                           Handle<JSReceiver> holder,
898                                           LookupIterator* lookup) {
899  DCHECK(holder->IsWasmObject(isolate));
900  WasmValueType type;
901  int field_offset;
902  if (holder->IsWasmArray(isolate)) {
903    // The only named property that WasmArray has is length.
904    DCHECK_EQ(0, lookup->property_details().field_index());
905    DCHECK_EQ(*isolate->factory()->length_string(), *lookup->name());
906    type = WasmValueType::kU32;
907    field_offset = WasmArray::kLengthOffset;
908  } else {
909    wasm::StructType* struct_type = Handle<WasmStruct>::cast(holder)->type();
910    int field_index = lookup->property_details().field_index();
911    type = GetWasmValueType(struct_type->field(field_index));
912    field_offset =
913        WasmStruct::kHeaderSize + struct_type->field_offset(field_index);
914
915    const size_t kMaxWasmFieldOffset =
916        WasmStruct::kHeaderSize + wasm::StructType::kMaxFieldOffset;
917    static_assert(kMaxWasmFieldOffset <= LoadHandler::WasmFieldOffsetBits::kMax,
918                  "Bigger numbers of struct fields require different approach");
919  }
920  return LoadHandler::LoadWasmStructField(isolate, type, field_offset);
921}
922
923#endif  // V8_ENABLE_WEBASSEMBLY
924
925}  // namespace
926
927Handle<Object> IC::CodeHandler(Builtin builtin) {
928  return MakeCodeHandler(isolate(), builtin);
929}
930
931Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
932  Handle<Object> receiver = lookup->GetReceiver();
933  ReadOnlyRoots roots(isolate());
934
935  Handle<Object> lookup_start_object = lookup->lookup_start_object();
936  // `in` cannot be called on strings, and will always return true for string
937  // wrapper length and function prototypes. The latter two cases are given
938  // LoadHandler::LoadNativeDataProperty below.
939  if (!IsAnyHas() && !lookup->IsElement()) {
940    if (lookup_start_object->IsString() &&
941        *lookup->name() == roots.length_string()) {
942      TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
943      return CodeHandler(Builtin::kLoadIC_StringLength);
944    }
945
946    if (lookup_start_object->IsStringWrapper() &&
947        *lookup->name() == roots.length_string()) {
948      TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
949      return CodeHandler(Builtin::kLoadIC_StringWrapperLength);
950    }
951
952    // Use specialized code for getting prototype of functions.
953    if (lookup_start_object->IsJSFunction() &&
954        *lookup->name() == roots.prototype_string() &&
955        !JSFunction::cast(*lookup_start_object)
956             .PrototypeRequiresRuntimeLookup()) {
957      TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
958      return CodeHandler(Builtin::kLoadIC_FunctionPrototype);
959    }
960  }
961
962  Handle<Map> map = lookup_start_object_map();
963  bool holder_is_lookup_start_object =
964      lookup_start_object.is_identical_to(lookup->GetHolder<JSReceiver>());
965
966  switch (lookup->state()) {
967    case LookupIterator::INTERCEPTOR: {
968      Handle<JSObject> holder = lookup->GetHolder<JSObject>();
969      Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
970
971      if (holder->GetNamedInterceptor().non_masking()) {
972        MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
973        if (!holder_is_lookup_start_object || IsLoadGlobalIC()) {
974          holder_ref = MaybeObjectHandle::Weak(holder);
975        }
976        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
977        return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
978                                          smi_handler);
979      }
980
981      if (holder_is_lookup_start_object) {
982        DCHECK(map->has_named_interceptor());
983        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
984        return smi_handler;
985      }
986
987      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
988      return LoadHandler::LoadFromPrototype(isolate(), map, holder,
989                                            smi_handler);
990    }
991
992    case LookupIterator::ACCESSOR: {
993      Handle<JSObject> holder = lookup->GetHolder<JSObject>();
994      // Use simple field loads for some well-known callback properties.
995      // The method will only return true for absolute truths based on the
996      // lookup start object maps.
997      FieldIndex field_index;
998      if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
999                                             &field_index)) {
1000        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
1001        return LoadHandler::LoadField(isolate(), field_index);
1002      }
1003      if (holder->IsJSModuleNamespace()) {
1004        Handle<ObjectHashTable> exports(
1005            Handle<JSModuleNamespace>::cast(holder)->module().exports(),
1006            isolate());
1007        InternalIndex entry =
1008            exports->FindEntry(isolate(), roots, lookup->name(),
1009                               Smi::ToInt(lookup->name()->GetHash()));
1010        // We found the accessor, so the entry must exist.
1011        DCHECK(entry.is_found());
1012        int value_index = ObjectHashTable::EntryToValueIndex(entry);
1013        Handle<Smi> smi_handler =
1014            LoadHandler::LoadModuleExport(isolate(), value_index);
1015        if (holder_is_lookup_start_object) {
1016          return smi_handler;
1017        }
1018        return LoadHandler::LoadFromPrototype(isolate(), map, holder,
1019                                              smi_handler);
1020      }
1021
1022      Handle<Object> accessors = lookup->GetAccessors();
1023      if (accessors->IsAccessorPair()) {
1024        Handle<AccessorPair> accessor_pair =
1025            Handle<AccessorPair>::cast(accessors);
1026        if (lookup->TryLookupCachedProperty(accessor_pair)) {
1027          DCHECK_EQ(LookupIterator::DATA, lookup->state());
1028          return ComputeHandler(lookup);
1029        }
1030
1031        Handle<Object> getter(accessor_pair->getter(), isolate());
1032        if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
1033          // TODO(jgruber): Update counter name.
1034          TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1035          return LoadHandler::LoadSlow(isolate());
1036        }
1037        set_accessor(getter);
1038
1039        if ((getter->IsFunctionTemplateInfo() &&
1040             FunctionTemplateInfo::cast(*getter).BreakAtEntry()) ||
1041            (getter->IsJSFunction() &&
1042             JSFunction::cast(*getter).shared().BreakAtEntry())) {
1043          // Do not install an IC if the api function has a breakpoint.
1044          TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1045          return LoadHandler::LoadSlow(isolate());
1046        }
1047
1048        Handle<Smi> smi_handler;
1049
1050        CallOptimization call_optimization(isolate(), getter);
1051        if (call_optimization.is_simple_api_call()) {
1052          CallOptimization::HolderLookup holder_lookup;
1053          Handle<JSObject> api_holder =
1054              call_optimization.LookupHolderOfExpectedType(isolate(), map,
1055                                                           &holder_lookup);
1056
1057          if (!call_optimization.IsCompatibleReceiverMap(api_holder, holder,
1058                                                         holder_lookup) ||
1059              !holder->HasFastProperties()) {
1060            TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1061            return LoadHandler::LoadSlow(isolate());
1062          }
1063
1064          smi_handler = LoadHandler::LoadApiGetter(
1065              isolate(), holder_lookup == CallOptimization::kHolderIsReceiver);
1066
1067          Handle<Context> context(
1068              call_optimization.GetAccessorContext(holder->map()), isolate());
1069
1070          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
1071          return LoadHandler::LoadFromPrototype(
1072              isolate(), map, holder, smi_handler,
1073              MaybeObjectHandle::Weak(call_optimization.api_call_info()),
1074              MaybeObjectHandle::Weak(context));
1075        }
1076
1077        if (holder->HasFastProperties()) {
1078          smi_handler =
1079              LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
1080
1081          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
1082          if (holder_is_lookup_start_object) return smi_handler;
1083          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
1084        } else if (holder->IsJSGlobalObject()) {
1085          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
1086          smi_handler = LoadHandler::LoadGlobal(isolate());
1087          return LoadHandler::LoadFromPrototype(
1088              isolate(), map, holder, smi_handler,
1089              MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
1090        } else {
1091          smi_handler = LoadHandler::LoadNormal(isolate());
1092          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1093          if (holder_is_lookup_start_object) return smi_handler;
1094          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1095        }
1096
1097        return LoadHandler::LoadFromPrototype(isolate(), map, holder,
1098                                              smi_handler);
1099      }
1100
1101      Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1102
1103      if (info->replace_on_access()) {
1104        set_slow_stub_reason(
1105            "getter needs to be reconfigured to data property");
1106        TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1107        return LoadHandler::LoadSlow(isolate());
1108      }
1109
1110      if (v8::ToCData<Address>(info->getter()) == kNullAddress ||
1111          !AccessorInfo::IsCompatibleReceiverMap(info, map) ||
1112          !holder->HasFastProperties() ||
1113          (info->is_sloppy() && !receiver->IsJSReceiver())) {
1114        TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1115        return LoadHandler::LoadSlow(isolate());
1116      }
1117
1118      Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
1119          isolate(), lookup->GetAccessorIndex());
1120      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
1121      if (holder_is_lookup_start_object) return smi_handler;
1122      TRACE_HANDLER_STATS(isolate(),
1123                          LoadIC_LoadNativeDataPropertyFromPrototypeDH);
1124      return LoadHandler::LoadFromPrototype(isolate(), map, holder,
1125                                            smi_handler);
1126    }
1127
1128    case LookupIterator::DATA: {
1129      Handle<JSReceiver> holder = lookup->GetHolder<JSReceiver>();
1130      DCHECK_EQ(PropertyKind::kData, lookup->property_details().kind());
1131      Handle<Smi> smi_handler;
1132      if (lookup->is_dictionary_holder()) {
1133        if (holder->IsJSGlobalObject(isolate())) {
1134          // TODO(verwaest): Also supporting the global object as receiver is a
1135          // workaround for code that leaks the global object.
1136          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
1137          smi_handler = LoadHandler::LoadGlobal(isolate());
1138          return LoadHandler::LoadFromPrototype(
1139              isolate(), map, holder, smi_handler,
1140              MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
1141        }
1142        smi_handler = LoadHandler::LoadNormal(isolate());
1143        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1144        if (holder_is_lookup_start_object) return smi_handler;
1145        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1146      } else if (lookup->IsElement(*holder)) {
1147#if V8_ENABLE_WEBASSEMBLY
1148        if (holder_is_lookup_start_object && holder->IsWasmStruct()) {
1149          // TODO(ishell): Consider supporting indexed access to WasmStruct
1150          // fields.
1151          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
1152          return LoadHandler::LoadNonExistent(isolate());
1153        }
1154#endif  // V8_ENABLE_WEBASSEMBLY
1155        TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1156        return LoadHandler::LoadSlow(isolate());
1157      } else {
1158        DCHECK_EQ(PropertyLocation::kField,
1159                  lookup->property_details().location());
1160#if V8_ENABLE_WEBASSEMBLY
1161        if (V8_UNLIKELY(holder->IsWasmObject(isolate()))) {
1162          smi_handler =
1163              MakeLoadWasmStructFieldHandler(isolate(), holder, lookup);
1164        } else  // NOLINT(readability/braces)
1165#endif          // V8_ENABLE_WEBASSEMBLY
1166        {
1167          DCHECK(holder->IsJSObject(isolate()));
1168          FieldIndex field = lookup->GetFieldIndex();
1169          smi_handler = LoadHandler::LoadField(isolate(), field);
1170        }
1171        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
1172        if (holder_is_lookup_start_object) return smi_handler;
1173        TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
1174      }
1175      if (lookup->constness() == PropertyConstness::kConst &&
1176          !holder_is_lookup_start_object) {
1177        DCHECK_IMPLIES(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL,
1178                       !lookup->is_dictionary_holder());
1179
1180        Handle<Object> value = lookup->GetDataValue();
1181
1182        if (value->IsThinString()) {
1183          value = handle(ThinString::cast(*value).actual(), isolate());
1184        }
1185
1186        // Non internalized strings could turn into thin/cons strings
1187        // when internalized. Weak references to thin/cons strings are
1188        // not supported in the GC. If concurrent marking is running
1189        // and the thin/cons string is marked but the actual string is
1190        // not, then the weak reference could be missed.
1191        if (!value->IsString() ||
1192            (value->IsString() && value->IsInternalizedString())) {
1193          MaybeObjectHandle weak_value =
1194              value->IsSmi() ? MaybeObjectHandle(*value, isolate())
1195                             : MaybeObjectHandle::Weak(*value, isolate());
1196
1197          smi_handler = LoadHandler::LoadConstantFromPrototype(isolate());
1198          TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
1199          return LoadHandler::LoadFromPrototype(isolate(), map, holder,
1200                                                smi_handler, weak_value);
1201        }
1202      }
1203      return LoadHandler::LoadFromPrototype(isolate(), map, holder,
1204                                            smi_handler);
1205    }
1206    case LookupIterator::INTEGER_INDEXED_EXOTIC:
1207      TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
1208      return LoadHandler::LoadNonExistent(isolate());
1209
1210    case LookupIterator::JSPROXY: {
1211      Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
1212      if (holder_is_lookup_start_object) return smi_handler;
1213
1214      Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
1215      return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
1216                                            smi_handler);
1217    }
1218    case LookupIterator::ACCESS_CHECK:
1219    case LookupIterator::NOT_FOUND:
1220    case LookupIterator::TRANSITION:
1221      UNREACHABLE();
1222  }
1223
1224  return Handle<Code>::null();
1225}
1226
1227bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) {
1228  const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map);
1229  if (handler.is_null()) return false;
1230  return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD;
1231}
1232
1233void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
1234                                    KeyedAccessLoadMode load_mode) {
1235  Handle<Map> receiver_map(receiver->map(), isolate());
1236  DCHECK(receiver_map->instance_type() !=
1237         JS_PRIMITIVE_WRAPPER_TYPE);  // Checked by caller.
1238  MapHandles target_receiver_maps;
1239  TargetMaps(&target_receiver_maps);
1240
1241  if (target_receiver_maps.empty()) {
1242    Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1243    return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1244  }
1245
1246  for (Handle<Map> map : target_receiver_maps) {
1247    if (map.is_null()) continue;
1248    if (map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
1249      set_slow_stub_reason("JSPrimitiveWrapper");
1250      return;
1251    }
1252    if (map->instance_type() == JS_PROXY_TYPE) {
1253      set_slow_stub_reason("JSProxy");
1254      return;
1255    }
1256  }
1257
1258  // The first time a receiver is seen that is a transitioned version of the
1259  // previous monomorphic receiver type, assume the new ElementsKind is the
1260  // monomorphic type. This benefits global arrays that only transition
1261  // once, and all call sites accessing them are faster if they remain
1262  // monomorphic. If this optimistic assumption is not true, the IC will
1263  // miss again and it will become polymorphic and support both the
1264  // untransitioned and transitioned maps.
1265  if (state() == MONOMORPHIC) {
1266    if ((receiver->IsJSObject() &&
1267         IsMoreGeneralElementsKindTransition(
1268             target_receiver_maps.at(0)->elements_kind(),
1269             Handle<JSObject>::cast(receiver)->GetElementsKind()))
1270#ifdef V8_ENABLE_WEBASSEMBLY
1271        || receiver->IsWasmObject()
1272#endif
1273    ) {
1274      Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1275      return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1276    }
1277  }
1278
1279  DCHECK(state() != GENERIC);
1280
1281  // Determine the list of receiver maps that this call site has seen,
1282  // adding the map that was just encountered.
1283  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1284    // If the {receiver_map} previously had a handler that didn't handle
1285    // out-of-bounds access, but can generally handle it, we can just go
1286    // on and update the handler appropriately below.
1287    if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS ||
1288        !CanChangeToAllowOutOfBounds(receiver_map)) {
1289      // If the miss wasn't due to an unseen map, a polymorphic stub
1290      // won't help, use the generic stub.
1291      set_slow_stub_reason("same map added twice");
1292      return;
1293    }
1294  }
1295
1296  // If the maximum number of receiver maps has been exceeded, use the generic
1297  // version of the IC.
1298  if (static_cast<int>(target_receiver_maps.size()) >
1299      FLAG_max_valid_polymorphic_map_count) {
1300    set_slow_stub_reason("max polymorph exceeded");
1301    return;
1302  }
1303
1304  MaybeObjectHandles handlers;
1305  handlers.reserve(target_receiver_maps.size());
1306  LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1307  DCHECK_LE(1, target_receiver_maps.size());
1308  if (target_receiver_maps.size() == 1) {
1309    ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1310  } else {
1311    ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1312  }
1313}
1314
1315namespace {
1316
1317bool AllowConvertHoleElementToUndefined(Isolate* isolate,
1318                                        Handle<Map> receiver_map) {
1319  if (receiver_map->IsJSTypedArrayMap()) {
1320    // For JSTypedArray we never lookup elements in the prototype chain.
1321    return true;
1322  }
1323
1324  // For other {receiver}s we need to check the "no elements" protector.
1325  if (Protectors::IsNoElementsIntact(isolate)) {
1326    if (receiver_map->IsStringMap()) {
1327      return true;
1328    }
1329    if (receiver_map->IsJSObjectMap()) {
1330      // For other JSObjects (including JSArrays) we can only continue if
1331      // the {receiver}s prototype is either the initial Object.prototype
1332      // or the initial Array.prototype, which are both guarded by the
1333      // "no elements" protector checked above.
1334      Handle<Object> receiver_prototype(receiver_map->prototype(), isolate);
1335
1336      if (isolate->IsInAnyContext(*receiver_prototype,
1337                                  Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1338          isolate->IsInAnyContext(*receiver_prototype,
1339                                  Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
1340        return true;
1341      }
1342    }
1343  }
1344
1345  return false;
1346}
1347}  // namespace
1348
1349Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
1350                                               KeyedAccessLoadMode load_mode) {
1351  // Has a getter interceptor, or is any has and has a query interceptor.
1352  if (receiver_map->has_indexed_interceptor() &&
1353      (!receiver_map->GetIndexedInterceptor().getter().IsUndefined(isolate()) ||
1354       (IsAnyHas() &&
1355        !receiver_map->GetIndexedInterceptor().query().IsUndefined(
1356            isolate()))) &&
1357      !receiver_map->GetIndexedInterceptor().non_masking()) {
1358    // TODO(jgruber): Update counter name.
1359    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1360    return IsAnyHas() ? CodeHandler(Builtin::kHasIndexedInterceptorIC)
1361                      : CodeHandler(Builtin::kLoadIndexedInterceptorIC);
1362  }
1363
1364  InstanceType instance_type = receiver_map->instance_type();
1365  if (instance_type < FIRST_NONSTRING_TYPE) {
1366    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1367    if (IsAnyHas()) return LoadHandler::LoadSlow(isolate());
1368    return LoadHandler::LoadIndexedString(isolate(), load_mode);
1369  }
1370  if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1371    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1372    return LoadHandler::LoadSlow(isolate());
1373  }
1374  if (instance_type == JS_PROXY_TYPE) {
1375    return LoadHandler::LoadProxy(isolate());
1376  }
1377#if V8_ENABLE_WEBASSEMBLY
1378  if (InstanceTypeChecker::IsWasmObject(instance_type)) {
1379    // TODO(jgruber): Update counter name.
1380    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1381    return LoadHandler::LoadSlow(isolate());
1382  }
1383#endif  // V8_ENABLE_WEBASSEMBLY
1384
1385  ElementsKind elements_kind = receiver_map->elements_kind();
1386  if (IsSloppyArgumentsElementsKind(elements_kind)) {
1387    // TODO(jgruber): Update counter name.
1388    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1389    return IsAnyHas() ? CodeHandler(Builtin::kKeyedHasIC_SloppyArguments)
1390                      : CodeHandler(Builtin::kKeyedLoadIC_SloppyArguments);
1391  }
1392  bool is_js_array = instance_type == JS_ARRAY_TYPE;
1393  if (elements_kind == DICTIONARY_ELEMENTS) {
1394    TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1395    return LoadHandler::LoadElement(isolate(), elements_kind, false,
1396                                    is_js_array, load_mode);
1397  }
1398  DCHECK(IsFastElementsKind(elements_kind) ||
1399         IsAnyNonextensibleElementsKind(elements_kind) ||
1400         IsTypedArrayOrRabGsabTypedArrayElementsKind(elements_kind));
1401  bool convert_hole_to_undefined =
1402      (elements_kind == HOLEY_SMI_ELEMENTS ||
1403       elements_kind == HOLEY_ELEMENTS) &&
1404      AllowConvertHoleElementToUndefined(isolate(), receiver_map);
1405  TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1406  return LoadHandler::LoadElement(isolate(), elements_kind,
1407                                  convert_hole_to_undefined, is_js_array,
1408                                  load_mode);
1409}
1410
1411void KeyedLoadIC::LoadElementPolymorphicHandlers(
1412    MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1413    KeyedAccessLoadMode load_mode) {
1414  // Filter out deprecated maps to ensure their instances get migrated.
1415  receiver_maps->erase(
1416      std::remove_if(
1417          receiver_maps->begin(), receiver_maps->end(),
1418          [](const Handle<Map>& map) { return map->is_deprecated(); }),
1419      receiver_maps->end());
1420
1421  for (Handle<Map> receiver_map : *receiver_maps) {
1422    // Mark all stable receiver maps that have elements kind transition map
1423    // among receiver_maps as unstable because the optimizing compilers may
1424    // generate an elements kind transition for this kind of receivers.
1425    if (receiver_map->is_stable()) {
1426      Map tmap = receiver_map->FindElementsKindTransitionedMap(
1427          isolate(), *receiver_maps, ConcurrencyMode::kSynchronous);
1428      if (!tmap.is_null()) {
1429        receiver_map->NotifyLeafMapLayoutChange(isolate());
1430      }
1431    }
1432    handlers->push_back(
1433        MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode)));
1434  }
1435}
1436
1437namespace {
1438
1439enum KeyType { kIntPtr, kName, kBailout };
1440
1441// The cases where kIntPtr is returned must match what
1442// CodeStubAssembler::TryToIntptr can handle!
1443KeyType TryConvertKey(Handle<Object> key, Isolate* isolate, intptr_t* index_out,
1444                      Handle<Name>* name_out) {
1445  if (key->IsSmi()) {
1446    *index_out = Smi::ToInt(*key);
1447    return kIntPtr;
1448  }
1449  if (key->IsHeapNumber()) {
1450    double num = HeapNumber::cast(*key).value();
1451    if (!(num >= -kMaxSafeInteger)) return kBailout;
1452    if (num > kMaxSafeInteger) return kBailout;
1453    *index_out = static_cast<intptr_t>(num);
1454    if (*index_out != num) return kBailout;
1455    return kIntPtr;
1456  }
1457  if (key->IsString()) {
1458    key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
1459    uint32_t maybe_array_index;
1460    if (String::cast(*key).AsArrayIndex(&maybe_array_index)) {
1461      if (maybe_array_index <= INT_MAX) {
1462        *index_out = static_cast<intptr_t>(maybe_array_index);
1463        return kIntPtr;
1464      }
1465      // {key} is a string representation of an array index beyond the range
1466      // that the IC could handle. Don't try to take the named-property path.
1467      return kBailout;
1468    }
1469    *name_out = Handle<String>::cast(key);
1470    return kName;
1471  }
1472  if (key->IsSymbol()) {
1473    *name_out = Handle<Symbol>::cast(key);
1474    return kName;
1475  }
1476  return kBailout;
1477}
1478
1479bool IntPtrKeyToSize(intptr_t index, Handle<HeapObject> receiver, size_t* out) {
1480  if (index < 0) {
1481    if (receiver->IsJSTypedArray()) {
1482      // For JSTypedArray receivers, we can support negative keys, which we
1483      // just map to a very large value. This is valid because all OOB accesses
1484      // (negative or positive) are handled the same way, and size_t::max is
1485      // guaranteed to be an OOB access.
1486      *out = std::numeric_limits<size_t>::max();
1487      return true;
1488    }
1489    return false;
1490  }
1491#if V8_HOST_ARCH_64_BIT
1492  if (index > JSObject::kMaxElementIndex && !receiver->IsJSTypedArray()) {
1493    return false;
1494  }
1495#else
1496  // On 32-bit platforms, any intptr_t is less than kMaxElementIndex.
1497  STATIC_ASSERT(
1498      static_cast<double>(std::numeric_limits<decltype(index)>::max()) <=
1499      static_cast<double>(JSObject::kMaxElementIndex));
1500#endif
1501  *out = static_cast<size_t>(index);
1502  return true;
1503}
1504
1505bool CanCache(Handle<Object> receiver, InlineCacheState state) {
1506  if (!FLAG_use_ic || state == NO_FEEDBACK) return false;
1507  if (!receiver->IsJSReceiver() && !receiver->IsString()) return false;
1508  return !receiver->IsAccessCheckNeeded() && !receiver->IsJSPrimitiveWrapper();
1509}
1510
1511bool IsOutOfBoundsAccess(Handle<Object> receiver, size_t index) {
1512  size_t length;
1513  if (receiver->IsJSArray()) {
1514    length = JSArray::cast(*receiver).length().Number();
1515  } else if (receiver->IsJSTypedArray()) {
1516    length = JSTypedArray::cast(*receiver).GetLength();
1517  } else if (receiver->IsJSObject()) {
1518    length = JSObject::cast(*receiver).elements().length();
1519  } else if (receiver->IsString()) {
1520    length = String::cast(*receiver).length();
1521  } else {
1522    return false;
1523  }
1524  return index >= length;
1525}
1526
1527KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
1528                                size_t index) {
1529  if (IsOutOfBoundsAccess(receiver, index)) {
1530    DCHECK(receiver->IsHeapObject());
1531    Handle<Map> receiver_map(Handle<HeapObject>::cast(receiver)->map(),
1532                             isolate);
1533    if (AllowConvertHoleElementToUndefined(isolate, receiver_map)) {
1534      return LOAD_IGNORE_OUT_OF_BOUNDS;
1535    }
1536  }
1537  return STANDARD_LOAD;
1538}
1539
1540}  // namespace
1541
1542MaybeHandle<Object> KeyedLoadIC::RuntimeLoad(Handle<Object> object,
1543                                             Handle<Object> key) {
1544  Handle<Object> result;
1545
1546  if (IsKeyedLoadIC()) {
1547    ASSIGN_RETURN_ON_EXCEPTION(
1548        isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1549        Object);
1550  } else {
1551    DCHECK(IsKeyedHasIC());
1552    ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1553                               Runtime::HasProperty(isolate(), object, key),
1554                               Object);
1555  }
1556  return result;
1557}
1558
1559MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1560                                      Handle<Object> key) {
1561  if (MigrateDeprecated(isolate(), object)) {
1562    return RuntimeLoad(object, key);
1563  }
1564
1565  Handle<Object> load_handle;
1566
1567  intptr_t maybe_index;
1568  size_t index;
1569  Handle<Name> maybe_name;
1570  KeyType key_type = TryConvertKey(key, isolate(), &maybe_index, &maybe_name);
1571
1572  if (key_type == kName) {
1573    ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1574                               LoadIC::Load(object, maybe_name), Object);
1575  } else if (key_type == kIntPtr && CanCache(object, state()) &&
1576             IntPtrKeyToSize(maybe_index, Handle<HeapObject>::cast(object),
1577                             &index)) {
1578    KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index);
1579    UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode);
1580    if (is_vector_set()) {
1581      TraceIC("LoadIC", key);
1582    }
1583  }
1584
1585  if (vector_needs_update()) {
1586    ConfigureVectorState(MEGAMORPHIC, key);
1587    TraceIC("LoadIC", key);
1588  }
1589
1590  if (!load_handle.is_null()) return load_handle;
1591
1592  return RuntimeLoad(object, key);
1593}
1594
1595bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1596                             StoreOrigin store_origin) {
1597  // Disable ICs for non-JSObjects for now.
1598  Handle<Object> object = it->GetReceiver();
1599  if (object->IsJSProxy()) return true;
1600  if (!object->IsJSObject()) return false;
1601  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1602  DCHECK(!receiver->map().is_deprecated());
1603
1604  if (it->state() != LookupIterator::TRANSITION) {
1605    for (; it->IsFound(); it->Next()) {
1606      switch (it->state()) {
1607        case LookupIterator::NOT_FOUND:
1608        case LookupIterator::TRANSITION:
1609          UNREACHABLE();
1610        case LookupIterator::JSPROXY:
1611          return true;
1612        case LookupIterator::INTERCEPTOR: {
1613          Handle<JSObject> holder = it->GetHolder<JSObject>();
1614          InterceptorInfo info = holder->GetNamedInterceptor();
1615          if (it->HolderIsReceiverOrHiddenPrototype() ||
1616              !info.getter().IsUndefined(isolate()) ||
1617              !info.query().IsUndefined(isolate())) {
1618            return true;
1619          }
1620          break;
1621        }
1622        case LookupIterator::ACCESS_CHECK:
1623          if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1624          break;
1625        case LookupIterator::ACCESSOR:
1626          return !it->IsReadOnly();
1627        case LookupIterator::INTEGER_INDEXED_EXOTIC:
1628          return false;
1629        case LookupIterator::DATA: {
1630          if (it->IsReadOnly()) return false;
1631          Handle<JSObject> holder = it->GetHolder<JSObject>();
1632          if (receiver.is_identical_to(holder)) {
1633            it->PrepareForDataProperty(value);
1634            // The previous receiver map might just have been deprecated,
1635            // so reload it.
1636            update_lookup_start_object_map(receiver);
1637            return true;
1638          }
1639
1640          // Receiver != holder.
1641          if (receiver->IsJSGlobalProxy()) {
1642            PrototypeIterator iter(isolate(), receiver);
1643            return it->GetHolder<Object>().is_identical_to(
1644                PrototypeIterator::GetCurrent(iter));
1645          }
1646
1647          if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1648
1649          if (it->ExtendingNonExtensible(receiver)) return false;
1650          it->PrepareTransitionToDataProperty(receiver, value, NONE,
1651                                              store_origin);
1652          return it->IsCacheableTransition();
1653        }
1654      }
1655    }
1656  }
1657
1658  // If we are in StoreGlobal then check if we should throw on non-existent
1659  // properties.
1660  if (IsStoreGlobalIC() &&
1661      (GetShouldThrow(it->isolate(), Nothing<ShouldThrow>()) ==
1662       ShouldThrow::kThrowOnError)) {
1663    // ICs typically does the store in two steps: prepare receiver for the
1664    // transition followed by the actual store. For global objects we create a
1665    // property cell when preparing for transition and install this cell in the
1666    // handler. In strict mode, we throw and never initialize this property
1667    // cell. The IC handler assumes that the property cell it is holding is for
1668    // a property that is existing. This case violates this assumption. If we
1669    // happen to invalidate this property cell later, it leads to incorrect
1670    // behaviour. For now just use a slow stub and don't install the property
1671    // cell for these cases. Hopefully these cases are not frequent enough to
1672    // impact performance.
1673    //
1674    // TODO(mythria): If we find this to be happening often, we could install a
1675    // new kind of handler for non-existent properties. These handlers can then
1676    // miss to runtime if the value is not hole (i.e. cell got invalidated) and
1677    // handle these stores correctly.
1678    return false;
1679  }
1680  receiver = it->GetStoreTarget<JSObject>();
1681  if (it->ExtendingNonExtensible(receiver)) return false;
1682  it->PrepareTransitionToDataProperty(receiver, value, NONE, store_origin);
1683  return it->IsCacheableTransition();
1684}
1685
1686MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
1687                                         Handle<Object> value) {
1688  DCHECK(name->IsString());
1689
1690  // Look up in script context table.
1691  Handle<String> str_name = Handle<String>::cast(name);
1692  Handle<JSGlobalObject> global = isolate()->global_object();
1693  Handle<ScriptContextTable> script_contexts(
1694      global->native_context().script_context_table(), isolate());
1695
1696  VariableLookupResult lookup_result;
1697  if (script_contexts->Lookup(str_name, &lookup_result)) {
1698    Handle<Context> script_context = ScriptContextTable::GetContext(
1699        isolate(), script_contexts, lookup_result.context_index);
1700    if (lookup_result.mode == VariableMode::kConst) {
1701      return TypeError(MessageTemplate::kConstAssign, global, name);
1702    }
1703
1704    Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
1705                                  isolate());
1706
1707    if (previous_value->IsTheHole(isolate())) {
1708      // Do not install stubs and stay pre-monomorphic for
1709      // uninitialized accesses.
1710      THROW_NEW_ERROR(
1711          isolate(),
1712          NewReferenceError(MessageTemplate::kAccessedUninitializedVariable,
1713                            name),
1714          Object);
1715    }
1716
1717    bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1718    if (use_ic) {
1719      if (nexus()->ConfigureLexicalVarMode(
1720              lookup_result.context_index, lookup_result.slot_index,
1721              lookup_result.mode == VariableMode::kConst)) {
1722        TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1723      } else {
1724        // Given combination of indices can't be encoded, so use slow stub.
1725        TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1726        SetCache(name, StoreHandler::StoreSlow(isolate()));
1727      }
1728      TraceIC("StoreGlobalIC", name);
1729    } else if (state() == NO_FEEDBACK) {
1730      TraceIC("StoreGlobalIC", name);
1731    }
1732    script_context->set(lookup_result.slot_index, *value);
1733    return value;
1734  }
1735
1736  return StoreIC::Store(global, name, value);
1737}
1738
1739namespace {
1740Maybe<bool> DefineOwnDataProperty(LookupIterator* it,
1741                                  LookupIterator::State original_state,
1742                                  Handle<Object> value,
1743                                  Maybe<ShouldThrow> should_throw,
1744                                  StoreOrigin store_origin) {
1745  // It should not be possible to call DefineOwnDataProperty in a
1746  // contextual store (indicated by IsJSGlobalObject()).
1747  DCHECK(!it->GetReceiver()->IsJSGlobalObject(it->isolate()));
1748
1749  // Handle special cases that can't be handled by
1750  // DefineOwnPropertyIgnoreAttributes first.
1751  switch (it->state()) {
1752    case LookupIterator::JSPROXY: {
1753      PropertyDescriptor new_desc;
1754      new_desc.set_value(value);
1755      new_desc.set_writable(true);
1756      new_desc.set_enumerable(true);
1757      new_desc.set_configurable(true);
1758      DCHECK_EQ(original_state, LookupIterator::JSPROXY);
1759      // TODO(joyee): this will start the lookup again. Ideally we should
1760      // implement something that reuses the existing LookupIterator.
1761      return JSProxy::DefineOwnProperty(it->isolate(), it->GetHolder<JSProxy>(),
1762                                        it->GetName(), &new_desc, should_throw);
1763    }
1764    // When lazy feedback is disabled, the original state could be different
1765    // while the object is already prepared for TRANSITION.
1766    case LookupIterator::TRANSITION: {
1767      switch (original_state) {
1768        case LookupIterator::JSPROXY:
1769        case LookupIterator::TRANSITION:
1770        case LookupIterator::DATA:
1771        case LookupIterator::INTERCEPTOR:
1772        case LookupIterator::ACCESSOR:
1773        case LookupIterator::INTEGER_INDEXED_EXOTIC:
1774          UNREACHABLE();
1775        case LookupIterator::ACCESS_CHECK: {
1776          DCHECK(!it->GetHolder<JSObject>()->IsAccessCheckNeeded());
1777          V8_FALLTHROUGH;
1778        }
1779        case LookupIterator::NOT_FOUND:
1780          return Object::AddDataProperty(it, value, NONE,
1781                                         Nothing<ShouldThrow>(), store_origin,
1782                                         EnforceDefineSemantics::kDefine);
1783      }
1784    }
1785    case LookupIterator::ACCESS_CHECK:
1786    case LookupIterator::NOT_FOUND:
1787    case LookupIterator::DATA:
1788    case LookupIterator::ACCESSOR:
1789    case LookupIterator::INTERCEPTOR:
1790    case LookupIterator::INTEGER_INDEXED_EXOTIC:
1791      break;
1792  }
1793
1794  // We need to restart to handle interceptors properly.
1795  it->Restart();
1796
1797  return JSObject::DefineOwnPropertyIgnoreAttributes(
1798      it, value, NONE, should_throw, JSObject::DONT_FORCE_FIELD,
1799      EnforceDefineSemantics::kDefine, store_origin);
1800}
1801}  // namespace
1802
1803MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1804                                   Handle<Object> value,
1805                                   StoreOrigin store_origin) {
1806  // TODO(verwaest): Let SetProperty do the migration, since storing a property
1807  // might deprecate the current map again, if value does not fit.
1808  if (MigrateDeprecated(isolate(), object)) {
1809    // KeyedStoreIC should handle DefineKeyedOwnIC with deprecated maps directly
1810    // instead of reusing this method.
1811    DCHECK(!IsDefineKeyedOwnIC());
1812    DCHECK(!name->IsPrivateName());
1813
1814    PropertyKey key(isolate(), name);
1815    LookupIterator it(
1816        isolate(), object, key,
1817        IsDefineNamedOwnIC() ? LookupIterator::OWN : LookupIterator::DEFAULT);
1818    DCHECK_IMPLIES(IsDefineNamedOwnIC(), it.IsFound() && it.HolderIsReceiver());
1819    // TODO(v8:12548): refactor DefinedNamedOwnIC and SetNamedIC as subclasses
1820    // of StoreIC so their logic doesn't get mixed here.
1821    if (IsDefineNamedOwnIC()) {
1822      MAYBE_RETURN_NULL(
1823          JSReceiver::CreateDataProperty(&it, value, Nothing<ShouldThrow>()));
1824    } else {
1825      MAYBE_RETURN_NULL(Object::SetProperty(&it, value, StoreOrigin::kNamed));
1826    }
1827    return value;
1828  }
1829
1830  bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1831  // If the object is undefined or null it's illegal to try to set any
1832  // properties on it; throw a TypeError in that case.
1833  if (object->IsNullOrUndefined(isolate())) {
1834    if (use_ic) {
1835      // Ensure the IC state progresses.
1836      TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1837      update_lookup_start_object_map(object);
1838      SetCache(name, StoreHandler::StoreSlow(isolate()));
1839      TraceIC("StoreIC", name);
1840    }
1841    return TypeError(MessageTemplate::kNonObjectPropertyStoreWithProperty, name,
1842                     object);
1843  }
1844
1845  JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1846  PropertyKey key(isolate(), name);
1847  LookupIterator it(
1848      isolate(), object, key,
1849      IsAnyDefineOwn() ? LookupIterator::OWN : LookupIterator::DEFAULT);
1850
1851  if (name->IsPrivate()) {
1852    if (name->IsPrivateName()) {
1853      DCHECK(!IsDefineNamedOwnIC());
1854      if (!JSReceiver::CheckPrivateNameStore(&it, IsDefineKeyedOwnIC())) {
1855        return MaybeHandle<Object>();
1856      }
1857    }
1858
1859    // IC handling of private fields/symbols stores on JSProxy is not
1860    // supported.
1861    if (object->IsJSProxy()) {
1862      use_ic = false;
1863    }
1864  }
1865
1866  // For IsAnyDefineOwn(), we can't simply do CreateDataProperty below
1867  // because we need to check the attributes before UpdateCaches updates
1868  // the state of the LookupIterator.
1869  LookupIterator::State original_state = it.state();
1870  // We'll defer the check for JSProxy and objects with named interceptors,
1871  // because the defineProperty traps need to be called first if they are
1872  // present. We can also skip this for private names since they are not
1873  // bound by configurability or extensibility checks, and errors would've
1874  // been thrown if the private field already exists in the object.
1875  if (IsAnyDefineOwn() && !name->IsPrivateName() && !object->IsJSProxy() &&
1876      !Handle<JSObject>::cast(object)->HasNamedInterceptor()) {
1877    Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
1878        isolate(), &it, value, Nothing<ShouldThrow>());
1879    if (can_define.IsNothing() || !can_define.FromJust()) {
1880      return MaybeHandle<Object>();
1881    }
1882  }
1883
1884  if (use_ic) {
1885    UpdateCaches(&it, value, store_origin);
1886  } else if (state() == NO_FEEDBACK) {
1887    // Tracing IC Stats for No Feedback State.
1888    IsStoreGlobalIC() ? TraceIC("StoreGlobalIC", name)
1889                      : TraceIC("StoreIC", name);
1890  }
1891
1892  // TODO(v8:12548): refactor DefinedNamedOwnIC and SetNamedIC as subclasses
1893  // of StoreIC so their logic doesn't get mixed here.
1894  // ES #sec-definefield
1895  // ES #sec-runtime-semantics-propertydefinitionevaluation
1896  // IsAnyDefineOwn() can be true when this method is reused by KeyedStoreIC.
1897  if (IsAnyDefineOwn()) {
1898    if (name->IsPrivateName()) {
1899      // We should define private fields without triggering traps or checking
1900      // extensibility.
1901      MAYBE_RETURN_NULL(
1902          JSReceiver::AddPrivateField(&it, value, Nothing<ShouldThrow>()));
1903    } else {
1904      MAYBE_RETURN_NULL(DefineOwnDataProperty(
1905          &it, original_state, value, Nothing<ShouldThrow>(), store_origin));
1906    }
1907  } else {
1908    MAYBE_RETURN_NULL(Object::SetProperty(&it, value, store_origin));
1909  }
1910  return value;
1911}
1912
1913void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1914                           StoreOrigin store_origin) {
1915  MaybeObjectHandle handler;
1916  if (LookupForWrite(lookup, value, store_origin)) {
1917    if (IsStoreGlobalIC()) {
1918      if (lookup->state() == LookupIterator::DATA &&
1919          lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1920        DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1921        // Now update the cell in the feedback vector.
1922        nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1923        TraceIC("StoreGlobalIC", lookup->GetName());
1924        return;
1925      }
1926    }
1927    handler = ComputeHandler(lookup);
1928  } else {
1929    set_slow_stub_reason("LookupForWrite said 'false'");
1930    handler = MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
1931  }
1932  // Can't use {lookup->name()} because the LookupIterator might be in
1933  // "elements" mode for keys that are strings representing integers above
1934  // JSArray::kMaxIndex.
1935  SetCache(lookup->GetName(), handler);
1936  TraceIC("StoreIC", lookup->GetName());
1937}
1938
1939MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
1940  switch (lookup->state()) {
1941    case LookupIterator::TRANSITION: {
1942      Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1943      if (store_target->IsJSGlobalObject()) {
1944        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1945
1946        if (lookup_start_object_map()->IsJSGlobalObject()) {
1947          DCHECK(IsStoreGlobalIC());
1948#ifdef DEBUG
1949          Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1950          DCHECK_EQ(*lookup->GetReceiver(), *holder);
1951          DCHECK_EQ(*store_target, *holder);
1952#endif
1953          return StoreHandler::StoreGlobal(lookup->transition_cell());
1954        }
1955        if (IsDefineKeyedOwnIC()) {
1956          // Private field can't be deleted from this global object and can't
1957          // be overwritten, so install slow handler in order to make store IC
1958          // throw if a private name already exists.
1959          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1960          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
1961        }
1962
1963        Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
1964        Handle<Object> handler = StoreHandler::StoreThroughPrototype(
1965            isolate(), lookup_start_object_map(), store_target, smi_handler,
1966            MaybeObjectHandle::Weak(lookup->transition_cell()));
1967        return MaybeObjectHandle(handler);
1968      }
1969      // Dictionary-to-fast transitions are not expected and not supported.
1970      DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
1971                     !lookup_start_object_map()->is_dictionary_map());
1972
1973      DCHECK(lookup->IsCacheableTransition());
1974      if (IsAnyDefineOwn()) {
1975        return StoreHandler::StoreOwnTransition(isolate(),
1976                                                lookup->transition_map());
1977      }
1978      return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
1979    }
1980
1981    case LookupIterator::INTERCEPTOR: {
1982      Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1983      InterceptorInfo info = holder->GetNamedInterceptor();
1984
1985      // If the interceptor is on the receiver...
1986      if (lookup->HolderIsReceiverOrHiddenPrototype() && !info.non_masking()) {
1987        // ...return a store interceptor Smi handler if there is a setter
1988        // interceptor and it's not DefineNamedOwnIC or DefineKeyedOwnIC
1989        // (which should call the definer)...
1990        if (!info.setter().IsUndefined(isolate()) && !IsAnyDefineOwn()) {
1991          return MaybeObjectHandle(StoreHandler::StoreInterceptor(isolate()));
1992        }
1993        // ...otherwise return a slow-case Smi handler, which invokes the
1994        // definer for DefineNamedOwnIC.
1995        return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
1996      }
1997
1998      // If the interceptor is a getter/query interceptor on the prototype
1999      // chain, return an invalidatable slow handler so it can turn fast if the
2000      // interceptor is masked by a regular property later.
2001      DCHECK(!info.getter().IsUndefined(isolate()) ||
2002             !info.query().IsUndefined(isolate()));
2003      Handle<Object> handler = StoreHandler::StoreThroughPrototype(
2004          isolate(), lookup_start_object_map(), holder,
2005          StoreHandler::StoreSlow(isolate()));
2006      return MaybeObjectHandle(handler);
2007    }
2008
2009    case LookupIterator::ACCESSOR: {
2010      // This is currently guaranteed by checks in StoreIC::Store.
2011      Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
2012      Handle<JSObject> holder = lookup->GetHolder<JSObject>();
2013      DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
2014
2015      if (!holder->HasFastProperties()) {
2016        set_slow_stub_reason("accessor on slow map");
2017        TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2018        MaybeObjectHandle handler =
2019            MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2020        return handler;
2021      }
2022      Handle<Object> accessors = lookup->GetAccessors();
2023      if (accessors->IsAccessorInfo()) {
2024        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
2025        if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
2026          set_slow_stub_reason("setter == kNullAddress");
2027          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2028          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2029        }
2030        if (AccessorInfo::cast(*accessors).is_special_data_property() &&
2031            !lookup->HolderIsReceiverOrHiddenPrototype()) {
2032          set_slow_stub_reason("special data property in prototype chain");
2033          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2034          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2035        }
2036        if (!AccessorInfo::IsCompatibleReceiverMap(info,
2037                                                   lookup_start_object_map())) {
2038          set_slow_stub_reason("incompatible receiver type");
2039          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2040          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2041        }
2042
2043        Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
2044            isolate(), lookup->GetAccessorIndex());
2045        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
2046        if (receiver.is_identical_to(holder)) {
2047          return MaybeObjectHandle(smi_handler);
2048        }
2049        TRACE_HANDLER_STATS(isolate(),
2050                            StoreIC_StoreNativeDataPropertyOnPrototypeDH);
2051        return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
2052            isolate(), lookup_start_object_map(), holder, smi_handler));
2053
2054      } else if (accessors->IsAccessorPair()) {
2055        Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
2056                              isolate());
2057        if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
2058          set_slow_stub_reason("setter not a function");
2059          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2060          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2061        }
2062
2063        if ((setter->IsFunctionTemplateInfo() &&
2064             FunctionTemplateInfo::cast(*setter).BreakAtEntry()) ||
2065            (setter->IsJSFunction() &&
2066             JSFunction::cast(*setter).shared().BreakAtEntry())) {
2067          // Do not install an IC if the api function has a breakpoint.
2068          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2069          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2070        }
2071
2072        CallOptimization call_optimization(isolate(), setter);
2073        if (call_optimization.is_simple_api_call()) {
2074          CallOptimization::HolderLookup holder_lookup;
2075          Handle<JSObject> api_holder =
2076              call_optimization.LookupHolderOfExpectedType(
2077                  isolate(), lookup_start_object_map(), &holder_lookup);
2078          if (call_optimization.IsCompatibleReceiverMap(api_holder, holder,
2079                                                        holder_lookup)) {
2080            Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
2081                isolate(),
2082                holder_lookup == CallOptimization::kHolderIsReceiver);
2083
2084            Handle<Context> context(
2085                call_optimization.GetAccessorContext(holder->map()), isolate());
2086            TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
2087            return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
2088                isolate(), lookup_start_object_map(), holder, smi_handler,
2089                MaybeObjectHandle::Weak(call_optimization.api_call_info()),
2090                MaybeObjectHandle::Weak(context)));
2091          }
2092          set_slow_stub_reason("incompatible receiver");
2093          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2094          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2095        } else if (setter->IsFunctionTemplateInfo()) {
2096          set_slow_stub_reason("setter non-simple template");
2097          TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2098          return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2099        }
2100
2101        Handle<Smi> smi_handler =
2102            StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex());
2103
2104        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
2105        if (receiver.is_identical_to(holder)) {
2106          return MaybeObjectHandle(smi_handler);
2107        }
2108        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
2109
2110        return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
2111            isolate(), lookup_start_object_map(), holder, smi_handler));
2112      }
2113      TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2114      return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2115    }
2116
2117    case LookupIterator::DATA: {
2118      // This is currently guaranteed by checks in StoreIC::Store.
2119      Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
2120      USE(receiver);
2121      Handle<JSObject> holder = lookup->GetHolder<JSObject>();
2122      DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
2123
2124      DCHECK_EQ(PropertyKind::kData, lookup->property_details().kind());
2125      if (lookup->is_dictionary_holder()) {
2126        if (holder->IsJSGlobalObject()) {
2127          TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
2128          return MaybeObjectHandle(
2129              StoreHandler::StoreGlobal(lookup->GetPropertyCell()));
2130        }
2131        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
2132        DCHECK(holder.is_identical_to(receiver));
2133        DCHECK_IMPLIES(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL,
2134                       lookup->constness() == PropertyConstness::kMutable);
2135
2136        Handle<Smi> handler = StoreHandler::StoreNormal(isolate());
2137        return MaybeObjectHandle(handler);
2138      }
2139
2140      // -------------- Elements (for TypedArrays) -------------
2141      if (lookup->IsElement(*holder)) {
2142        TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2143        return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2144      }
2145
2146      // -------------- Fields --------------
2147      if (lookup->property_details().location() == PropertyLocation::kField) {
2148        TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
2149        int descriptor = lookup->GetFieldDescriptorIndex();
2150        FieldIndex index = lookup->GetFieldIndex();
2151        if (V8_UNLIKELY(holder->IsJSSharedStruct())) {
2152          return MaybeObjectHandle(StoreHandler::StoreSharedStructField(
2153              isolate(), descriptor, index, lookup->representation()));
2154        }
2155        PropertyConstness constness = lookup->constness();
2156        if (constness == PropertyConstness::kConst &&
2157            IsDefineNamedOwnICKind(nexus()->kind())) {
2158          // DefineNamedOwnICs are used for initializing object literals
2159          // therefore we must store the value unconditionally even to
2160          // VariableMode::kConst fields.
2161          constness = PropertyConstness::kMutable;
2162        }
2163        return MaybeObjectHandle(StoreHandler::StoreField(
2164            isolate(), descriptor, index, constness, lookup->representation()));
2165      }
2166
2167      // -------------- Constant properties --------------
2168      DCHECK_EQ(PropertyLocation::kDescriptor,
2169                lookup->property_details().location());
2170      set_slow_stub_reason("constant property");
2171      TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2172      return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2173    }
2174    case LookupIterator::JSPROXY: {
2175      Handle<JSReceiver> receiver =
2176          Handle<JSReceiver>::cast(lookup->GetReceiver());
2177      Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
2178
2179      // IsDefineNamedOwnIC() is true when we are defining public fields on a
2180      // Proxy. In that case use the slow stub to invoke the define trap.
2181      if (IsDefineNamedOwnIC()) {
2182        TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2183        return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
2184      }
2185
2186      return MaybeObjectHandle(StoreHandler::StoreProxy(
2187          isolate(), lookup_start_object_map(), holder, receiver));
2188    }
2189
2190    case LookupIterator::INTEGER_INDEXED_EXOTIC:
2191    case LookupIterator::ACCESS_CHECK:
2192    case LookupIterator::NOT_FOUND:
2193      UNREACHABLE();
2194  }
2195  return MaybeObjectHandle();
2196}
2197
2198void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
2199                                      KeyedAccessStoreMode store_mode,
2200                                      Handle<Map> new_receiver_map) {
2201  std::vector<MapAndHandler> target_maps_and_handlers;
2202  nexus()->ExtractMapsAndHandlers(
2203      &target_maps_and_handlers,
2204      [this](Handle<Map> map) { return Map::TryUpdate(isolate(), map); });
2205  if (target_maps_and_handlers.empty()) {
2206    Handle<Map> monomorphic_map = receiver_map;
2207    // If we transitioned to a map that is a more general map than incoming
2208    // then use the new map.
2209    if (IsTransitionOfMonomorphicTarget(*receiver_map, *new_receiver_map)) {
2210      monomorphic_map = new_receiver_map;
2211    }
2212    Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
2213    return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
2214  }
2215
2216  for (const MapAndHandler& map_and_handler : target_maps_and_handlers) {
2217    Handle<Map> map = map_and_handler.first;
2218    if (!map.is_null() && map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
2219      DCHECK(!IsStoreInArrayLiteralIC());
2220      set_slow_stub_reason("JSPrimitiveWrapper");
2221      return;
2222    }
2223  }
2224
2225  // There are several special cases where an IC that is MONOMORPHIC can still
2226  // transition to a different IC that handles a superset of the original IC.
2227  // Handle those here if the receiver map hasn't changed or it has transitioned
2228  // to a more general kind.
2229  KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
2230  Handle<Map> previous_receiver_map = target_maps_and_handlers.at(0).first;
2231  if (state() == MONOMORPHIC) {
2232    Handle<Map> transitioned_receiver_map = new_receiver_map;
2233    if (IsTransitionOfMonomorphicTarget(*previous_receiver_map,
2234                                        *transitioned_receiver_map)) {
2235      // If the "old" and "new" maps are in the same elements map family, or
2236      // if they at least come from the same origin for a transitioning store,
2237      // stay MONOMORPHIC and use the map for the most generic ElementsKind.
2238      Handle<Object> handler =
2239          StoreElementHandler(transitioned_receiver_map, store_mode);
2240      ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
2241      return;
2242    }
2243    // If there is no transition and if we have seen the same map earlier and
2244    // there is only a change in the store_mode we can still stay monomorphic.
2245    if (receiver_map.is_identical_to(previous_receiver_map) &&
2246        new_receiver_map.is_identical_to(receiver_map) &&
2247        old_store_mode == STANDARD_STORE && store_mode != STANDARD_STORE) {
2248      if (receiver_map->IsJSArrayMap() &&
2249          JSArray::MayHaveReadOnlyLength(*receiver_map)) {
2250        set_slow_stub_reason(
2251            "can't generalize store mode (potentially read-only length)");
2252        return;
2253      }
2254      // A "normal" IC that handles stores can switch to a version that can
2255      // grow at the end of the array, handle OOB accesses or copy COW arrays
2256      // and still stay MONOMORPHIC.
2257      Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
2258      return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
2259    }
2260  }
2261
2262  DCHECK(state() != GENERIC);
2263
2264  bool map_added =
2265      AddOneReceiverMapIfMissing(&target_maps_and_handlers, receiver_map);
2266
2267  if (IsTransitionOfMonomorphicTarget(*receiver_map, *new_receiver_map)) {
2268    map_added |=
2269        AddOneReceiverMapIfMissing(&target_maps_and_handlers, new_receiver_map);
2270  }
2271
2272  if (!map_added) {
2273    // If the miss wasn't due to an unseen map, a polymorphic stub
2274    // won't help, use the megamorphic stub which can handle everything.
2275    set_slow_stub_reason("same map added twice");
2276    return;
2277  }
2278
2279  // If the maximum number of receiver maps has been exceeded, use the
2280  // megamorphic version of the IC.
2281  if (static_cast<int>(target_maps_and_handlers.size()) >
2282      FLAG_max_valid_polymorphic_map_count) {
2283    return;
2284  }
2285
2286  // Make sure all polymorphic handlers have the same store mode, otherwise the
2287  // megamorphic stub must be used.
2288  if (old_store_mode != STANDARD_STORE) {
2289    if (store_mode == STANDARD_STORE) {
2290      store_mode = old_store_mode;
2291    } else if (store_mode != old_store_mode) {
2292      set_slow_stub_reason("store mode mismatch");
2293      return;
2294    }
2295  }
2296
2297  // If the store mode isn't the standard mode, make sure that all polymorphic
2298  // receivers are either external arrays, or all "normal" arrays with writable
2299  // length. Otherwise, use the megamorphic stub.
2300  if (store_mode != STANDARD_STORE) {
2301    size_t external_arrays = 0;
2302    for (MapAndHandler map_and_handler : target_maps_and_handlers) {
2303      Handle<Map> map = map_and_handler.first;
2304      if (map->IsJSArrayMap() && JSArray::MayHaveReadOnlyLength(*map)) {
2305        set_slow_stub_reason(
2306            "unsupported combination of arrays (potentially read-only length)");
2307        return;
2308
2309      } else if (map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2310        DCHECK(!IsStoreInArrayLiteralIC());
2311        external_arrays++;
2312      }
2313    }
2314    if (external_arrays != 0 &&
2315        external_arrays != target_maps_and_handlers.size()) {
2316      DCHECK(!IsStoreInArrayLiteralIC());
2317      set_slow_stub_reason(
2318          "unsupported combination of external and normal arrays");
2319      return;
2320    }
2321  }
2322
2323  StoreElementPolymorphicHandlers(&target_maps_and_handlers, store_mode);
2324  if (target_maps_and_handlers.size() == 0) {
2325    Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
2326    ConfigureVectorState(Handle<Name>(), receiver_map, handler);
2327  } else if (target_maps_and_handlers.size() == 1) {
2328    ConfigureVectorState(Handle<Name>(), target_maps_and_handlers[0].first,
2329                         target_maps_and_handlers[0].second);
2330  } else {
2331    ConfigureVectorState(Handle<Name>(), target_maps_and_handlers);
2332  }
2333}
2334
2335Handle<Object> KeyedStoreIC::StoreElementHandler(
2336    Handle<Map> receiver_map, KeyedAccessStoreMode store_mode,
2337    MaybeHandle<Object> prev_validity_cell) {
2338  // The only case when could keep using non-slow element store handler for
2339  // a fast array with potentially read-only elements is when it's an
2340  // initializing store to array literal.
2341  DCHECK_IMPLIES(
2342      !receiver_map->has_dictionary_elements() &&
2343          receiver_map->MayHaveReadOnlyElementsInPrototypeChain(isolate()),
2344      IsStoreInArrayLiteralIC());
2345
2346  if (receiver_map->IsJSProxyMap()) {
2347    return StoreHandler::StoreProxy(isolate());
2348  }
2349
2350  // TODO(ishell): move to StoreHandler::StoreElement().
2351  Handle<Object> code;
2352  if (receiver_map->has_sloppy_arguments_elements()) {
2353    // TODO(jgruber): Update counter name.
2354    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
2355    code = CodeHandler(StoreHandler::StoreSloppyArgumentsBuiltin(store_mode));
2356  } else if (receiver_map->has_fast_elements() ||
2357             receiver_map->has_sealed_elements() ||
2358             receiver_map->has_nonextensible_elements() ||
2359             receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2360    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
2361    code = CodeHandler(StoreHandler::StoreFastElementBuiltin(store_mode));
2362    if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2363      return code;
2364    }
2365  } else if (IsStoreInArrayLiteralIC()) {
2366    // TODO(jgruber): Update counter name.
2367    TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
2368    return StoreHandler::StoreSlow(isolate(), store_mode);
2369  } else {
2370    // TODO(jgruber): Update counter name.
2371    TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
2372    DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() ||
2373           receiver_map->has_frozen_elements());
2374    code = StoreHandler::StoreSlow(isolate(), store_mode);
2375  }
2376
2377  if (IsAnyDefineOwn() || IsStoreInArrayLiteralIC()) return code;
2378  Handle<Object> validity_cell;
2379  if (!prev_validity_cell.ToHandle(&validity_cell)) {
2380    validity_cell =
2381        Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
2382  }
2383  if (validity_cell->IsSmi()) {
2384    // There's no prototype validity cell to check, so we can just use the stub.
2385    return code;
2386  }
2387  Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0);
2388  handler->set_validity_cell(*validity_cell);
2389  handler->set_smi_handler(*code);
2390  return handler;
2391}
2392
2393void KeyedStoreIC::StoreElementPolymorphicHandlers(
2394    std::vector<MapAndHandler>* receiver_maps_and_handlers,
2395    KeyedAccessStoreMode store_mode) {
2396  std::vector<Handle<Map>> receiver_maps;
2397  for (size_t i = 0; i < receiver_maps_and_handlers->size(); i++) {
2398    receiver_maps.push_back(receiver_maps_and_handlers->at(i).first);
2399  }
2400
2401  for (size_t i = 0; i < receiver_maps_and_handlers->size(); i++) {
2402    Handle<Map> receiver_map = receiver_maps_and_handlers->at(i).first;
2403    DCHECK(!receiver_map->is_deprecated());
2404    MaybeObjectHandle old_handler = receiver_maps_and_handlers->at(i).second;
2405    Handle<Object> handler;
2406    Handle<Map> transition;
2407
2408    if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
2409        receiver_map->MayHaveReadOnlyElementsInPrototypeChain(isolate())) {
2410      // TODO(mvstanton): Consider embedding store_mode in the state of the slow
2411      // keyed store ic for uniformity.
2412      TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
2413      handler = StoreHandler::StoreSlow(isolate());
2414
2415    } else {
2416      {
2417        Map tmap = receiver_map->FindElementsKindTransitionedMap(
2418            isolate(), receiver_maps, ConcurrencyMode::kSynchronous);
2419        if (!tmap.is_null()) {
2420          if (receiver_map->is_stable()) {
2421            receiver_map->NotifyLeafMapLayoutChange(isolate());
2422          }
2423          transition = handle(tmap, isolate());
2424        }
2425      }
2426
2427      MaybeHandle<Object> validity_cell;
2428      HeapObject old_handler_obj;
2429      if (!old_handler.is_null() &&
2430          old_handler->GetHeapObject(&old_handler_obj) &&
2431          old_handler_obj.IsDataHandler()) {
2432        validity_cell = MaybeHandle<Object>(
2433            DataHandler::cast(old_handler_obj).validity_cell(), isolate());
2434      }
2435      // TODO(mythria): Do not recompute the handler if we know there is no
2436      // change in the handler.
2437      // TODO(mvstanton): The code below is doing pessimistic elements
2438      // transitions. I would like to stop doing that and rely on Allocation
2439      // Site Tracking to do a better job of ensuring the data types are what
2440      // they need to be. Not all the elements are in place yet, pessimistic
2441      // elements transitions are still important for performance.
2442      if (!transition.is_null()) {
2443        TRACE_HANDLER_STATS(isolate(),
2444                            KeyedStoreIC_ElementsTransitionAndStoreStub);
2445        handler = StoreHandler::StoreElementTransition(
2446            isolate(), receiver_map, transition, store_mode, validity_cell);
2447      } else {
2448        handler = StoreElementHandler(receiver_map, store_mode, validity_cell);
2449      }
2450    }
2451    DCHECK(!handler.is_null());
2452    receiver_maps_and_handlers->at(i) =
2453        MapAndHandler(receiver_map, MaybeObjectHandle(handler));
2454  }
2455}
2456
2457namespace {
2458
2459bool MayHaveTypedArrayInPrototypeChain(Handle<JSObject> object) {
2460  for (PrototypeIterator iter(object->GetIsolate(), *object); !iter.IsAtEnd();
2461       iter.Advance()) {
2462    // Be conservative, don't walk into proxies.
2463    if (iter.GetCurrent().IsJSProxy()) return true;
2464    if (iter.GetCurrent().IsJSTypedArray()) return true;
2465  }
2466  return false;
2467}
2468
2469KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, size_t index) {
2470  bool oob_access = IsOutOfBoundsAccess(receiver, index);
2471  // Don't consider this a growing store if the store would send the receiver to
2472  // dictionary mode.
2473  bool allow_growth =
2474      receiver->IsJSArray() && oob_access && index <= JSArray::kMaxArrayIndex &&
2475      !receiver->WouldConvertToSlowElements(static_cast<uint32_t>(index));
2476  if (allow_growth) {
2477    return STORE_AND_GROW_HANDLE_COW;
2478  }
2479  if (receiver->map().has_typed_array_or_rab_gsab_typed_array_elements() &&
2480      oob_access) {
2481    return STORE_IGNORE_OUT_OF_BOUNDS;
2482  }
2483  return receiver->elements().IsCowArray() ? STORE_HANDLE_COW : STANDARD_STORE;
2484}
2485
2486}  // namespace
2487
2488MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2489                                        Handle<Object> key,
2490                                        Handle<Object> value) {
2491  // TODO(verwaest): Let SetProperty do the migration, since storing a property
2492  // might deprecate the current map again, if value does not fit.
2493  if (MigrateDeprecated(isolate(), object)) {
2494    Handle<Object> result;
2495    // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of StoreIC
2496    // so the logic doesn't get mixed here.
2497    ASSIGN_RETURN_ON_EXCEPTION(
2498        isolate(), result,
2499        IsDefineKeyedOwnIC()
2500            ? Runtime::DefineObjectOwnProperty(isolate(), object, key, value,
2501                                               StoreOrigin::kMaybeKeyed)
2502            : Runtime::SetObjectProperty(isolate(), object, key, value,
2503                                         StoreOrigin::kMaybeKeyed),
2504        Object);
2505    return result;
2506  }
2507
2508  Handle<Object> store_handle;
2509
2510  intptr_t maybe_index;
2511  Handle<Name> maybe_name;
2512  KeyType key_type = TryConvertKey(key, isolate(), &maybe_index, &maybe_name);
2513
2514  if (key_type == kName) {
2515    ASSIGN_RETURN_ON_EXCEPTION(
2516        isolate(), store_handle,
2517        StoreIC::Store(object, maybe_name, value, StoreOrigin::kMaybeKeyed),
2518        Object);
2519    if (vector_needs_update()) {
2520      if (ConfigureVectorState(MEGAMORPHIC, key)) {
2521        set_slow_stub_reason("unhandled internalized string key");
2522        TraceIC("StoreIC", key);
2523      }
2524    }
2525    return store_handle;
2526  }
2527
2528  JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
2529
2530  // TODO(jkummerow): Refactor the condition logic here and below.
2531  bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic &&
2532                !object->IsStringWrapper() && !object->IsAccessCheckNeeded() &&
2533                !object->IsJSGlobalProxy();
2534  if (use_ic && !object->IsSmi()) {
2535    // Don't use ICs for maps of the objects in Array's prototype chain. We
2536    // expect to be able to trap element sets to objects with those maps in
2537    // the runtime to enable optimization of element hole access.
2538    Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2539    if (heap_object->map().IsMapInArrayPrototypeChain(isolate())) {
2540      set_slow_stub_reason("map in array prototype");
2541      use_ic = false;
2542    }
2543  }
2544
2545  Handle<Map> old_receiver_map;
2546  bool is_arguments = false;
2547  bool key_is_valid_index = (key_type == kIntPtr);
2548  KeyedAccessStoreMode store_mode = STANDARD_STORE;
2549  if (use_ic && object->IsJSReceiver() && key_is_valid_index) {
2550    Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
2551    old_receiver_map = handle(receiver->map(), isolate());
2552    is_arguments = receiver->IsJSArgumentsObject();
2553    bool is_proxy = receiver->IsJSProxy();
2554    size_t index;
2555    key_is_valid_index = IntPtrKeyToSize(maybe_index, receiver, &index);
2556    if (!is_arguments && !is_proxy) {
2557      if (key_is_valid_index) {
2558        Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
2559        store_mode = GetStoreMode(receiver_object, index);
2560      }
2561    }
2562  }
2563
2564  DCHECK(store_handle.is_null());
2565  ASSIGN_RETURN_ON_EXCEPTION(
2566      isolate(), store_handle,
2567      // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of StoreIC
2568      // so the logic doesn't get mixed here.
2569      IsDefineKeyedOwnIC()
2570          ? Runtime::DefineObjectOwnProperty(isolate(), object, key, value,
2571                                             StoreOrigin::kMaybeKeyed)
2572          : Runtime::SetObjectProperty(isolate(), object, key, value,
2573                                       StoreOrigin::kMaybeKeyed),
2574      Object);
2575  if (use_ic) {
2576    if (!old_receiver_map.is_null()) {
2577      if (is_arguments) {
2578        set_slow_stub_reason("arguments receiver");
2579      } else if (object->IsJSArray() && IsGrowStoreMode(store_mode) &&
2580                 JSArray::HasReadOnlyLength(Handle<JSArray>::cast(object))) {
2581        set_slow_stub_reason("array has read only length");
2582      } else if (object->IsJSObject() && MayHaveTypedArrayInPrototypeChain(
2583                                             Handle<JSObject>::cast(object))) {
2584        // Make sure we don't handle this in IC if there's any JSTypedArray in
2585        // the {receiver}'s prototype chain, since that prototype is going to
2586        // swallow all stores that are out-of-bounds for said prototype, and we
2587        // just let the runtime deal with the complexity of this.
2588        set_slow_stub_reason("typed array in the prototype chain");
2589      } else if (key_is_valid_index) {
2590        if (old_receiver_map->is_abandoned_prototype_map()) {
2591          set_slow_stub_reason("receiver with prototype map");
2592        } else if (old_receiver_map->has_dictionary_elements() ||
2593                   !old_receiver_map->MayHaveReadOnlyElementsInPrototypeChain(
2594                       isolate())) {
2595          // We should go generic if receiver isn't a dictionary, but our
2596          // prototype chain does have dictionary elements. This ensures that
2597          // other non-dictionary receivers in the polymorphic case benefit
2598          // from fast path keyed stores.
2599          Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
2600          UpdateStoreElement(old_receiver_map, store_mode,
2601                             handle(receiver->map(), isolate()));
2602        } else {
2603          set_slow_stub_reason("prototype with potentially read-only elements");
2604        }
2605      } else {
2606        set_slow_stub_reason("non-smi-like key");
2607      }
2608    } else {
2609      set_slow_stub_reason("non-JSObject receiver");
2610    }
2611  }
2612
2613  if (vector_needs_update()) {
2614    ConfigureVectorState(MEGAMORPHIC, key);
2615  }
2616  TraceIC("StoreIC", key);
2617
2618  return store_handle;
2619}
2620
2621namespace {
2622Maybe<bool> StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
2623                            Handle<Object> index, Handle<Object> value) {
2624  DCHECK(index->IsNumber());
2625  PropertyKey key(isolate, index);
2626  LookupIterator it(isolate, array, key, LookupIterator::OWN);
2627
2628  MAYBE_RETURN(JSObject::DefineOwnPropertyIgnoreAttributes(
2629                   &it, value, NONE, Just(ShouldThrow::kThrowOnError)),
2630               Nothing<bool>());
2631  return Just(true);
2632}
2633}  // namespace
2634
2635MaybeHandle<Object> StoreInArrayLiteralIC::Store(Handle<JSArray> array,
2636                                                 Handle<Object> index,
2637                                                 Handle<Object> value) {
2638  DCHECK(!array->map().IsMapInArrayPrototypeChain(isolate()));
2639  DCHECK(index->IsNumber());
2640
2641  if (!FLAG_use_ic || state() == NO_FEEDBACK ||
2642      MigrateDeprecated(isolate(), array)) {
2643    MAYBE_RETURN_NULL(StoreOwnElement(isolate(), array, index, value));
2644    TraceIC("StoreInArrayLiteralIC", index);
2645    return value;
2646  }
2647
2648  // TODO(neis): Convert HeapNumber to Smi if possible?
2649
2650  KeyedAccessStoreMode store_mode = STANDARD_STORE;
2651  if (index->IsSmi()) {
2652    DCHECK_GE(Smi::ToInt(*index), 0);
2653    uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2654    store_mode = GetStoreMode(array, index32);
2655  }
2656
2657  Handle<Map> old_array_map(array->map(), isolate());
2658  MAYBE_RETURN_NULL(StoreOwnElement(isolate(), array, index, value));
2659
2660  if (index->IsSmi()) {
2661    DCHECK(!old_array_map->is_abandoned_prototype_map());
2662    UpdateStoreElement(old_array_map, store_mode,
2663                       handle(array->map(), isolate()));
2664  } else {
2665    set_slow_stub_reason("index out of Smi range");
2666  }
2667
2668  if (vector_needs_update()) {
2669    ConfigureVectorState(MEGAMORPHIC, index);
2670  }
2671  TraceIC("StoreInArrayLiteralIC", index);
2672  return value;
2673}
2674
2675// ----------------------------------------------------------------------------
2676// Static IC stub generators.
2677//
2678//
2679RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2680  HandleScope scope(isolate);
2681  DCHECK_EQ(4, args.length());
2682  // Runtime functions don't follow the IC's calling convention.
2683  Handle<Object> receiver = args.at(0);
2684  Handle<Name> key = args.at<Name>(1);
2685  Handle<TaggedIndex> slot = args.at<TaggedIndex>(2);
2686  Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2687  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2688
2689  // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2690  // LoadIC miss handler if the handler misses. Since the vector Nexus is
2691  // set up outside the IC, handle that here.
2692  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2693  if (IsLoadICKind(kind)) {
2694    LoadIC ic(isolate, vector, vector_slot, kind);
2695    ic.UpdateState(receiver, key);
2696    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2697
2698  } else if (IsLoadGlobalICKind(kind)) {
2699    DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2700    receiver = isolate->global_object();
2701    LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2702    ic.UpdateState(receiver, key);
2703    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2704
2705  } else {
2706    DCHECK(IsKeyedLoadICKind(kind));
2707    KeyedLoadIC ic(isolate, vector, vector_slot, kind);
2708    ic.UpdateState(receiver, key);
2709    RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2710  }
2711}
2712
2713RUNTIME_FUNCTION(Runtime_LoadNoFeedbackIC_Miss) {
2714  HandleScope scope(isolate);
2715  DCHECK_EQ(3, args.length());
2716  // Runtime functions don't follow the IC's calling convention.
2717  Handle<Object> receiver = args.at(0);
2718  Handle<Name> key = args.at<Name>(1);
2719  int slot_kind = args.smi_value_at(2);
2720  FeedbackSlotKind kind = static_cast<FeedbackSlotKind>(slot_kind);
2721
2722  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2723  FeedbackSlot vector_slot = FeedbackSlot::Invalid();
2724  // This function is only called after looking up in the ScriptContextTable so
2725  // it is safe to call LoadIC::Load for global loads as well.
2726  LoadIC ic(isolate, vector, vector_slot, kind);
2727  ic.UpdateState(receiver, key);
2728  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2729}
2730
2731RUNTIME_FUNCTION(Runtime_LoadWithReceiverNoFeedbackIC_Miss) {
2732  HandleScope scope(isolate);
2733  DCHECK_EQ(3, args.length());
2734  // Runtime functions don't follow the IC's calling convention.
2735  Handle<Object> receiver = args.at(0);
2736  Handle<Object> object = args.at(1);
2737  Handle<Name> key = args.at<Name>(2);
2738
2739  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2740  FeedbackSlot vector_slot = FeedbackSlot::Invalid();
2741  LoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadProperty);
2742  ic.UpdateState(object, key);
2743  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(object, key, true, receiver));
2744}
2745
2746RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2747  HandleScope scope(isolate);
2748  DCHECK_EQ(4, args.length());
2749  // Runtime functions don't follow the IC's calling convention.
2750  Handle<JSGlobalObject> global = isolate->global_object();
2751  Handle<String> name = args.at<String>(0);
2752  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2753  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2754  int typeof_value = args.smi_value_at(3);
2755  TypeofMode typeof_mode = static_cast<TypeofMode>(typeof_value);
2756  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2757
2758  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2759  if (!maybe_vector->IsUndefined()) {
2760    DCHECK(maybe_vector->IsFeedbackVector());
2761    vector = Handle<FeedbackVector>::cast(maybe_vector);
2762  }
2763
2764  FeedbackSlotKind kind = (typeof_mode == TypeofMode::kInside)
2765                              ? FeedbackSlotKind::kLoadGlobalInsideTypeof
2766                              : FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
2767  LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2768  ic.UpdateState(global, name);
2769
2770  Handle<Object> result;
2771  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2772  return *result;
2773}
2774
2775RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2776  HandleScope scope(isolate);
2777  DCHECK_EQ(3, args.length());
2778  Handle<String> name = args.at<String>(0);
2779
2780  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2781  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2782  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2783  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2784
2785  LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2786  Handle<Object> result;
2787  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name, false));
2788  return *result;
2789}
2790
2791RUNTIME_FUNCTION(Runtime_LoadWithReceiverIC_Miss) {
2792  HandleScope scope(isolate);
2793  DCHECK_EQ(5, args.length());
2794  // Runtime functions don't follow the IC's calling convention.
2795  Handle<Object> receiver = args.at(0);
2796  Handle<Object> object = args.at(1);
2797  Handle<Name> key = args.at<Name>(2);
2798  Handle<TaggedIndex> slot = args.at<TaggedIndex>(3);
2799  Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2800  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2801
2802  DCHECK(IsLoadICKind(vector->GetKind(vector_slot)));
2803  LoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadProperty);
2804  ic.UpdateState(object, key);
2805  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(object, key, true, receiver));
2806}
2807
2808RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2809  HandleScope scope(isolate);
2810  DCHECK_EQ(4, args.length());
2811  // Runtime functions don't follow the IC's calling convention.
2812  Handle<Object> receiver = args.at(0);
2813  Handle<Object> key = args.at(1);
2814  Handle<TaggedIndex> slot = args.at<TaggedIndex>(2);
2815  Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2816
2817  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2818  if (!maybe_vector->IsUndefined()) {
2819    DCHECK(maybe_vector->IsFeedbackVector());
2820    vector = Handle<FeedbackVector>::cast(maybe_vector);
2821  }
2822  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2823  KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadKeyed);
2824  ic.UpdateState(receiver, key);
2825  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2826}
2827
2828RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2829  HandleScope scope(isolate);
2830  DCHECK_EQ(5, args.length());
2831  // Runtime functions don't follow the IC's calling convention.
2832  Handle<Object> value = args.at(0);
2833  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2834  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2835  Handle<Object> receiver = args.at(3);
2836  Handle<Name> key = args.at<Name>(4);
2837
2838  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2839
2840  // When there is no feedback vector it is OK to use the SetNamedStrict as
2841  // the feedback slot kind. We only reuse this for DefineNamedOwnIC when
2842  // installing the handler for storing const properties. This will happen only
2843  // when feedback vector is available.
2844  FeedbackSlotKind kind = FeedbackSlotKind::kSetNamedStrict;
2845  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2846  if (!maybe_vector->IsUndefined()) {
2847    DCHECK(maybe_vector->IsFeedbackVector());
2848    vector = Handle<FeedbackVector>::cast(maybe_vector);
2849    kind = vector->GetKind(vector_slot);
2850  }
2851
2852  DCHECK(IsSetNamedICKind(kind) || IsDefineNamedOwnICKind(kind));
2853  StoreIC ic(isolate, vector, vector_slot, kind);
2854  ic.UpdateState(receiver, key);
2855  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2856}
2857
2858RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Miss) {
2859  HandleScope scope(isolate);
2860  DCHECK_EQ(5, args.length());
2861  // Runtime functions don't follow the IC's calling convention.
2862  Handle<Object> value = args.at(0);
2863  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2864  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2865  Handle<Object> receiver = args.at(3);
2866  Handle<Name> key = args.at<Name>(4);
2867
2868  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2869
2870  // When there is no feedback vector it is OK to use the DefineNamedOwn
2871  // feedback kind. There _should_ be a vector, though.
2872  FeedbackSlotKind kind = FeedbackSlotKind::kDefineNamedOwn;
2873  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2874  if (!maybe_vector->IsUndefined()) {
2875    DCHECK(maybe_vector->IsFeedbackVector());
2876    vector = Handle<FeedbackVector>::cast(maybe_vector);
2877    kind = vector->GetKind(vector_slot);
2878  }
2879
2880  DCHECK(IsDefineNamedOwnICKind(kind));
2881
2882  // TODO(v8:12548): refactor DefineNamedOwnIC as a subclass of StoreIC, which
2883  // can be called here.
2884  StoreIC ic(isolate, vector, vector_slot, kind);
2885  ic.UpdateState(receiver, key);
2886  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2887}
2888
2889RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Slow) {
2890  HandleScope scope(isolate);
2891  DCHECK_EQ(3, args.length());
2892
2893  Handle<Object> value = args.at(0);
2894  Handle<Object> object = args.at(1);
2895  Handle<Object> key = args.at(2);
2896
2897  // Unlike DefineKeyedOwnIC, DefineNamedOwnIC doesn't handle private
2898  // fields and is used for defining data properties in object literals
2899  // and defining named public class fields.
2900  DCHECK(!key->IsSymbol() || !Symbol::cast(*key).is_private_name());
2901
2902  PropertyKey lookup_key(isolate, key);
2903  LookupIterator it(isolate, object, lookup_key, LookupIterator::OWN);
2904
2905  MAYBE_RETURN(
2906      JSReceiver::CreateDataProperty(&it, value, Nothing<ShouldThrow>()),
2907      ReadOnlyRoots(isolate).exception());
2908  return *value;
2909}
2910
2911RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2912  HandleScope scope(isolate);
2913  DCHECK_EQ(4, args.length());
2914  // Runtime functions don't follow the IC's calling convention.
2915  Handle<Object> value = args.at(0);
2916  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2917  Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2918  Handle<Name> key = args.at<Name>(3);
2919
2920  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2921  FeedbackSlotKind kind = vector->GetKind(vector_slot);
2922  StoreGlobalIC ic(isolate, vector, vector_slot, kind);
2923  Handle<JSGlobalObject> global = isolate->global_object();
2924  ic.UpdateState(global, key);
2925  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2926}
2927
2928RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
2929  HandleScope scope(isolate);
2930  DCHECK_EQ(2, args.length());
2931  // Runtime functions don't follow the IC's calling convention.
2932  Handle<Object> value = args.at(0);
2933  Handle<Name> key = args.at<Name>(1);
2934
2935  // TODO(mythria): Replace StoreGlobalStrict/Sloppy with SetNamedProperty.
2936  StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(),
2937                   FeedbackSlotKind::kStoreGlobalStrict);
2938  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2939}
2940
2941// TODO(mythria): Remove Feedback vector and slot. Since they are not used apart
2942// from the DCHECK.
2943RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
2944  HandleScope scope(isolate);
2945  DCHECK_EQ(5, args.length());
2946  // Runtime functions don't follow the IC's calling convention.
2947  Handle<Object> value = args.at(0);
2948  Handle<String> name = args.at<String>(4);
2949
2950#ifdef DEBUG
2951  {
2952    Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
2953    Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2954    FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2955    FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2956    DCHECK(IsStoreGlobalICKind(slot_kind));
2957    Handle<Object> receiver = args.at(3);
2958    DCHECK(receiver->IsJSGlobalProxy());
2959  }
2960#endif
2961
2962  Handle<JSGlobalObject> global = isolate->global_object();
2963  Handle<Context> native_context = isolate->native_context();
2964  Handle<ScriptContextTable> script_contexts(
2965      native_context->script_context_table(), isolate);
2966
2967  VariableLookupResult lookup_result;
2968  if (script_contexts->Lookup(name, &lookup_result)) {
2969    Handle<Context> script_context = ScriptContextTable::GetContext(
2970        isolate, script_contexts, lookup_result.context_index);
2971    if (lookup_result.mode == VariableMode::kConst) {
2972      THROW_NEW_ERROR_RETURN_FAILURE(
2973          isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
2974    }
2975
2976    Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
2977                                  isolate);
2978
2979    if (previous_value->IsTheHole(isolate)) {
2980      THROW_NEW_ERROR_RETURN_FAILURE(
2981          isolate, NewReferenceError(
2982                       MessageTemplate::kAccessedUninitializedVariable, name));
2983    }
2984
2985    script_context->set(lookup_result.slot_index, *value);
2986    return *value;
2987  }
2988
2989  RETURN_RESULT_OR_FAILURE(
2990      isolate, Runtime::SetObjectProperty(isolate, global, name, value,
2991                                          StoreOrigin::kMaybeKeyed));
2992}
2993
2994RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2995  HandleScope scope(isolate);
2996  DCHECK_EQ(5, args.length());
2997  // Runtime functions don't follow the IC's calling convention.
2998  Handle<Object> value = args.at(0);
2999  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
3000  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3001  Handle<Object> receiver = args.at(3);
3002  Handle<Object> key = args.at(4);
3003  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3004
3005  // When the feedback vector is not valid the slot can only be of type
3006  // StoreKeyed. Storing in array literals falls back to
3007  // StoreInArrayLiterIC_Miss. This function is also used from store handlers
3008  // installed in feedback vectors. In such cases, we need to get the kind from
3009  // feedback vector slot since the handlers are used for both for StoreKeyed
3010  // and StoreInArrayLiteral kinds.
3011  FeedbackSlotKind kind = FeedbackSlotKind::kSetKeyedStrict;
3012  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
3013  if (!maybe_vector->IsUndefined()) {
3014    DCHECK(maybe_vector->IsFeedbackVector());
3015    vector = Handle<FeedbackVector>::cast(maybe_vector);
3016    kind = vector->GetKind(vector_slot);
3017  }
3018
3019  // The elements store stubs miss into this function, but they are shared by
3020  // different ICs.
3021  // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of KeyedStoreIC,
3022  // which can be called here.
3023  if (IsKeyedStoreICKind(kind) || IsDefineKeyedOwnICKind(kind)) {
3024    KeyedStoreIC ic(isolate, vector, vector_slot, kind);
3025    ic.UpdateState(receiver, key);
3026    RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
3027  } else {
3028    DCHECK(IsStoreInArrayLiteralICKind(kind));
3029    DCHECK(receiver->IsJSArray());
3030    DCHECK(key->IsNumber());
3031    StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
3032    ic.UpdateState(receiver, key);
3033    RETURN_RESULT_OR_FAILURE(
3034        isolate, ic.Store(Handle<JSArray>::cast(receiver), key, value));
3035  }
3036}
3037
3038RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Miss) {
3039  HandleScope scope(isolate);
3040  DCHECK_EQ(5, args.length());
3041  // Runtime functions don't follow the IC's calling convention.
3042  Handle<Object> value = args.at(0);
3043  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
3044  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3045  Handle<Object> receiver = args.at(3);
3046  Handle<Object> key = args.at(4);
3047  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3048
3049  FeedbackSlotKind kind = FeedbackSlotKind::kDefineKeyedOwn;
3050  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
3051  if (!maybe_vector->IsUndefined()) {
3052    DCHECK(maybe_vector->IsFeedbackVector());
3053    vector = Handle<FeedbackVector>::cast(maybe_vector);
3054    kind = vector->GetKind(vector_slot);
3055    DCHECK(IsDefineKeyedOwnICKind(kind));
3056  }
3057
3058  // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of KeyedStoreIC,
3059  // which can be called here.
3060  KeyedStoreIC ic(isolate, vector, vector_slot, kind);
3061  ic.UpdateState(receiver, key);
3062  RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
3063}
3064
3065RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
3066  HandleScope scope(isolate);
3067  DCHECK_EQ(5, args.length());
3068  // Runtime functions don't follow the IC's calling convention.
3069  Handle<Object> value = args.at(0);
3070  Handle<TaggedIndex> slot = args.at<TaggedIndex>(1);
3071  Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3072  Handle<Object> receiver = args.at(3);
3073  Handle<Object> key = args.at(4);
3074  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
3075  if (!maybe_vector->IsUndefined()) {
3076    DCHECK(maybe_vector->IsFeedbackVector());
3077    vector = Handle<FeedbackVector>::cast(maybe_vector);
3078  }
3079  DCHECK(receiver->IsJSArray());
3080  DCHECK(key->IsNumber());
3081  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3082  StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
3083  RETURN_RESULT_OR_FAILURE(
3084      isolate, ic.Store(Handle<JSArray>::cast(receiver), key, value));
3085}
3086
3087RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
3088  HandleScope scope(isolate);
3089  DCHECK_EQ(3, args.length());
3090  // Runtime functions don't follow the IC's calling convention.
3091  Handle<Object> value = args.at(0);
3092  Handle<Object> object = args.at(1);
3093  Handle<Object> key = args.at(2);
3094  RETURN_RESULT_OR_FAILURE(
3095      isolate, Runtime::SetObjectProperty(isolate, object, key, value,
3096                                          StoreOrigin::kMaybeKeyed));
3097}
3098
3099RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Slow) {
3100  HandleScope scope(isolate);
3101  DCHECK_EQ(3, args.length());
3102  // Runtime functions don't follow the IC's calling convention.
3103  Handle<Object> value = args.at(0);
3104  Handle<Object> object = args.at(1);
3105  Handle<Object> key = args.at(2);
3106  RETURN_RESULT_OR_FAILURE(
3107      isolate, Runtime::DefineObjectOwnProperty(isolate, object, key, value,
3108                                                StoreOrigin::kMaybeKeyed));
3109}
3110
3111RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
3112  HandleScope scope(isolate);
3113  DCHECK_EQ(3, args.length());
3114  // Runtime functions don't follow the IC's calling convention.
3115  Handle<Object> value = args.at(0);
3116  Handle<Object> array = args.at(1);
3117  Handle<Object> index = args.at(2);
3118  StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value);
3119  return *value;
3120}
3121
3122RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
3123  HandleScope scope(isolate);
3124  DCHECK_EQ(6, args.length());
3125  // Runtime functions don't follow the IC's calling convention.
3126  Handle<Object> object = args.at(0);
3127  Handle<Object> key = args.at(1);
3128  Handle<Object> value = args.at(2);
3129  Handle<Map> map = args.at<Map>(3);
3130  Handle<TaggedIndex> slot = args.at<TaggedIndex>(4);
3131  Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
3132  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3133  FeedbackSlotKind kind = vector->GetKind(vector_slot);
3134
3135  if (object->IsJSObject()) {
3136    JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
3137                                     map->elements_kind());
3138  }
3139
3140  if (IsStoreInArrayLiteralICKind(kind)) {
3141    StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value);
3142    return *value;
3143  } else {
3144    DCHECK(IsKeyedStoreICKind(kind) || IsSetNamedICKind(kind) ||
3145           IsDefineKeyedOwnICKind(kind));
3146    RETURN_RESULT_OR_FAILURE(
3147        isolate,
3148        IsDefineKeyedOwnICKind(kind)
3149            ? Runtime::DefineObjectOwnProperty(isolate, object, key, value,
3150                                               StoreOrigin::kMaybeKeyed)
3151            : Runtime::SetObjectProperty(isolate, object, key, value,
3152                                         StoreOrigin::kMaybeKeyed));
3153  }
3154}
3155
3156static bool CanFastCloneObject(Handle<Map> map) {
3157  DisallowGarbageCollection no_gc;
3158  if (map->IsNullOrUndefinedMap()) return true;
3159  if (!map->IsJSObjectMap() ||
3160      !IsSmiOrObjectElementsKind(map->elements_kind()) ||
3161      !map->OnlyHasSimpleProperties()) {
3162    return false;
3163  }
3164
3165  DescriptorArray descriptors = map->instance_descriptors();
3166  for (InternalIndex i : map->IterateOwnDescriptors()) {
3167    PropertyDetails details = descriptors.GetDetails(i);
3168    Name key = descriptors.GetKey(i);
3169    if (details.kind() != PropertyKind::kData || !details.IsEnumerable() ||
3170        key.IsPrivateName()) {
3171      return false;
3172    }
3173  }
3174
3175  return true;
3176}
3177
3178static Handle<Map> FastCloneObjectMap(Isolate* isolate, Handle<Map> source_map,
3179                                      int flags) {
3180  SLOW_DCHECK(CanFastCloneObject(source_map));
3181  Handle<JSFunction> constructor(isolate->native_context()->object_function(),
3182                                 isolate);
3183  DCHECK(constructor->has_initial_map());
3184  Handle<Map> initial_map(constructor->initial_map(), isolate);
3185  Handle<Map> map = initial_map;
3186
3187  if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() !=
3188                                         initial_map->GetInObjectProperties()) {
3189    int inobject_properties = source_map->GetInObjectProperties();
3190    int instance_size =
3191        JSObject::kHeaderSize + kTaggedSize * inobject_properties;
3192    int unused = source_map->UnusedInObjectProperties();
3193    DCHECK(instance_size <= JSObject::kMaxInstanceSize);
3194    map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties,
3195                              unused);
3196  }
3197
3198  if (flags & ObjectLiteral::kHasNullPrototype) {
3199    if (map.is_identical_to(initial_map)) {
3200      map = Map::Copy(isolate, map, "ObjectWithNullProto");
3201    }
3202    Map::SetPrototype(isolate, map, isolate->factory()->null_value());
3203  }
3204
3205  if (source_map->NumberOfOwnDescriptors() == 0) {
3206    return map;
3207  }
3208  DCHECK(!source_map->IsNullOrUndefinedMap());
3209
3210  if (map.is_identical_to(initial_map)) {
3211    map = Map::Copy(isolate, map, "InitializeClonedDescriptors");
3212  }
3213
3214  Handle<DescriptorArray> source_descriptors(
3215      source_map->instance_descriptors(isolate), isolate);
3216  int size = source_map->NumberOfOwnDescriptors();
3217  int slack = 0;
3218  Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone(
3219      isolate, source_descriptors, size, slack);
3220  map->InitializeDescriptors(isolate, *descriptors);
3221  map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map);
3222
3223  // Update bitfields
3224  map->set_may_have_interesting_symbols(
3225      source_map->may_have_interesting_symbols());
3226
3227  return map;
3228}
3229
3230static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
3231                                                 Handle<Object> source,
3232                                                 int flags) {
3233  Handle<JSObject> new_object;
3234  if (flags & ObjectLiteral::kHasNullPrototype) {
3235    new_object = isolate->factory()->NewJSObjectWithNullProto();
3236  } else {
3237    Handle<JSFunction> constructor(isolate->native_context()->object_function(),
3238                                   isolate);
3239    new_object = isolate->factory()->NewJSObject(constructor);
3240  }
3241
3242  if (source->IsNullOrUndefined()) {
3243    return new_object;
3244  }
3245
3246  MAYBE_RETURN(
3247      JSReceiver::SetOrCopyDataProperties(
3248          isolate, new_object, source,
3249          PropertiesEnumerationMode::kPropertyAdditionOrder, nullptr, false),
3250      MaybeHandle<JSObject>());
3251  return new_object;
3252}
3253
3254RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
3255  HandleScope scope(isolate);
3256  DCHECK_EQ(4, args.length());
3257  Handle<Object> source = args.at(0);
3258  int flags = args.smi_value_at(1);
3259
3260  if (!MigrateDeprecated(isolate, source)) {
3261    int index = args.tagged_index_value_at(2);
3262    FeedbackSlot slot = FeedbackVector::ToSlot(index);
3263    Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
3264    if (maybe_vector->IsFeedbackVector()) {
3265      FeedbackNexus nexus(Handle<FeedbackVector>::cast(maybe_vector), slot);
3266      if (!source->IsSmi() && !nexus.IsMegamorphic()) {
3267        Handle<Map> source_map(Handle<HeapObject>::cast(source)->map(),
3268                               isolate);
3269        if (CanFastCloneObject(source_map)) {
3270          Handle<Map> target_map =
3271              FastCloneObjectMap(isolate, source_map, flags);
3272          nexus.ConfigureCloneObject(source_map, target_map);
3273          return *target_map;
3274        }
3275
3276        nexus.ConfigureMegamorphic();
3277      }
3278    }
3279  }
3280
3281  RETURN_RESULT_OR_FAILURE(isolate,
3282                           CloneObjectSlowPath(isolate, source, flags));
3283}
3284
3285RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
3286  Handle<JSObject> receiver = args.at<JSObject>(0);
3287  Handle<JSObject> holder = args.at<JSObject>(1);
3288  Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
3289  Handle<Name> name = args.at<Name>(3);
3290  Handle<Object> value = args.at(4);
3291  HandleScope scope(isolate);
3292
3293#ifdef V8_RUNTIME_CALL_STATS
3294  if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) {
3295    RETURN_RESULT_OR_FAILURE(
3296        isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
3297                                            StoreOrigin::kMaybeKeyed));
3298  }
3299#endif
3300
3301  DCHECK(info->IsCompatibleReceiver(*receiver));
3302
3303  PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
3304                                      Nothing<ShouldThrow>());
3305  arguments.CallAccessorSetter(info, name, value);
3306  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3307  return *value;
3308}
3309
3310/**
3311 * Loads a property with an interceptor performing post interceptor
3312 * lookup if interceptor failed.
3313 */
3314RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
3315  HandleScope scope(isolate);
3316  DCHECK_EQ(5, args.length());
3317  Handle<Name> name = args.at<Name>(0);
3318  Handle<Object> receiver = args.at(1);
3319  Handle<JSObject> holder = args.at<JSObject>(2);
3320
3321  if (!receiver->IsJSReceiver()) {
3322    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3323        isolate, receiver, Object::ConvertReceiver(isolate, receiver));
3324  }
3325
3326  Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
3327  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3328                                      *holder, Just(kDontThrow));
3329  Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
3330
3331  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3332
3333  if (!result.is_null()) return *result;
3334
3335  LookupIterator it(isolate, receiver, name, holder);
3336  // Skip any lookup work until we hit the (possibly non-masking) interceptor.
3337  while (it.state() != LookupIterator::INTERCEPTOR ||
3338         !it.GetHolder<JSObject>().is_identical_to(holder)) {
3339    DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
3340    it.Next();
3341  }
3342  // Skip past the interceptor.
3343  it.Next();
3344  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
3345
3346  if (it.IsFound()) return *result;
3347
3348  Handle<TaggedIndex> slot = args.at<TaggedIndex>(3);
3349  Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
3350  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3351  FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
3352  // It could actually be any kind of load IC slot here but the predicate
3353  // handles all the cases properly.
3354  if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
3355    return ReadOnlyRoots(isolate).undefined_value();
3356  }
3357
3358  // Throw a reference error.
3359  THROW_NEW_ERROR_RETURN_FAILURE(
3360      isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
3361}
3362
3363RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
3364  HandleScope scope(isolate);
3365  DCHECK_EQ(3, args.length());
3366  // Runtime functions don't follow the IC's calling convention.
3367  Handle<Object> value = args.at(0);
3368  Handle<JSObject> receiver = args.at<JSObject>(1);
3369  Handle<Name> name = args.at<Name>(2);
3370
3371  // TODO(ishell): Cache interceptor_holder in the store handler like we do
3372  // for LoadHandler::kInterceptor case.
3373  Handle<JSObject> interceptor_holder = receiver;
3374  if (receiver->IsJSGlobalProxy() &&
3375      (!receiver->HasNamedInterceptor() ||
3376       receiver->GetNamedInterceptor().non_masking())) {
3377    interceptor_holder =
3378        handle(JSObject::cast(receiver->map().prototype()), isolate);
3379  }
3380  DCHECK(interceptor_holder->HasNamedInterceptor());
3381  Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
3382                                      isolate);
3383
3384  DCHECK(!interceptor->non_masking());
3385  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3386                                      *receiver, Just(kDontThrow));
3387
3388  Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
3389  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3390  if (!result.is_null()) return *value;
3391
3392  LookupIterator it(isolate, receiver, name, receiver);
3393  // Skip past any access check on the receiver.
3394  if (it.state() == LookupIterator::ACCESS_CHECK) {
3395    DCHECK(it.HasAccess());
3396    it.Next();
3397  }
3398  // Skip past the interceptor on the receiver.
3399  DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
3400  it.Next();
3401
3402  MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed),
3403               ReadOnlyRoots(isolate).exception());
3404  return *value;
3405}
3406
3407RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
3408  // TODO(verwaest): This should probably get the holder and receiver as input.
3409  HandleScope scope(isolate);
3410  Handle<JSObject> receiver = args.at<JSObject>(0);
3411  DCHECK_GE(args.smi_value_at(1), 0);
3412  uint32_t index = args.smi_value_at(1);
3413
3414  Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
3415                                      isolate);
3416  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3417                                      *receiver, Just(kDontThrow));
3418  Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
3419
3420  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3421
3422  if (result.is_null()) {
3423    LookupIterator it(isolate, receiver, index, receiver);
3424    DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
3425    it.Next();
3426    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3427                                       Object::GetProperty(&it));
3428  }
3429
3430  return *result;
3431}
3432
3433RUNTIME_FUNCTION(Runtime_KeyedHasIC_Miss) {
3434  HandleScope scope(isolate);
3435  DCHECK_EQ(4, args.length());
3436  // Runtime functions don't follow the IC's calling convention.
3437  Handle<Object> receiver = args.at(0);
3438  Handle<Object> key = args.at(1);
3439  Handle<TaggedIndex> slot = args.at<TaggedIndex>(2);
3440  Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
3441
3442  Handle<FeedbackVector> vector = Handle<FeedbackVector>();
3443  if (!maybe_vector->IsUndefined()) {
3444    DCHECK(maybe_vector->IsFeedbackVector());
3445    vector = Handle<FeedbackVector>::cast(maybe_vector);
3446  }
3447  FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
3448  KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kHasKeyed);
3449  ic.UpdateState(receiver, key);
3450  RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
3451}
3452
3453RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) {
3454  HandleScope scope(isolate);
3455  Handle<JSObject> receiver = args.at<JSObject>(0);
3456  DCHECK_GE(args.smi_value_at(1), 0);
3457  uint32_t index = args.smi_value_at(1);
3458
3459  Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
3460                                      isolate);
3461  PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3462                                      *receiver, Just(kDontThrow));
3463
3464  if (!interceptor->query().IsUndefined(isolate)) {
3465    Handle<Object> result = arguments.CallIndexedQuery(interceptor, index);
3466    if (!result.is_null()) {
3467      int32_t value;
3468      CHECK(result->ToInt32(&value));
3469      return value == ABSENT ? ReadOnlyRoots(isolate).false_value()
3470                             : ReadOnlyRoots(isolate).true_value();
3471    }
3472  } else if (!interceptor->getter().IsUndefined(isolate)) {
3473    Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
3474    if (!result.is_null()) {
3475      return ReadOnlyRoots(isolate).true_value();
3476    }
3477  }
3478
3479  LookupIterator it(isolate, receiver, index, receiver);
3480  DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
3481  it.Next();
3482  Maybe<bool> maybe = JSReceiver::HasProperty(&it);
3483  if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
3484  return maybe.FromJust() ? ReadOnlyRoots(isolate).true_value()
3485                          : ReadOnlyRoots(isolate).false_value();
3486}
3487
3488}  // namespace internal
3489}  // namespace v8
3490