• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
51 namespace v8 {
52 namespace internal {
53 
54 // Aliases to avoid having to repeat the class.
55 // With C++20 we can use "using" to introduce scoped enums.
56 constexpr InlineCacheState NO_FEEDBACK = InlineCacheState::NO_FEEDBACK;
57 constexpr InlineCacheState UNINITIALIZED = InlineCacheState::UNINITIALIZED;
58 constexpr InlineCacheState MONOMORPHIC = InlineCacheState::MONOMORPHIC;
59 constexpr InlineCacheState RECOMPUTE_HANDLER =
60     InlineCacheState::RECOMPUTE_HANDLER;
61 constexpr InlineCacheState POLYMORPHIC = InlineCacheState::POLYMORPHIC;
62 constexpr InlineCacheState MEGAMORPHIC = InlineCacheState::MEGAMORPHIC;
63 constexpr InlineCacheState MEGADOM = InlineCacheState::MEGADOM;
64 constexpr InlineCacheState GENERIC = InlineCacheState::GENERIC;
65 
TransitionMarkFromState(IC::State state)66 char 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 
88 namespace {
89 
GetModifier(KeyedAccessLoadMode mode)90 const char* GetModifier(KeyedAccessLoadMode mode) {
91   if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB";
92   return "";
93 }
94 
GetModifier(KeyedAccessStoreMode mode)95 const 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 
TraceIC(const char * type,Handle<Object> name)111 void 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 
TraceIC(const char * type,Handle<Object> name,State old_state,State new_state)118 void 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 
IC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot,FeedbackSlotKind kind)193 IC::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 
LookupForRead(LookupIterator * it,bool is_has_property)206 static 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 
ShouldRecomputeHandler(Handle<String> name)241 bool 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 
RecomputeHandlerForName(Handle<Object> name)269 bool 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 
UpdateState(Handle<Object> lookup_start_object,Handle<Object> name)280 void 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 
TypeError(MessageTemplate index,Handle<Object> object,Handle<Object> key)295 MaybeHandle<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 
ReferenceError(Handle<Name> name)301 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
302   HandleScope scope(isolate());
303   THROW_NEW_ERROR(
304       isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
305 }
306 
OnFeedbackChanged(const char * reason)307 void 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
OnFeedbackChanged(Isolate * isolate,FeedbackVector vector,FeedbackSlot slot,const char * reason)315 void 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 
352 namespace {
353 
MigrateDeprecated(Isolate * isolate,Handle<Object> object)354 bool 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 
ConfigureVectorState(IC::State new_state,Handle<Object> key)364 bool 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 
ConfigureVectorState(Handle<Name> name,Handle<Map> map,Handle<Object> handler)376 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
377                               Handle<Object> handler) {
378   ConfigureVectorState(name, map, MaybeObjectHandle(handler));
379 }
380 
ConfigureVectorState(Handle<Name> name,Handle<Map> map,const MaybeObjectHandle & handler)381 void 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 
ConfigureVectorState(Handle<Name> name,MapHandles const & maps,MaybeObjectHandles * handlers)394 void 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 
ConfigureVectorState(Handle<Name> name,std::vector<MapAndHandler> const & maps_and_handlers)405 void 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 
Load(Handle<Object> object,Handle<Name> name,bool update_feedback,Handle<Object> receiver)415 MaybeHandle<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 
Load(Handle<Name> name,bool update_feedback)523 MaybeHandle<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 
AddOneReceiverMapIfMissing(MapHandles * receiver_maps,Handle<Map> new_receiver_map)575 static 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 
AddOneReceiverMapIfMissing(std::vector<MapAndHandler> * receiver_maps_and_handlers,Handle<Map> new_receiver_map)587 static 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 
UpdateMegaDOMIC(const MaybeObjectHandle & handler,Handle<Name> name)603 bool 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 
UpdatePolymorphicIC(Handle<Name> name,const MaybeObjectHandle & handler)652 bool 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 
UpdateMonomorphicIC(const MaybeObjectHandle & handler,Handle<Name> name)735 void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
736                              Handle<Name> name) {
737   DCHECK(IsHandler(*handler));
738   ConfigureVectorState(name, lookup_start_object_map(), handler);
739 }
740 
CopyICToMegamorphicCache(Handle<Name> name)741 void 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 
IsTransitionOfMonomorphicTarget(Map source_map,Map target_map)749 bool 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 
SetCache(Handle<Name> name,Handle<Object> handler)766 void IC::SetCache(Handle<Name> name, Handle<Object> handler) {
767   SetCache(name, MaybeObjectHandle(handler));
768 }
769 
SetCache(Handle<Name> name,const MaybeObjectHandle & handler)770 void 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 
UpdateCaches(LookupIterator * lookup)807 void 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 
stub_cache()845 StubCache* 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 
UpdateMegamorphicCache(Handle<Map> map,Handle<Name> name,const MaybeObjectHandle & handler)858 void 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 
865 namespace {
866 
867 #if V8_ENABLE_WEBASSEMBLY
868 
GetWasmValueType(wasm::ValueType type)869 inline 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 
MakeLoadWasmStructFieldHandler(Isolate * isolate,Handle<JSReceiver> holder,LookupIterator * lookup)896 Handle<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 
CodeHandler(Builtin builtin)927 Handle<Object> IC::CodeHandler(Builtin builtin) {
928   return MakeCodeHandler(isolate(), builtin);
929 }
930 
ComputeHandler(LookupIterator * lookup)931 Handle<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 
CanChangeToAllowOutOfBounds(Handle<Map> receiver_map)1227 bool 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 
UpdateLoadElement(Handle<HeapObject> receiver,KeyedAccessLoadMode load_mode)1233 void 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 
1315 namespace {
1316 
AllowConvertHoleElementToUndefined(Isolate * isolate,Handle<Map> receiver_map)1317 bool 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 
LoadElementHandler(Handle<Map> receiver_map,KeyedAccessLoadMode load_mode)1349 Handle<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 
LoadElementPolymorphicHandlers(MapHandles * receiver_maps,MaybeObjectHandles * handlers,KeyedAccessLoadMode load_mode)1411 void 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 
1437 namespace {
1438 
1439 enum KeyType { kIntPtr, kName, kBailout };
1440 
1441 // The cases where kIntPtr is returned must match what
1442 // CodeStubAssembler::TryToIntptr can handle!
TryConvertKey(Handle<Object> key,Isolate * isolate,intptr_t * index_out,Handle<Name> * name_out)1443 KeyType 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 
IntPtrKeyToSize(intptr_t index,Handle<HeapObject> receiver,size_t * out)1479 bool 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 
CanCache(Handle<Object> receiver,InlineCacheState state)1505 bool 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 
IsOutOfBoundsAccess(Handle<Object> receiver,size_t index)1511 bool 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 
GetLoadMode(Isolate * isolate,Handle<Object> receiver,size_t index)1527 KeyedAccessLoadMode 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 
RuntimeLoad(Handle<Object> object,Handle<Object> key)1542 MaybeHandle<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 
Load(Handle<Object> object,Handle<Object> key)1559 MaybeHandle<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 
LookupForWrite(LookupIterator * it,Handle<Object> value,StoreOrigin store_origin)1595 bool 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 
Store(Handle<Name> name,Handle<Object> value)1686 MaybeHandle<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 
1739 namespace {
DefineOwnDataProperty(LookupIterator * it,LookupIterator::State original_state,Handle<Object> value,Maybe<ShouldThrow> should_throw,StoreOrigin store_origin)1740 Maybe<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 
Store(Handle<Object> object,Handle<Name> name,Handle<Object> value,StoreOrigin store_origin)1803 MaybeHandle<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 
UpdateCaches(LookupIterator * lookup,Handle<Object> value,StoreOrigin store_origin)1913 void 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 
ComputeHandler(LookupIterator * lookup)1939 MaybeObjectHandle 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 
UpdateStoreElement(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode,Handle<Map> new_receiver_map)2198 void 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 
StoreElementHandler(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode,MaybeHandle<Object> prev_validity_cell)2335 Handle<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 
StoreElementPolymorphicHandlers(std::vector<MapAndHandler> * receiver_maps_and_handlers,KeyedAccessStoreMode store_mode)2393 void 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 
2457 namespace {
2458 
MayHaveTypedArrayInPrototypeChain(Handle<JSObject> object)2459 bool 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 
GetStoreMode(Handle<JSObject> receiver,size_t index)2469 KeyedAccessStoreMode 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 
Store(Handle<Object> object,Handle<Object> key,Handle<Object> value)2488 MaybeHandle<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 
2621 namespace {
StoreOwnElement(Isolate * isolate,Handle<JSArray> array,Handle<Object> index,Handle<Object> value)2622 Maybe<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 
Store(Handle<JSArray> array,Handle<Object> index,Handle<Object> value)2635 MaybeHandle<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 //
RUNTIME_FUNCTION(Runtime_LoadIC_Miss)2679 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadNoFeedbackIC_Miss)2713 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadWithReceiverNoFeedbackIC_Miss)2731 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss)2746 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow)2775 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadWithReceiverIC_Miss)2791 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss)2808 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreIC_Miss)2828 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Miss)2858 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Slow)2889 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss)2911 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss)2928 RUNTIME_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.
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow)2943 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss)2994 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Miss)3038 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss)3065 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow)3087 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Slow)3099 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow)3111 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss)3122 RUNTIME_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 
CanFastCloneObject(Handle<Map> map)3156 static 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 
FastCloneObjectMap(Isolate * isolate,Handle<Map> source_map,int flags)3178 static 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 
CloneObjectSlowPath(Isolate * isolate,Handle<Object> source,int flags)3230 static 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 
RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss)3254 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StoreCallbackProperty)3285 RUNTIME_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  */
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor)3314 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor)3363 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor)3407 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_KeyedHasIC_Miss)3433 RUNTIME_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 
RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor)3453 RUNTIME_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