• 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/accessors.h"
8 #include "src/api-arguments-inl.h"
9 #include "src/api.h"
10 #include "src/arguments-inl.h"
11 #include "src/ast/ast.h"
12 #include "src/base/bits.h"
13 #include "src/conversions.h"
14 #include "src/execution.h"
15 #include "src/field-type.h"
16 #include "src/frames-inl.h"
17 #include "src/handles-inl.h"
18 #include "src/ic/call-optimization.h"
19 #include "src/ic/handler-configuration-inl.h"
20 #include "src/ic/ic-inl.h"
21 #include "src/ic/ic-stats.h"
22 #include "src/ic/stub-cache.h"
23 #include "src/isolate-inl.h"
24 #include "src/macro-assembler.h"
25 #include "src/objects/api-callbacks.h"
26 #include "src/objects/data-handler-inl.h"
27 #include "src/objects/hash-table-inl.h"
28 #include "src/objects/js-array-inl.h"
29 #include "src/objects/module-inl.h"
30 #include "src/prototype.h"
31 #include "src/runtime-profiler.h"
32 #include "src/runtime/runtime-utils.h"
33 #include "src/runtime/runtime.h"
34 #include "src/tracing/trace-event.h"
35 #include "src/tracing/tracing-category-observer.h"
36 
37 namespace v8 {
38 namespace internal {
39 
TransitionMarkFromState(IC::State state)40 char IC::TransitionMarkFromState(IC::State state) {
41   switch (state) {
42     case UNINITIALIZED:
43       return '0';
44     case PREMONOMORPHIC:
45       return '.';
46     case MONOMORPHIC:
47       return '1';
48     case RECOMPUTE_HANDLER:
49       return '^';
50     case POLYMORPHIC:
51       return 'P';
52     case MEGAMORPHIC:
53       return 'N';
54     case GENERIC:
55       return 'G';
56   }
57   UNREACHABLE();
58 }
59 
60 namespace {
61 
GetModifier(KeyedAccessLoadMode mode)62 const char* GetModifier(KeyedAccessLoadMode mode) {
63   if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB";
64   return "";
65 }
66 
GetModifier(KeyedAccessStoreMode mode)67 const char* GetModifier(KeyedAccessStoreMode mode) {
68   switch (mode) {
69     case STORE_NO_TRANSITION_HANDLE_COW:
70       return ".COW";
71     case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
72       return ".STORE+COW";
73     case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
74       return ".IGNORE_OOB";
75     default:
76       break;
77   }
78   DCHECK(!IsCOWHandlingStoreMode(mode));
79   return IsGrowStoreMode(mode) ? ".GROW" : "";
80 }
81 
82 }  // namespace
83 
TraceIC(const char * type,Handle<Object> name)84 void IC::TraceIC(const char* type, Handle<Object> name) {
85   if (FLAG_ic_stats) {
86     if (AddressIsDeoptimizedCode()) return;
87     State new_state = nexus()->StateFromFeedback();
88     TraceIC(type, name, state(), new_state);
89   }
90 }
91 
TraceIC(const char * type,Handle<Object> name,State old_state,State new_state)92 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
93                  State new_state) {
94   if (V8_LIKELY(!FLAG_ic_stats)) return;
95 
96   Map* map = nullptr;
97   if (!receiver_map().is_null()) {
98     map = *receiver_map();
99   }
100 
101   const char* modifier = "";
102   if (IsKeyedLoadIC()) {
103     KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
104     modifier = GetModifier(mode);
105   } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind())) {
106     KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
107     modifier = GetModifier(mode);
108   }
109 
110   bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind());
111 
112   if (!(FLAG_ic_stats &
113         v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
114     LOG(isolate(), ICEvent(type, keyed_prefix, map, *name,
115                            TransitionMarkFromState(old_state),
116                            TransitionMarkFromState(new_state), modifier,
117                            slow_stub_reason_));
118     return;
119   }
120 
121   ICStats::instance()->Begin();
122   ICInfo& ic_info = ICStats::instance()->Current();
123   ic_info.type = keyed_prefix ? "Keyed" : "";
124   ic_info.type += type;
125 
126   Object* maybe_function =
127       Memory<Object*>(fp_ + JavaScriptFrameConstants::kFunctionOffset);
128   DCHECK(maybe_function->IsJSFunction());
129   JSFunction* function = JSFunction::cast(maybe_function);
130   int code_offset = 0;
131   if (function->IsInterpreted()) {
132     code_offset = InterpretedFrame::GetBytecodeOffset(fp());
133   } else {
134     code_offset = static_cast<int>(pc() - function->code()->InstructionStart());
135   }
136   JavaScriptFrame::CollectFunctionAndOffsetForICStats(
137       function, function->abstract_code(), code_offset);
138 
139   // Reserve enough space for IC transition state, the longest length is 17.
140   ic_info.state.reserve(17);
141   ic_info.state = "(";
142   ic_info.state += TransitionMarkFromState(old_state);
143   ic_info.state += "->";
144   ic_info.state += TransitionMarkFromState(new_state);
145   ic_info.state += modifier;
146   ic_info.state += ")";
147   ic_info.map = reinterpret_cast<void*>(map);
148   if (map != nullptr) {
149     ic_info.is_dictionary_map = map->is_dictionary_map();
150     ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
151     ic_info.instance_type = std::to_string(map->instance_type());
152   }
153   // TODO(lpy) Add name as key field in ICStats.
154   ICStats::instance()->End();
155 }
156 
IC(Isolate * isolate,Handle<FeedbackVector> vector,FeedbackSlot slot)157 IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot)
158     : isolate_(isolate),
159       vector_set_(false),
160       kind_(FeedbackSlotKind::kInvalid),
161       target_maps_set_(false),
162       slow_stub_reason_(nullptr),
163       nexus_(vector, slot) {
164   // To improve the performance of the (much used) IC code, we unfold a few
165   // levels of the stack frame iteration code. This yields a ~35% speedup when
166   // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
167   const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
168   Address* constant_pool = nullptr;
169   if (FLAG_enable_embedded_constant_pool) {
170     constant_pool = reinterpret_cast<Address*>(
171         entry + ExitFrameConstants::kConstantPoolOffset);
172   }
173   Address* pc_address =
174       reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
175   Address fp = Memory<Address>(entry + ExitFrameConstants::kCallerFPOffset);
176 #ifdef DEBUG
177   StackFrameIterator it(isolate);
178   for (int i = 0; i < 1; i++) it.Advance();
179   StackFrame* frame = it.frame();
180   DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
181 #endif
182   // For interpreted functions, some bytecode handlers construct a
183   // frame. We have to skip the constructed frame to find the interpreted
184   // function's frame. Check if the there is an additional frame, and if there
185   // is skip this frame. However, the pc should not be updated. The call to
186   // ICs happen from bytecode handlers.
187   intptr_t frame_marker =
188       Memory<intptr_t>(fp + TypedFrameConstants::kFrameTypeOffset);
189   if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
190     fp = Memory<Address>(fp + TypedFrameConstants::kCallerFPOffset);
191   }
192   fp_ = fp;
193   if (FLAG_enable_embedded_constant_pool) {
194     constant_pool_address_ = constant_pool;
195   }
196   pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
197   kind_ = nexus_.kind();
198   state_ = nexus_.StateFromFeedback();
199   old_state_ = state_;
200 }
201 
GetHostFunction() const202 JSFunction* IC::GetHostFunction() const {
203   // Compute the JavaScript frame for the frame pointer of this IC
204   // structure. We need this to be able to find the function
205   // corresponding to the frame.
206   StackFrameIterator it(isolate());
207   while (it.frame()->fp() != this->fp()) it.Advance();
208   JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
209   // Find the function on the stack and both the active code for the
210   // function and the original code.
211   return frame->function();
212 }
213 
LookupForRead(Isolate * isolate,LookupIterator * it)214 static void LookupForRead(Isolate* isolate, LookupIterator* it) {
215   for (; it->IsFound(); it->Next()) {
216     switch (it->state()) {
217       case LookupIterator::NOT_FOUND:
218       case LookupIterator::TRANSITION:
219         UNREACHABLE();
220       case LookupIterator::JSPROXY:
221         return;
222       case LookupIterator::INTERCEPTOR: {
223         // If there is a getter, return; otherwise loop to perform the lookup.
224         Handle<JSObject> holder = it->GetHolder<JSObject>();
225         if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) {
226           return;
227         }
228         break;
229       }
230       case LookupIterator::ACCESS_CHECK:
231         // ICs know how to perform access checks on global proxies.
232         if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
233           break;
234         }
235         return;
236       case LookupIterator::ACCESSOR:
237       case LookupIterator::INTEGER_INDEXED_EXOTIC:
238       case LookupIterator::DATA:
239         return;
240     }
241   }
242 }
243 
ShouldRecomputeHandler(Handle<String> name)244 bool IC::ShouldRecomputeHandler(Handle<String> name) {
245   if (!RecomputeHandlerForName(name)) return false;
246 
247   // This is a contextual access, always just update the handler and stay
248   // monomorphic.
249   if (IsGlobalIC()) return true;
250 
251   maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
252 
253   // The current map wasn't handled yet. There's no reason to stay monomorphic,
254   // *unless* we're moving from a deprecated map to its replacement, or
255   // to a more general elements kind.
256   // TODO(verwaest): Check if the current map is actually what the old map
257   // would transition to.
258   if (maybe_handler_.is_null()) {
259     if (!receiver_map()->IsJSObjectMap()) return false;
260     Map* first_map = FirstTargetMap();
261     if (first_map == nullptr) return false;
262     Handle<Map> old_map(first_map, isolate());
263     if (old_map->is_deprecated()) return true;
264     return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
265                                                receiver_map()->elements_kind());
266   }
267 
268   return true;
269 }
270 
RecomputeHandlerForName(Handle<Object> name)271 bool IC::RecomputeHandlerForName(Handle<Object> name) {
272   if (is_keyed()) {
273     // Determine whether the failure is due to a name failure.
274     if (!name->IsName()) return false;
275     Name* stub_name = nexus()->FindFirstName();
276     if (*name != stub_name) return false;
277   }
278 
279   return true;
280 }
281 
282 
UpdateState(Handle<Object> receiver,Handle<Object> name)283 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
284   update_receiver_map(receiver);
285   if (!name->IsString()) return;
286   if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
287   if (receiver->IsNullOrUndefined(isolate())) return;
288 
289   // Remove the target from the code cache if it became invalid
290   // because of changes in the prototype chain to avoid hitting it
291   // again.
292   if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
293     MarkRecomputeHandler(name);
294   }
295 }
296 
297 
TypeError(MessageTemplate::Template index,Handle<Object> object,Handle<Object> key)298 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
299                                   Handle<Object> object, Handle<Object> key) {
300   HandleScope scope(isolate());
301   THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
302 }
303 
304 
ReferenceError(Handle<Name> name)305 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
306   HandleScope scope(isolate());
307   THROW_NEW_ERROR(
308       isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
309 }
310 
311 // static
OnFeedbackChanged(Isolate * isolate,FeedbackNexus * nexus,JSFunction * host_function,const char * reason)312 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
313                            JSFunction* host_function, const char* reason) {
314   FeedbackVector* vector = nexus->vector();
315   FeedbackSlot slot = nexus->slot();
316   OnFeedbackChanged(isolate, vector, slot, host_function, reason);
317 }
318 
319 // static
OnFeedbackChanged(Isolate * isolate,FeedbackVector * vector,FeedbackSlot slot,JSFunction * host_function,const char * reason)320 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector,
321                            FeedbackSlot slot, JSFunction* host_function,
322                            const char* reason) {
323   if (FLAG_trace_opt_verbose) {
324     // TODO(leszeks): The host function is only needed for this print, we could
325     // remove it as a parameter if we're of with removing this trace (or only
326     // tracing the feedback vector, not the function name).
327     if (vector->profiler_ticks() != 0) {
328       PrintF("[resetting ticks for ");
329       host_function->ShortPrint();
330       PrintF(" due from %d due to IC change: %s]\n", vector->profiler_ticks(),
331              reason);
332     }
333   }
334   vector->set_profiler_ticks(0);
335 
336 #ifdef V8_TRACE_FEEDBACK_UPDATES
337   if (FLAG_trace_feedback_updates) {
338     int slot_count = vector->metadata()->slot_count();
339 
340     StdoutStream os;
341     if (slot.IsInvalid()) {
342       os << "[Feedback slots in ";
343     } else {
344       os << "[Feedback slot " << slot.ToInt() << "/" << slot_count << " in ";
345     }
346     vector->shared_function_info()->ShortPrint(os);
347     if (slot.IsInvalid()) {
348       os << " updated - ";
349     } else {
350       os << " updated to ";
351       vector->FeedbackSlotPrint(os, slot);
352       os << " - ";
353     }
354     os << reason << "]" << std::endl;
355   }
356 #endif
357 
358   isolate->runtime_profiler()->NotifyICChanged();
359   // TODO(2029): When an optimized function is patched, it would
360   // be nice to propagate the corresponding type information to its
361   // unoptimized version for the benefit of later inlining.
362 }
363 
MigrateDeprecated(Handle<Object> object)364 static bool MigrateDeprecated(Handle<Object> object) {
365   if (!object->IsJSObject()) return false;
366   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
367   if (!receiver->map()->is_deprecated()) return false;
368   JSObject::MigrateInstance(Handle<JSObject>::cast(object));
369   return true;
370 }
371 
ConfigureVectorState(IC::State new_state,Handle<Object> key)372 bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
373   DCHECK_EQ(MEGAMORPHIC, new_state);
374   DCHECK_IMPLIES(!is_keyed(), key->IsName());
375   // Even though we don't change the feedback data, we still want to reset the
376   // profiler ticks. Real-world observations suggest that optimizing these
377   // functions doesn't improve performance.
378   bool changed =
379       nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
380   vector_set_ = true;
381   OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Megamorphic");
382   return changed;
383 }
384 
ConfigureVectorState(Handle<Map> map)385 void IC::ConfigureVectorState(Handle<Map> map) {
386   nexus()->ConfigurePremonomorphic(map);
387   vector_set_ = true;
388   OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Premonomorphic");
389 }
390 
ConfigureVectorState(Handle<Name> name,Handle<Map> map,Handle<Object> handler)391 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
392                               Handle<Object> handler) {
393   ConfigureVectorState(name, map, MaybeObjectHandle(handler));
394 }
395 
ConfigureVectorState(Handle<Name> name,Handle<Map> map,const MaybeObjectHandle & handler)396 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
397                               const MaybeObjectHandle& handler) {
398   if (IsGlobalIC()) {
399     nexus()->ConfigureHandlerMode(handler);
400   } else {
401     // Non-keyed ICs don't track the name explicitly.
402     if (!is_keyed()) name = Handle<Name>::null();
403     nexus()->ConfigureMonomorphic(name, map, handler);
404   }
405 
406   vector_set_ = true;
407   OnFeedbackChanged(isolate(), nexus(), GetHostFunction(),
408                     IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
409 }
410 
ConfigureVectorState(Handle<Name> name,MapHandles const & maps,MaybeObjectHandles * handlers)411 void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
412                               MaybeObjectHandles* handlers) {
413   DCHECK(!IsGlobalIC());
414   // Non-keyed ICs don't track the name explicitly.
415   if (!is_keyed()) name = Handle<Name>::null();
416   nexus()->ConfigurePolymorphic(name, maps, handlers);
417 
418   vector_set_ = true;
419   OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Polymorphic");
420 }
421 
Load(Handle<Object> object,Handle<Name> name)422 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
423   // If the object is undefined or null it's illegal to try to get any
424   // of its properties; throw a TypeError in that case.
425   if (object->IsNullOrUndefined(isolate())) {
426     if (FLAG_use_ic && state() != PREMONOMORPHIC) {
427       // Ensure the IC state progresses.
428       TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
429       update_receiver_map(object);
430       PatchCache(name, slow_stub());
431       TraceIC("LoadIC", name);
432     }
433 
434     if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
435       return Runtime::ThrowIteratorError(isolate(), object);
436     }
437     return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
438   }
439 
440   bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
441 
442   if (state() != UNINITIALIZED) {
443     JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
444     update_receiver_map(object);
445   }
446   // Named lookup in the object.
447   LookupIterator it(isolate(), object, name);
448   LookupForRead(isolate(), &it);
449 
450   if (name->IsPrivate()) {
451     if (name->IsPrivateField() && !it.IsFound()) {
452       return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object,
453                        name);
454     }
455 
456     // IC handling of private symbols/fields lookup on JSProxy is not
457     // supported.
458     if (object->IsJSProxy()) {
459       use_ic = false;
460     }
461   }
462 
463   if (it.IsFound() || !ShouldThrowReferenceError()) {
464     // Update inline cache and stub cache.
465     if (use_ic) UpdateCaches(&it);
466 
467     // Get the property.
468     Handle<Object> result;
469 
470     ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
471                                Object);
472     if (it.IsFound()) {
473       return result;
474     } else if (!ShouldThrowReferenceError()) {
475       LOG(isolate(), SuspectReadEvent(*name, *object));
476       return result;
477     }
478   }
479   return ReferenceError(name);
480 }
481 
Load(Handle<Name> name)482 MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
483   Handle<JSGlobalObject> global = isolate()->global_object();
484 
485   if (name->IsString()) {
486     // Look up in script context table.
487     Handle<String> str_name = Handle<String>::cast(name);
488     Handle<ScriptContextTable> script_contexts(
489         global->native_context()->script_context_table(), isolate());
490 
491     ScriptContextTable::LookupResult lookup_result;
492     if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
493                                    &lookup_result)) {
494       Handle<Object> result = FixedArray::get(
495           *ScriptContextTable::GetContext(isolate(), script_contexts,
496                                           lookup_result.context_index),
497           lookup_result.slot_index, isolate());
498       if (result->IsTheHole(isolate())) {
499         // Do not install stubs and stay pre-monomorphic for
500         // uninitialized accesses.
501         return ReferenceError(name);
502       }
503 
504       if (FLAG_use_ic) {
505         if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
506                                              lookup_result.slot_index)) {
507           TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
508         } else {
509           // Given combination of indices can't be encoded, so use slow stub.
510           TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
511           PatchCache(name, slow_stub());
512         }
513         TraceIC("LoadGlobalIC", name);
514       }
515       return result;
516     }
517   }
518   return LoadIC::Load(global, name);
519 }
520 
AddOneReceiverMapIfMissing(MapHandles * receiver_maps,Handle<Map> new_receiver_map)521 static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
522                                        Handle<Map> new_receiver_map) {
523   DCHECK(!new_receiver_map.is_null());
524   for (Handle<Map> map : *receiver_maps) {
525     if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
526       return false;
527     }
528   }
529   receiver_maps->push_back(new_receiver_map);
530   return true;
531 }
532 
UpdatePolymorphicIC(Handle<Name> name,const MaybeObjectHandle & handler)533 bool IC::UpdatePolymorphicIC(Handle<Name> name,
534                              const MaybeObjectHandle& handler) {
535   DCHECK(IsHandler(*handler));
536   if (is_keyed() && state() != RECOMPUTE_HANDLER) {
537     if (nexus()->FindFirstName() != *name) return false;
538   }
539   Handle<Map> map = receiver_map();
540   MapHandles maps;
541   MaybeObjectHandles handlers;
542 
543   TargetMaps(&maps);
544   int number_of_maps = static_cast<int>(maps.size());
545   int deprecated_maps = 0;
546   int handler_to_overwrite = -1;
547   if (!nexus()->FindHandlers(&handlers, number_of_maps)) return false;
548 
549   for (int i = 0; i < number_of_maps; i++) {
550     Handle<Map> current_map = maps.at(i);
551     if (current_map->is_deprecated()) {
552       // Filter out deprecated maps to ensure their instances get migrated.
553       ++deprecated_maps;
554     } else if (map.is_identical_to(current_map)) {
555       // If both map and handler stayed the same (and the name is also the
556       // same as checked above, for keyed accesses), we're not progressing
557       // in the lattice and need to go MEGAMORPHIC instead. There's one
558       // exception to this rule, which is when we're in RECOMPUTE_HANDLER
559       // state, there we allow to migrate to a new handler.
560       if (handler.is_identical_to(handlers[i]) &&
561           state() != RECOMPUTE_HANDLER) {
562         return false;
563       }
564       // If the receiver type is already in the polymorphic IC, this indicates
565       // there was a prototoype chain failure. In that case, just overwrite the
566       // handler.
567       handler_to_overwrite = i;
568     } else if (handler_to_overwrite == -1 &&
569                IsTransitionOfMonomorphicTarget(*current_map, *map)) {
570       handler_to_overwrite = i;
571     }
572   }
573 
574   int number_of_valid_maps =
575       number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
576 
577   if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
578   if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
579     return false;
580   }
581 
582   number_of_valid_maps++;
583   if (number_of_valid_maps == 1) {
584     ConfigureVectorState(name, receiver_map(), handler);
585   } else {
586     if (is_keyed() && nexus()->FindFirstName() != *name) return false;
587     if (handler_to_overwrite >= 0) {
588       handlers[handler_to_overwrite] = handler;
589       if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
590         maps[handler_to_overwrite] = map;
591       }
592     } else {
593       maps.push_back(map);
594       handlers.push_back(handler);
595     }
596 
597     ConfigureVectorState(name, maps, &handlers);
598   }
599 
600   return true;
601 }
602 
UpdateMonomorphicIC(const MaybeObjectHandle & handler,Handle<Name> name)603 void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
604                              Handle<Name> name) {
605   DCHECK(IsHandler(*handler));
606   ConfigureVectorState(name, receiver_map(), handler);
607 }
608 
609 
CopyICToMegamorphicCache(Handle<Name> name)610 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
611   MapHandles maps;
612   MaybeObjectHandles handlers;
613   TargetMaps(&maps);
614   if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return;
615   for (int i = 0; i < static_cast<int>(maps.size()); i++) {
616     UpdateMegamorphicCache(maps.at(i), name, handlers.at(i));
617   }
618 }
619 
620 
IsTransitionOfMonomorphicTarget(Map * source_map,Map * target_map)621 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
622   if (source_map == nullptr) return true;
623   if (target_map == nullptr) return false;
624   if (source_map->is_abandoned_prototype_map()) return false;
625   ElementsKind target_elements_kind = target_map->elements_kind();
626   bool more_general_transition = IsMoreGeneralElementsKindTransition(
627       source_map->elements_kind(), target_elements_kind);
628   Map* transitioned_map = nullptr;
629   if (more_general_transition) {
630     MapHandles map_list;
631     map_list.push_back(handle(target_map, isolate_));
632     transitioned_map =
633         source_map->FindElementsKindTransitionedMap(isolate(), map_list);
634   }
635   return transitioned_map == target_map;
636 }
637 
PatchCache(Handle<Name> name,Handle<Object> handler)638 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
639   PatchCache(name, MaybeObjectHandle(handler));
640 }
641 
PatchCache(Handle<Name> name,const MaybeObjectHandle & handler)642 void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
643   DCHECK(IsHandler(*handler));
644   // Currently only load and store ICs support non-code handlers.
645   DCHECK(IsAnyLoad() || IsAnyStore());
646   switch (state()) {
647     case UNINITIALIZED:
648     case PREMONOMORPHIC:
649       UpdateMonomorphicIC(handler, name);
650       break;
651     case RECOMPUTE_HANDLER:
652     case MONOMORPHIC:
653       if (IsGlobalIC()) {
654         UpdateMonomorphicIC(handler, name);
655         break;
656       }
657       V8_FALLTHROUGH;
658     case POLYMORPHIC:
659       if (UpdatePolymorphicIC(name, handler)) break;
660       if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
661         CopyICToMegamorphicCache(name);
662       }
663       ConfigureVectorState(MEGAMORPHIC, name);
664       V8_FALLTHROUGH;
665     case MEGAMORPHIC:
666       UpdateMegamorphicCache(receiver_map(), name, handler);
667       // Indicate that we've handled this case.
668       vector_set_ = true;
669       break;
670     case GENERIC:
671       UNREACHABLE();
672       break;
673   }
674 }
675 
UpdateCaches(LookupIterator * lookup)676 void LoadIC::UpdateCaches(LookupIterator* lookup) {
677   if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
678     // This is the first time we execute this inline cache. Set the target to
679     // the pre monomorphic stub to delay setting the monomorphic state.
680     TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
681     ConfigureVectorState(receiver_map());
682     TraceIC("LoadIC", lookup->name());
683     return;
684   }
685 
686   Handle<Object> code;
687   if (lookup->state() == LookupIterator::ACCESS_CHECK) {
688     code = slow_stub();
689   } else if (!lookup->IsFound()) {
690     TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
691     Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
692     code = LoadHandler::LoadFullChain(
693         isolate(), receiver_map(),
694         MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
695   } else {
696     if (IsLoadGlobalIC()) {
697       if (lookup->TryLookupCachedProperty()) {
698         DCHECK_EQ(LookupIterator::DATA, lookup->state());
699       }
700       if (lookup->state() == LookupIterator::DATA &&
701           lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
702         DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
703         // Now update the cell in the feedback vector.
704         nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
705         TraceIC("LoadGlobalIC", lookup->name());
706         return;
707       }
708     }
709     code = ComputeHandler(lookup);
710   }
711 
712   PatchCache(lookup->name(), code);
713   TraceIC("LoadIC", lookup->name());
714 }
715 
stub_cache()716 StubCache* IC::stub_cache() {
717   if (IsAnyLoad()) {
718     return isolate()->load_stub_cache();
719   } else {
720     DCHECK(IsAnyStore());
721     return isolate()->store_stub_cache();
722   }
723 }
724 
UpdateMegamorphicCache(Handle<Map> map,Handle<Name> name,const MaybeObjectHandle & handler)725 void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
726                                 const MaybeObjectHandle& handler) {
727   stub_cache()->Set(*name, *map, *handler);
728 }
729 
TraceHandlerCacheHitStats(LookupIterator * lookup)730 void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
731   DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
732   if (V8_LIKELY(!FLAG_runtime_stats)) return;
733   if (IsAnyLoad()) {
734     TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
735   } else {
736     DCHECK(IsAnyStore());
737     TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
738   }
739 }
740 
ComputeHandler(LookupIterator * lookup)741 Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
742   Handle<Object> receiver = lookup->GetReceiver();
743   ReadOnlyRoots roots(isolate());
744   if (receiver->IsString() && *lookup->name() == roots.length_string()) {
745     TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
746     return BUILTIN_CODE(isolate(), LoadIC_StringLength);
747   }
748 
749   if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) {
750     TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
751     return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
752   }
753 
754   // Use specialized code for getting prototype of functions.
755   if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() &&
756       !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
757     Handle<Code> stub;
758     TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
759     return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
760   }
761 
762   Handle<Map> map = receiver_map();
763   Handle<JSObject> holder;
764   bool receiver_is_holder;
765   if (lookup->state() != LookupIterator::JSPROXY) {
766     holder = lookup->GetHolder<JSObject>();
767     receiver_is_holder = receiver.is_identical_to(holder);
768   }
769 
770   switch (lookup->state()) {
771     case LookupIterator::INTERCEPTOR: {
772       Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
773 
774       if (holder->GetNamedInterceptor()->non_masking()) {
775         MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
776         if (!receiver_is_holder || IsLoadGlobalIC()) {
777           holder_ref = MaybeObjectHandle::Weak(holder);
778         }
779         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
780         return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
781                                           smi_handler);
782       }
783 
784       if (receiver_is_holder) {
785         DCHECK(map->has_named_interceptor());
786         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
787         return smi_handler;
788       }
789 
790       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
791       return LoadHandler::LoadFromPrototype(isolate(), map, holder,
792                                             smi_handler);
793     }
794 
795     case LookupIterator::ACCESSOR: {
796       // Use simple field loads for some well-known callback properties.
797       // The method will only return true for absolute truths based on the
798       // receiver maps.
799       FieldIndex index;
800       if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
801                                              &index)) {
802         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
803         return LoadHandler::LoadField(isolate(), index);
804       }
805       if (holder->IsJSModuleNamespace()) {
806         Handle<ObjectHashTable> exports(
807             Handle<JSModuleNamespace>::cast(holder)->module()->exports(),
808             isolate());
809         int entry = exports->FindEntry(roots, lookup->name(),
810                                        Smi::ToInt(lookup->name()->GetHash()));
811         // We found the accessor, so the entry must exist.
812         DCHECK_NE(entry, ObjectHashTable::kNotFound);
813         int index = ObjectHashTable::EntryToValueIndex(entry);
814         return LoadHandler::LoadModuleExport(isolate(), index);
815       }
816 
817       Handle<Object> accessors = lookup->GetAccessors();
818       if (accessors->IsAccessorPair()) {
819         if (lookup->TryLookupCachedProperty()) {
820           DCHECK_EQ(LookupIterator::DATA, lookup->state());
821           return ComputeHandler(lookup);
822         }
823 
824         Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
825                               isolate());
826         if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
827           TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
828           return slow_stub();
829         }
830 
831         if (getter->IsFunctionTemplateInfo() &&
832             FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) {
833           // Do not install an IC if the api function has a breakpoint.
834           TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
835           return slow_stub();
836         }
837 
838         Handle<Smi> smi_handler;
839 
840         CallOptimization call_optimization(isolate(), getter);
841         if (call_optimization.is_simple_api_call()) {
842           if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
843               !holder->HasFastProperties()) {
844             TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
845             return slow_stub();
846           }
847 
848           CallOptimization::HolderLookup holder_lookup;
849           call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
850 
851           smi_handler = LoadHandler::LoadApiGetter(
852               isolate(), holder_lookup == CallOptimization::kHolderIsReceiver);
853 
854           Handle<Context> context(
855               call_optimization.GetAccessorContext(holder->map()), isolate());
856 
857           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
858           return LoadHandler::LoadFromPrototype(
859               isolate(), map, holder, smi_handler,
860               MaybeObjectHandle::Weak(call_optimization.api_call_info()),
861               MaybeObjectHandle::Weak(context));
862         }
863 
864         if (holder->HasFastProperties()) {
865           smi_handler =
866               LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
867 
868           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
869           if (receiver_is_holder) return smi_handler;
870           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
871         } else if (holder->IsJSGlobalObject()) {
872           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
873           smi_handler = LoadHandler::LoadGlobal(isolate());
874           return LoadHandler::LoadFromPrototype(
875               isolate(), map, holder, smi_handler,
876               MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
877         } else {
878           smi_handler = LoadHandler::LoadNormal(isolate());
879 
880           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
881           if (receiver_is_holder) return smi_handler;
882           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
883         }
884 
885         return LoadHandler::LoadFromPrototype(isolate(), map, holder,
886                                               smi_handler);
887       }
888 
889       Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
890 
891       if (v8::ToCData<Address>(info->getter()) == kNullAddress ||
892           !AccessorInfo::IsCompatibleReceiverMap(info, map) ||
893           !holder->HasFastProperties() ||
894           (info->is_sloppy() && !receiver->IsJSReceiver())) {
895         TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
896         return slow_stub();
897       }
898 
899       Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
900           isolate(), lookup->GetAccessorIndex());
901       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
902       if (receiver_is_holder) return smi_handler;
903       TRACE_HANDLER_STATS(isolate(),
904                           LoadIC_LoadNativeDataPropertyFromPrototypeDH);
905       return LoadHandler::LoadFromPrototype(isolate(), map, holder,
906                                             smi_handler);
907     }
908 
909     case LookupIterator::DATA: {
910       DCHECK_EQ(kData, lookup->property_details().kind());
911       Handle<Smi> smi_handler;
912       if (lookup->is_dictionary_holder()) {
913         if (holder->IsJSGlobalObject()) {
914           // TODO(verwaest): Also supporting the global object as receiver is a
915           // workaround for code that leaks the global object.
916           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
917           smi_handler = LoadHandler::LoadGlobal(isolate());
918           return LoadHandler::LoadFromPrototype(
919               isolate(), map, holder, smi_handler,
920               MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
921         }
922 
923         smi_handler = LoadHandler::LoadNormal(isolate());
924         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
925         if (receiver_is_holder) return smi_handler;
926         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
927 
928       } else if (lookup->property_details().location() == kField) {
929         FieldIndex field = lookup->GetFieldIndex();
930         smi_handler = LoadHandler::LoadField(isolate(), field);
931         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
932         if (receiver_is_holder) return smi_handler;
933         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
934       } else {
935         DCHECK_EQ(kDescriptor, lookup->property_details().location());
936         smi_handler =
937             LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
938         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
939         if (receiver_is_holder) return smi_handler;
940         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
941       }
942       return LoadHandler::LoadFromPrototype(isolate(), map, holder,
943                                             smi_handler);
944     }
945     case LookupIterator::INTEGER_INDEXED_EXOTIC:
946       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
947       return LoadHandler::LoadNonExistent(isolate());
948     case LookupIterator::JSPROXY: {
949       Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
950       bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy);
951       Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
952       if (receiver_is_holder_proxy) {
953         return smi_handler;
954       }
955       return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
956                                             smi_handler);
957     }
958     case LookupIterator::ACCESS_CHECK:
959     case LookupIterator::NOT_FOUND:
960     case LookupIterator::TRANSITION:
961       UNREACHABLE();
962   }
963 
964   return Handle<Code>::null();
965 }
966 
TryConvertKey(Handle<Object> key,Isolate * isolate)967 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
968   // This helper implements a few common fast cases for converting
969   // non-smi keys of keyed loads/stores to a smi or a string.
970   if (key->IsHeapNumber()) {
971     double value = Handle<HeapNumber>::cast(key)->value();
972     if (std::isnan(value)) {
973       key = isolate->factory()->NaN_string();
974     } else {
975       // Check bounds first to avoid undefined behavior in the conversion
976       // to int.
977       if (value <= Smi::kMaxValue && value >= Smi::kMinValue) {
978         int int_value = FastD2I(value);
979         if (value == int_value) {
980           key = handle(Smi::FromInt(int_value), isolate);
981         }
982       }
983     }
984   } else if (key->IsString()) {
985     key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
986   }
987   return key;
988 }
989 
CanChangeToAllowOutOfBounds(Handle<Map> receiver_map)990 bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) {
991   const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map);
992   if (handler.is_null()) return false;
993   return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD;
994 }
995 
UpdateLoadElement(Handle<HeapObject> receiver,KeyedAccessLoadMode load_mode)996 void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
997                                     KeyedAccessLoadMode load_mode) {
998   Handle<Map> receiver_map(receiver->map(), isolate());
999   DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE);  // Checked by caller.
1000   MapHandles target_receiver_maps;
1001   TargetMaps(&target_receiver_maps);
1002 
1003   if (target_receiver_maps.empty()) {
1004     Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1005     return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1006   }
1007 
1008   for (Handle<Map> map : target_receiver_maps) {
1009     if (map.is_null()) continue;
1010     if (map->instance_type() == JS_VALUE_TYPE) {
1011       set_slow_stub_reason("JSValue");
1012       return;
1013     }
1014     if (map->instance_type() == JS_PROXY_TYPE) {
1015       set_slow_stub_reason("JSProxy");
1016       return;
1017     }
1018   }
1019 
1020   // The first time a receiver is seen that is a transitioned version of the
1021   // previous monomorphic receiver type, assume the new ElementsKind is the
1022   // monomorphic type. This benefits global arrays that only transition
1023   // once, and all call sites accessing them are faster if they remain
1024   // monomorphic. If this optimistic assumption is not true, the IC will
1025   // miss again and it will become polymorphic and support both the
1026   // untransitioned and transitioned maps.
1027   if (state() == MONOMORPHIC && !receiver->IsString() &&
1028       !receiver->IsJSProxy() &&
1029       IsMoreGeneralElementsKindTransition(
1030           target_receiver_maps.at(0)->elements_kind(),
1031           Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1032     Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1033     return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1034   }
1035 
1036   DCHECK(state() != GENERIC);
1037 
1038   // Determine the list of receiver maps that this call site has seen,
1039   // adding the map that was just encountered.
1040   if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1041     // If the {receiver_map} previously had a handler that didn't handle
1042     // out-of-bounds access, but can generally handle it, we can just go
1043     // on and update the handler appropriately below.
1044     if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS ||
1045         !CanChangeToAllowOutOfBounds(receiver_map)) {
1046       // If the miss wasn't due to an unseen map, a polymorphic stub
1047       // won't help, use the generic stub.
1048       set_slow_stub_reason("same map added twice");
1049       return;
1050     }
1051   }
1052 
1053   // If the maximum number of receiver maps has been exceeded, use the generic
1054   // version of the IC.
1055   if (target_receiver_maps.size() > kMaxKeyedPolymorphism) {
1056     set_slow_stub_reason("max polymorph exceeded");
1057     return;
1058   }
1059 
1060   MaybeObjectHandles handlers;
1061   handlers.reserve(target_receiver_maps.size());
1062   LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1063   DCHECK_LE(1, target_receiver_maps.size());
1064   if (target_receiver_maps.size() == 1) {
1065     ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1066   } else {
1067     ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1068   }
1069 }
1070 
LoadElementHandler(Handle<Map> receiver_map,KeyedAccessLoadMode load_mode)1071 Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
1072                                                KeyedAccessLoadMode load_mode) {
1073   if (receiver_map->has_indexed_interceptor() &&
1074       !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
1075           isolate()) &&
1076       !receiver_map->GetIndexedInterceptor()->non_masking()) {
1077     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1078     return LoadIndexedInterceptorStub(isolate()).GetCode();
1079   }
1080   InstanceType instance_type = receiver_map->instance_type();
1081   if (instance_type < FIRST_NONSTRING_TYPE) {
1082     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1083     return LoadHandler::LoadIndexedString(isolate(), load_mode);
1084   }
1085   if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1086     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1087     return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
1088   }
1089   if (instance_type == JS_PROXY_TYPE) {
1090     return LoadHandler::LoadProxy(isolate());
1091   }
1092 
1093   ElementsKind elements_kind = receiver_map->elements_kind();
1094   if (IsSloppyArgumentsElementsKind(elements_kind)) {
1095     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1096     return KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
1097   }
1098   bool is_js_array = instance_type == JS_ARRAY_TYPE;
1099   if (elements_kind == DICTIONARY_ELEMENTS) {
1100     TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1101     return LoadHandler::LoadElement(isolate(), elements_kind, false,
1102                                     is_js_array, load_mode);
1103   }
1104   DCHECK(IsFastElementsKind(elements_kind) ||
1105          IsFixedTypedArrayElementsKind(elements_kind));
1106   // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind).
1107   bool convert_hole_to_undefined =
1108       is_js_array && elements_kind == HOLEY_ELEMENTS &&
1109       *receiver_map ==
1110           isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind);
1111   TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1112   return LoadHandler::LoadElement(isolate(), elements_kind,
1113                                   convert_hole_to_undefined, is_js_array,
1114                                   load_mode);
1115 }
1116 
LoadElementPolymorphicHandlers(MapHandles * receiver_maps,MaybeObjectHandles * handlers,KeyedAccessLoadMode load_mode)1117 void KeyedLoadIC::LoadElementPolymorphicHandlers(
1118     MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1119     KeyedAccessLoadMode load_mode) {
1120   // Filter out deprecated maps to ensure their instances get migrated.
1121   receiver_maps->erase(
1122       std::remove_if(
1123           receiver_maps->begin(), receiver_maps->end(),
1124           [](const Handle<Map>& map) { return map->is_deprecated(); }),
1125       receiver_maps->end());
1126 
1127   for (Handle<Map> receiver_map : *receiver_maps) {
1128     // Mark all stable receiver maps that have elements kind transition map
1129     // among receiver_maps as unstable because the optimizing compilers may
1130     // generate an elements kind transition for this kind of receivers.
1131     if (receiver_map->is_stable()) {
1132       Map* tmap = receiver_map->FindElementsKindTransitionedMap(isolate(),
1133                                                                 *receiver_maps);
1134       if (tmap != nullptr) {
1135         receiver_map->NotifyLeafMapLayoutChange(isolate());
1136       }
1137     }
1138     handlers->push_back(
1139         MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode)));
1140   }
1141 }
1142 
1143 namespace {
1144 
ConvertKeyToIndex(Handle<Object> receiver,Handle<Object> key,uint32_t * index)1145 bool ConvertKeyToIndex(Handle<Object> receiver, Handle<Object> key,
1146                        uint32_t* index) {
1147   if (!FLAG_use_ic) return false;
1148   if (receiver->IsAccessCheckNeeded() || receiver->IsJSValue()) return false;
1149 
1150   // For regular JSReceiver or String receivers, the {key} must be a positive
1151   // array index.
1152   if (receiver->IsJSReceiver() || receiver->IsString()) {
1153     if (key->ToArrayIndex(index)) return true;
1154   }
1155   // For JSTypedArray receivers, we can also support negative keys, which we
1156   // just map into the [2**31, 2**32 - 1] range via a bit_cast. This is valid
1157   // because JSTypedArray::length is always a Smi, so such keys will always
1158   // be detected as OOB.
1159   if (receiver->IsJSTypedArray()) {
1160     int32_t signed_index;
1161     if (key->ToInt32(&signed_index)) {
1162       *index = bit_cast<uint32_t>(signed_index);
1163       return true;
1164     }
1165   }
1166   return false;
1167 }
1168 
IsOutOfBoundsAccess(Handle<Object> receiver,uint32_t index)1169 bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) {
1170   uint32_t length = 0;
1171   if (receiver->IsJSArray()) {
1172     JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1173   } else if (receiver->IsString()) {
1174     length = String::cast(*receiver)->length();
1175   } else if (receiver->IsJSObject()) {
1176     length = JSObject::cast(*receiver)->elements()->length();
1177   } else {
1178     return false;
1179   }
1180   return index >= length;
1181 }
1182 
GetLoadMode(Isolate * isolate,Handle<Object> receiver,uint32_t index)1183 KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
1184                                 uint32_t index) {
1185   if (IsOutOfBoundsAccess(receiver, index)) {
1186     if (receiver->IsJSTypedArray()) {
1187       // For JSTypedArray we never lookup elements in the prototype chain.
1188       return LOAD_IGNORE_OUT_OF_BOUNDS;
1189     }
1190 
1191     // For other {receiver}s we need to check the "no elements" protector.
1192     if (isolate->IsNoElementsProtectorIntact()) {
1193       if (receiver->IsString()) {
1194         // ToObject(receiver) will have the initial String.prototype.
1195         return LOAD_IGNORE_OUT_OF_BOUNDS;
1196       }
1197       if (receiver->IsJSObject()) {
1198         // For other JSObjects (including JSArrays) we can only continue if
1199         // the {receiver}s prototype is either the initial Object.prototype
1200         // or the initial Array.prototype, which are both guarded by the
1201         // "no elements" protector checked above.
1202         Handle<Object> receiver_prototype(
1203             JSObject::cast(*receiver)->map()->prototype(), isolate);
1204         if (isolate->IsInAnyContext(*receiver_prototype,
1205                                     Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1206             isolate->IsInAnyContext(*receiver_prototype,
1207                                     Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
1208           return LOAD_IGNORE_OUT_OF_BOUNDS;
1209         }
1210       }
1211     }
1212   }
1213   return STANDARD_LOAD;
1214 }
1215 
1216 }  // namespace
1217 
Load(Handle<Object> object,Handle<Object> key)1218 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1219                                       Handle<Object> key) {
1220   if (MigrateDeprecated(object)) {
1221     Handle<Object> result;
1222     ASSIGN_RETURN_ON_EXCEPTION(
1223         isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1224         Object);
1225     return result;
1226   }
1227 
1228   Handle<Object> load_handle;
1229 
1230   // Check for non-string values that can be converted into an
1231   // internalized string directly or is representable as a smi.
1232   key = TryConvertKey(key, isolate());
1233 
1234   uint32_t index;
1235   if ((key->IsInternalizedString() &&
1236        !String::cast(*key)->AsArrayIndex(&index)) ||
1237       key->IsSymbol()) {
1238     ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1239                                LoadIC::Load(object, Handle<Name>::cast(key)),
1240                                Object);
1241   } else if (ConvertKeyToIndex(object, key, &index)) {
1242     KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index);
1243     UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode);
1244     if (is_vector_set()) {
1245       TraceIC("LoadIC", key);
1246     }
1247   }
1248 
1249   if (vector_needs_update()) {
1250     ConfigureVectorState(MEGAMORPHIC, key);
1251     TraceIC("LoadIC", key);
1252   }
1253 
1254   if (!load_handle.is_null()) return load_handle;
1255 
1256   Handle<Object> result;
1257   ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1258                              Runtime::GetObjectProperty(isolate(), object, key),
1259                              Object);
1260   return result;
1261 }
1262 
1263 
LookupForWrite(LookupIterator * it,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1264 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1265                              JSReceiver::StoreFromKeyed store_mode) {
1266   // Disable ICs for non-JSObjects for now.
1267   Handle<Object> object = it->GetReceiver();
1268   if (object->IsJSProxy()) return true;
1269   if (!object->IsJSObject()) return false;
1270   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1271   DCHECK(!receiver->map()->is_deprecated());
1272 
1273   if (it->state() != LookupIterator::TRANSITION) {
1274     for (; it->IsFound(); it->Next()) {
1275       switch (it->state()) {
1276         case LookupIterator::NOT_FOUND:
1277         case LookupIterator::TRANSITION:
1278           UNREACHABLE();
1279         case LookupIterator::JSPROXY:
1280           return true;
1281         case LookupIterator::INTERCEPTOR: {
1282           Handle<JSObject> holder = it->GetHolder<JSObject>();
1283           InterceptorInfo* info = holder->GetNamedInterceptor();
1284           if (it->HolderIsReceiverOrHiddenPrototype()) {
1285             return !info->non_masking() && receiver.is_identical_to(holder) &&
1286                    !info->setter()->IsUndefined(isolate());
1287           } else if (!info->getter()->IsUndefined(isolate()) ||
1288                      !info->query()->IsUndefined(isolate())) {
1289             return false;
1290           }
1291           break;
1292         }
1293         case LookupIterator::ACCESS_CHECK:
1294           if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1295           break;
1296         case LookupIterator::ACCESSOR:
1297           return !it->IsReadOnly();
1298         case LookupIterator::INTEGER_INDEXED_EXOTIC:
1299           return false;
1300         case LookupIterator::DATA: {
1301           if (it->IsReadOnly()) return false;
1302           Handle<JSObject> holder = it->GetHolder<JSObject>();
1303           if (receiver.is_identical_to(holder)) {
1304             it->PrepareForDataProperty(value);
1305             // The previous receiver map might just have been deprecated,
1306             // so reload it.
1307             update_receiver_map(receiver);
1308             return true;
1309           }
1310 
1311           // Receiver != holder.
1312           if (receiver->IsJSGlobalProxy()) {
1313             PrototypeIterator iter(isolate(), receiver);
1314             return it->GetHolder<Object>().is_identical_to(
1315                 PrototypeIterator::GetCurrent(iter));
1316           }
1317 
1318           if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1319 
1320           if (it->ExtendingNonExtensible(receiver)) return false;
1321           it->PrepareTransitionToDataProperty(receiver, value, NONE,
1322                                               store_mode);
1323           return it->IsCacheableTransition();
1324         }
1325       }
1326     }
1327   }
1328 
1329   receiver = it->GetStoreTarget<JSObject>();
1330   if (it->ExtendingNonExtensible(receiver)) return false;
1331   it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1332   return it->IsCacheableTransition();
1333 }
1334 
Store(Handle<Name> name,Handle<Object> value)1335 MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
1336                                          Handle<Object> value) {
1337   DCHECK(name->IsString());
1338 
1339   // Look up in script context table.
1340   Handle<String> str_name = Handle<String>::cast(name);
1341   Handle<JSGlobalObject> global = isolate()->global_object();
1342   Handle<ScriptContextTable> script_contexts(
1343       global->native_context()->script_context_table(), isolate());
1344 
1345   ScriptContextTable::LookupResult lookup_result;
1346   if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
1347                                  &lookup_result)) {
1348     Handle<Context> script_context = ScriptContextTable::GetContext(
1349         isolate(), script_contexts, lookup_result.context_index);
1350     if (lookup_result.mode == VariableMode::kConst) {
1351       return TypeError(MessageTemplate::kConstAssign, global, name);
1352     }
1353 
1354     Handle<Object> previous_value =
1355         FixedArray::get(*script_context, lookup_result.slot_index, isolate());
1356 
1357     if (previous_value->IsTheHole(isolate())) {
1358       // Do not install stubs and stay pre-monomorphic for
1359       // uninitialized accesses.
1360       return ReferenceError(name);
1361     }
1362 
1363     if (FLAG_use_ic) {
1364       if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
1365                                            lookup_result.slot_index)) {
1366         TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1367       } else {
1368         // Given combination of indices can't be encoded, so use slow stub.
1369         TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1370         PatchCache(name, slow_stub());
1371       }
1372       TraceIC("StoreGlobalIC", name);
1373     }
1374 
1375     script_context->set(lookup_result.slot_index, *value);
1376     return value;
1377   }
1378 
1379   return StoreIC::Store(global, name, value);
1380 }
1381 
Store(Handle<Object> object,Handle<Name> name,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1382 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1383                                    Handle<Object> value,
1384                                    JSReceiver::StoreFromKeyed store_mode) {
1385   // TODO(verwaest): Let SetProperty do the migration, since storing a property
1386   // might deprecate the current map again, if value does not fit.
1387   if (MigrateDeprecated(object)) {
1388     Handle<Object> result;
1389     ASSIGN_RETURN_ON_EXCEPTION(
1390         isolate(), result,
1391         Object::SetProperty(isolate(), object, name, value, language_mode()),
1392         Object);
1393     return result;
1394   }
1395 
1396   // If the object is undefined or null it's illegal to try to set any
1397   // properties on it; throw a TypeError in that case.
1398   if (object->IsNullOrUndefined(isolate())) {
1399     if (FLAG_use_ic && state() != PREMONOMORPHIC) {
1400       // Ensure the IC state progresses.
1401       TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1402       update_receiver_map(object);
1403       PatchCache(name, slow_stub());
1404       TraceIC("StoreIC", name);
1405     }
1406     return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1407   }
1408 
1409   if (state() != UNINITIALIZED) {
1410     JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1411   }
1412   LookupIterator it(isolate(), object, name);
1413   bool use_ic = FLAG_use_ic;
1414 
1415   if (name->IsPrivate()) {
1416     if (name->IsPrivateField() && !it.IsFound()) {
1417       return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object,
1418                        name);
1419     }
1420 
1421     // IC handling of private fields/symbols stores on JSProxy is not
1422     // supported.
1423     if (object->IsJSProxy()) {
1424       use_ic = false;
1425     }
1426   }
1427   if (use_ic) UpdateCaches(&it, value, store_mode);
1428 
1429   MAYBE_RETURN_NULL(
1430       Object::SetProperty(&it, value, language_mode(), store_mode));
1431   return value;
1432 }
1433 
UpdateCaches(LookupIterator * lookup,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1434 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1435                            JSReceiver::StoreFromKeyed store_mode) {
1436   if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
1437     // This is the first time we execute this inline cache. Transition
1438     // to premonomorphic state to delay setting the monomorphic state.
1439     TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1440     ConfigureVectorState(receiver_map());
1441     TraceIC("StoreIC", lookup->name());
1442     return;
1443   }
1444 
1445   MaybeObjectHandle handler;
1446   if (LookupForWrite(lookup, value, store_mode)) {
1447     if (IsStoreGlobalIC()) {
1448       if (lookup->state() == LookupIterator::DATA &&
1449           lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1450         DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1451         // Now update the cell in the feedback vector.
1452         nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1453         TraceIC("StoreGlobalIC", lookup->name());
1454         return;
1455       }
1456     }
1457     handler = ComputeHandler(lookup);
1458   } else {
1459     set_slow_stub_reason("LookupForWrite said 'false'");
1460     // TODO(marja): change slow_stub to return MaybeObjectHandle.
1461     handler = MaybeObjectHandle(slow_stub());
1462   }
1463 
1464   PatchCache(lookup->name(), handler);
1465   TraceIC("StoreIC", lookup->name());
1466 }
1467 
ComputeHandler(LookupIterator * lookup)1468 MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
1469   switch (lookup->state()) {
1470     case LookupIterator::TRANSITION: {
1471       Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1472       if (store_target->IsJSGlobalObject()) {
1473         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1474 
1475         if (receiver_map()->IsJSGlobalObject()) {
1476           DCHECK(IsStoreGlobalIC());
1477 #ifdef DEBUG
1478           Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1479           DCHECK_EQ(*lookup->GetReceiver(), *holder);
1480           DCHECK_EQ(*store_target, *holder);
1481 #endif
1482           return StoreHandler::StoreGlobal(lookup->transition_cell());
1483         }
1484 
1485         Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
1486         Handle<Object> handler = StoreHandler::StoreThroughPrototype(
1487             isolate(), receiver_map(), store_target, smi_handler,
1488             MaybeObjectHandle::Weak(lookup->transition_cell()));
1489         return MaybeObjectHandle(handler);
1490       }
1491       // Dictionary-to-fast transitions are not expected and not supported.
1492       DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
1493                      !receiver_map()->is_dictionary_map());
1494 
1495       DCHECK(lookup->IsCacheableTransition());
1496 
1497       return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
1498     }
1499 
1500     case LookupIterator::INTERCEPTOR: {
1501       Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1502       USE(holder);
1503 
1504       DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1505       TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1506       StoreInterceptorStub stub(isolate());
1507       return MaybeObjectHandle(stub.GetCode());
1508     }
1509 
1510     case LookupIterator::ACCESSOR: {
1511       // This is currently guaranteed by checks in StoreIC::Store.
1512       Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1513       Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1514       DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1515 
1516       if (!holder->HasFastProperties()) {
1517         set_slow_stub_reason("accessor on slow map");
1518         TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1519         return MaybeObjectHandle(slow_stub());
1520       }
1521       Handle<Object> accessors = lookup->GetAccessors();
1522       if (accessors->IsAccessorInfo()) {
1523         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1524         if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
1525           set_slow_stub_reason("setter == kNullAddress");
1526           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1527           return MaybeObjectHandle(slow_stub());
1528         }
1529         if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1530             !lookup->HolderIsReceiverOrHiddenPrototype()) {
1531           set_slow_stub_reason("special data property in prototype chain");
1532           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1533           return MaybeObjectHandle(slow_stub());
1534         }
1535         if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) {
1536           set_slow_stub_reason("incompatible receiver type");
1537           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1538           return MaybeObjectHandle(slow_stub());
1539         }
1540 
1541         Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
1542             isolate(), lookup->GetAccessorIndex());
1543         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
1544         if (receiver.is_identical_to(holder)) {
1545           return MaybeObjectHandle(smi_handler);
1546         }
1547         TRACE_HANDLER_STATS(isolate(),
1548                             StoreIC_StoreNativeDataPropertyOnPrototypeDH);
1549         return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1550             isolate(), receiver_map(), holder, smi_handler));
1551 
1552       } else if (accessors->IsAccessorPair()) {
1553         Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1554                               isolate());
1555         if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1556           set_slow_stub_reason("setter not a function");
1557           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1558           return MaybeObjectHandle(slow_stub());
1559         }
1560 
1561         if (setter->IsFunctionTemplateInfo() &&
1562             FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) {
1563           // Do not install an IC if the api function has a breakpoint.
1564           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1565           return MaybeObjectHandle(slow_stub());
1566         }
1567 
1568         CallOptimization call_optimization(isolate(), setter);
1569         if (call_optimization.is_simple_api_call()) {
1570           if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1571             CallOptimization::HolderLookup holder_lookup;
1572             call_optimization.LookupHolderOfExpectedType(receiver_map(),
1573                                                          &holder_lookup);
1574 
1575             Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
1576                 isolate(),
1577                 holder_lookup == CallOptimization::kHolderIsReceiver);
1578 
1579             Handle<Context> context(
1580                 call_optimization.GetAccessorContext(holder->map()), isolate());
1581             TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
1582             return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1583                 isolate(), receiver_map(), holder, smi_handler,
1584                 MaybeObjectHandle::Weak(call_optimization.api_call_info()),
1585                 MaybeObjectHandle::Weak(context)));
1586           }
1587           set_slow_stub_reason("incompatible receiver");
1588           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1589           return MaybeObjectHandle(slow_stub());
1590         } else if (setter->IsFunctionTemplateInfo()) {
1591           set_slow_stub_reason("setter non-simple template");
1592           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1593           return MaybeObjectHandle(slow_stub());
1594         }
1595 
1596         Handle<Smi> smi_handler =
1597             StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex());
1598 
1599         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
1600         if (receiver.is_identical_to(holder)) {
1601           return MaybeObjectHandle(smi_handler);
1602         }
1603         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
1604 
1605         return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1606             isolate(), receiver_map(), holder, smi_handler));
1607       }
1608       TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1609       return MaybeObjectHandle(slow_stub());
1610     }
1611 
1612     case LookupIterator::DATA: {
1613       // This is currently guaranteed by checks in StoreIC::Store.
1614       Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1615       USE(receiver);
1616       Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1617       DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1618 
1619       DCHECK_EQ(kData, lookup->property_details().kind());
1620       if (lookup->is_dictionary_holder()) {
1621         if (holder->IsJSGlobalObject()) {
1622           TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
1623           return MaybeObjectHandle(
1624               StoreHandler::StoreGlobal(lookup->GetPropertyCell()));
1625         }
1626         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
1627         DCHECK(holder.is_identical_to(receiver));
1628         return MaybeObjectHandle(StoreHandler::StoreNormal(isolate()));
1629       }
1630 
1631       // -------------- Fields --------------
1632       if (lookup->property_details().location() == kField) {
1633         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
1634         int descriptor = lookup->GetFieldDescriptorIndex();
1635         FieldIndex index = lookup->GetFieldIndex();
1636         PropertyConstness constness = lookup->constness();
1637         if (constness == PropertyConstness::kConst &&
1638             IsStoreOwnICKind(nexus()->kind())) {
1639           // StoreOwnICs are used for initializing object literals therefore
1640           // we must store the value unconditionally even to
1641           // VariableMode::kConst fields.
1642           constness = PropertyConstness::kMutable;
1643         }
1644         return MaybeObjectHandle(StoreHandler::StoreField(
1645             isolate(), descriptor, index, constness, lookup->representation()));
1646       }
1647 
1648       // -------------- Constant properties --------------
1649       DCHECK_EQ(kDescriptor, lookup->property_details().location());
1650       set_slow_stub_reason("constant property");
1651       TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1652       return MaybeObjectHandle(slow_stub());
1653     }
1654     case LookupIterator::JSPROXY: {
1655       Handle<JSReceiver> receiver =
1656           Handle<JSReceiver>::cast(lookup->GetReceiver());
1657       Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
1658       return MaybeObjectHandle(StoreHandler::StoreProxy(
1659           isolate(), receiver_map(), holder, receiver));
1660     }
1661 
1662     case LookupIterator::INTEGER_INDEXED_EXOTIC:
1663     case LookupIterator::ACCESS_CHECK:
1664     case LookupIterator::NOT_FOUND:
1665       UNREACHABLE();
1666   }
1667   return MaybeObjectHandle();
1668 }
1669 
UpdateStoreElement(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode,bool receiver_was_cow)1670 void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
1671                                       KeyedAccessStoreMode store_mode,
1672                                       bool receiver_was_cow) {
1673   MapHandles target_receiver_maps;
1674   TargetMaps(&target_receiver_maps);
1675   if (target_receiver_maps.empty()) {
1676     Handle<Map> monomorphic_map =
1677         ComputeTransitionedMap(receiver_map, store_mode);
1678     store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1679     Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
1680     return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
1681   }
1682 
1683   for (Handle<Map> map : target_receiver_maps) {
1684     if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
1685       DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1686       set_slow_stub_reason("JSValue");
1687       return;
1688     }
1689   }
1690 
1691   // There are several special cases where an IC that is MONOMORPHIC can still
1692   // transition to a different GetNonTransitioningStoreMode IC that handles a
1693   // superset of the original IC. Handle those here if the receiver map hasn't
1694   // changed or it has transitioned to a more general kind.
1695   KeyedAccessStoreMode old_store_mode;
1696   old_store_mode = GetKeyedAccessStoreMode();
1697   Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1698   if (state() == MONOMORPHIC) {
1699     Handle<Map> transitioned_receiver_map = receiver_map;
1700     if (IsTransitionStoreMode(store_mode)) {
1701       transitioned_receiver_map =
1702           ComputeTransitionedMap(receiver_map, store_mode);
1703     }
1704     if ((receiver_map.is_identical_to(previous_receiver_map) &&
1705          IsTransitionStoreMode(store_mode)) ||
1706         IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1707                                         *transitioned_receiver_map)) {
1708       // If the "old" and "new" maps are in the same elements map family, or
1709       // if they at least come from the same origin for a transitioning store,
1710       // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1711       store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1712       Handle<Object> handler =
1713           StoreElementHandler(transitioned_receiver_map, store_mode);
1714       ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
1715       return;
1716     }
1717     if (receiver_map.is_identical_to(previous_receiver_map) &&
1718         old_store_mode == STANDARD_STORE &&
1719         (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1720          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1721          store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1722       // A "normal" IC that handles stores can switch to a version that can
1723       // grow at the end of the array, handle OOB accesses or copy COW arrays
1724       // and still stay MONOMORPHIC.
1725       Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
1726       return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1727     }
1728   }
1729 
1730   DCHECK(state() != GENERIC);
1731 
1732   bool map_added =
1733       AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1734 
1735   if (IsTransitionStoreMode(store_mode)) {
1736     Handle<Map> transitioned_receiver_map =
1737         ComputeTransitionedMap(receiver_map, store_mode);
1738     map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1739                                             transitioned_receiver_map);
1740   }
1741 
1742   if (!map_added) {
1743     // If the miss wasn't due to an unseen map, a polymorphic stub
1744     // won't help, use the megamorphic stub which can handle everything.
1745     set_slow_stub_reason("same map added twice");
1746     return;
1747   }
1748 
1749   // If the maximum number of receiver maps has been exceeded, use the
1750   // megamorphic version of the IC.
1751   if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return;
1752 
1753   // Make sure all polymorphic handlers have the same store mode, otherwise the
1754   // megamorphic stub must be used.
1755   store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1756   if (old_store_mode != STANDARD_STORE) {
1757     if (store_mode == STANDARD_STORE) {
1758       store_mode = old_store_mode;
1759     } else if (store_mode != old_store_mode) {
1760       set_slow_stub_reason("store mode mismatch");
1761       return;
1762     }
1763   }
1764 
1765   // If the store mode isn't the standard mode, make sure that all polymorphic
1766   // receivers are either external arrays, or all "normal" arrays. Otherwise,
1767   // use the megamorphic stub.
1768   if (store_mode != STANDARD_STORE) {
1769     size_t external_arrays = 0;
1770     for (Handle<Map> map : target_receiver_maps) {
1771       if (map->has_fixed_typed_array_elements()) {
1772         DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1773         external_arrays++;
1774       }
1775     }
1776     if (external_arrays != 0 &&
1777         external_arrays != target_receiver_maps.size()) {
1778       DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1779       set_slow_stub_reason(
1780           "unsupported combination of external and normal arrays");
1781       return;
1782     }
1783   }
1784 
1785   MaybeObjectHandles handlers;
1786   handlers.reserve(target_receiver_maps.size());
1787   StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
1788   if (target_receiver_maps.size() == 0) {
1789     // Transition to PREMONOMORPHIC state here and remember a weak-reference
1790     // to the {receiver_map} in case TurboFan sees this function before the
1791     // IC can transition further.
1792     ConfigureVectorState(receiver_map);
1793   } else if (target_receiver_maps.size() == 1) {
1794     ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1795   } else {
1796     ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1797   }
1798 }
1799 
1800 
ComputeTransitionedMap(Handle<Map> map,KeyedAccessStoreMode store_mode)1801 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1802     Handle<Map> map, KeyedAccessStoreMode store_mode) {
1803   switch (store_mode) {
1804     case STORE_TRANSITION_TO_OBJECT:
1805     case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1806       ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1807                               ? HOLEY_ELEMENTS
1808                               : PACKED_ELEMENTS;
1809       return Map::TransitionElementsTo(isolate(), map, kind);
1810     }
1811     case STORE_TRANSITION_TO_DOUBLE:
1812     case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1813       ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1814                               ? HOLEY_DOUBLE_ELEMENTS
1815                               : PACKED_DOUBLE_ELEMENTS;
1816       return Map::TransitionElementsTo(isolate(), map, kind);
1817     }
1818     case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1819       DCHECK(map->has_fixed_typed_array_elements());
1820       V8_FALLTHROUGH;
1821     case STORE_NO_TRANSITION_HANDLE_COW:
1822     case STANDARD_STORE:
1823     case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
1824       return map;
1825   }
1826   UNREACHABLE();
1827 }
1828 
StoreElementHandler(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)1829 Handle<Object> KeyedStoreIC::StoreElementHandler(
1830     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1831   DCHECK(store_mode == STANDARD_STORE ||
1832          store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1833          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1834          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1835   DCHECK_IMPLIES(
1836       receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()),
1837       IsStoreInArrayLiteralICKind(kind()));
1838 
1839   if (receiver_map->IsJSProxyMap()) {
1840     return StoreHandler::StoreProxy(isolate());
1841   }
1842 
1843   // TODO(ishell): move to StoreHandler::StoreElement().
1844   ElementsKind elements_kind = receiver_map->elements_kind();
1845   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1846   Handle<Code> stub;
1847   if (receiver_map->has_sloppy_arguments_elements()) {
1848     TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
1849     stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
1850   } else if (receiver_map->has_fast_elements() ||
1851              receiver_map->has_fixed_typed_array_elements()) {
1852     TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
1853     stub =
1854         StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode)
1855             .GetCode();
1856     if (receiver_map->has_fixed_typed_array_elements()) return stub;
1857   } else if (IsStoreInArrayLiteralICKind(kind())) {
1858     TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
1859     stub = StoreInArrayLiteralSlowStub(isolate(), store_mode).GetCode();
1860   } else {
1861     TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
1862     DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
1863     stub = StoreSlowElementStub(isolate(), store_mode).GetCode();
1864   }
1865 
1866   if (IsStoreInArrayLiteralICKind(kind())) return stub;
1867 
1868   Handle<Object> validity_cell =
1869       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1870   if (validity_cell->IsSmi()) {
1871     // There's no prototype validity cell to check, so we can just use the stub.
1872     return stub;
1873   }
1874   Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0);
1875   handler->set_validity_cell(*validity_cell);
1876   handler->set_smi_handler(*stub);
1877   return handler;
1878 }
1879 
StoreElementPolymorphicHandlers(MapHandles * receiver_maps,MaybeObjectHandles * handlers,KeyedAccessStoreMode store_mode)1880 void KeyedStoreIC::StoreElementPolymorphicHandlers(
1881     MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1882     KeyedAccessStoreMode store_mode) {
1883   DCHECK(store_mode == STANDARD_STORE ||
1884          store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1885          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1886          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1887 
1888   // Filter out deprecated maps to ensure their instances get migrated.
1889   receiver_maps->erase(
1890       std::remove_if(
1891           receiver_maps->begin(), receiver_maps->end(),
1892           [](const Handle<Map>& map) { return map->is_deprecated(); }),
1893       receiver_maps->end());
1894 
1895   for (Handle<Map> receiver_map : *receiver_maps) {
1896     Handle<Object> handler;
1897     Handle<Map> transition;
1898 
1899     if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
1900         receiver_map->DictionaryElementsInPrototypeChainOnly(isolate())) {
1901       // TODO(mvstanton): Consider embedding store_mode in the state of the slow
1902       // keyed store ic for uniformity.
1903       TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
1904       handler = slow_stub();
1905 
1906     } else {
1907       {
1908         Map* tmap = receiver_map->FindElementsKindTransitionedMap(
1909             isolate(), *receiver_maps);
1910         if (tmap != nullptr) {
1911           if (receiver_map->is_stable()) {
1912             receiver_map->NotifyLeafMapLayoutChange(isolate());
1913           }
1914           transition = handle(tmap, isolate());
1915         }
1916       }
1917 
1918       // TODO(mvstanton): The code below is doing pessimistic elements
1919       // transitions. I would like to stop doing that and rely on Allocation
1920       // Site Tracking to do a better job of ensuring the data types are what
1921       // they need to be. Not all the elements are in place yet, pessimistic
1922       // elements transitions are still important for performance.
1923       if (!transition.is_null()) {
1924         TRACE_HANDLER_STATS(isolate(),
1925                             KeyedStoreIC_ElementsTransitionAndStoreStub);
1926         handler = StoreHandler::StoreElementTransition(isolate(), receiver_map,
1927                                                        transition, store_mode);
1928       } else {
1929         handler = StoreElementHandler(receiver_map, store_mode);
1930       }
1931     }
1932     DCHECK(!handler.is_null());
1933     handlers->push_back(MaybeObjectHandle(handler));
1934   }
1935 }
1936 
1937 
GetStoreMode(Handle<JSObject> receiver,uint32_t index,Handle<Object> value)1938 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
1939                                          uint32_t index, Handle<Object> value) {
1940   bool oob_access = IsOutOfBoundsAccess(receiver, index);
1941   // Don't consider this a growing store if the store would send the receiver to
1942   // dictionary mode.
1943   bool allow_growth = receiver->IsJSArray() && oob_access &&
1944                       !receiver->WouldConvertToSlowElements(index);
1945   if (allow_growth) {
1946     // Handle growing array in stub if necessary.
1947     if (receiver->HasSmiElements()) {
1948       if (value->IsHeapNumber()) {
1949         return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
1950       }
1951       if (value->IsHeapObject()) {
1952         return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1953       }
1954     } else if (receiver->HasDoubleElements()) {
1955       if (!value->IsSmi() && !value->IsHeapNumber()) {
1956         return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1957       }
1958     }
1959     return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1960   } else {
1961     // Handle only in-bounds elements accesses.
1962     if (receiver->HasSmiElements()) {
1963       if (value->IsHeapNumber()) {
1964         return STORE_TRANSITION_TO_DOUBLE;
1965       } else if (value->IsHeapObject()) {
1966         return STORE_TRANSITION_TO_OBJECT;
1967       }
1968     } else if (receiver->HasDoubleElements()) {
1969       if (!value->IsSmi() && !value->IsHeapNumber()) {
1970         return STORE_TRANSITION_TO_OBJECT;
1971       }
1972     }
1973     if (!FLAG_trace_external_array_abuse &&
1974         receiver->map()->has_fixed_typed_array_elements() && oob_access) {
1975       return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1976     }
1977     return receiver->elements()->IsCowArray() ? STORE_NO_TRANSITION_HANDLE_COW
1978                                               : STANDARD_STORE;
1979   }
1980 }
1981 
1982 
Store(Handle<Object> object,Handle<Object> key,Handle<Object> value)1983 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
1984                                         Handle<Object> key,
1985                                         Handle<Object> value) {
1986   // TODO(verwaest): Let SetProperty do the migration, since storing a property
1987   // might deprecate the current map again, if value does not fit.
1988   if (MigrateDeprecated(object)) {
1989     Handle<Object> result;
1990     ASSIGN_RETURN_ON_EXCEPTION(
1991         isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
1992                                                       value, language_mode()),
1993         Object);
1994     return result;
1995   }
1996 
1997   // Check for non-string values that can be converted into an
1998   // internalized string directly or is representable as a smi.
1999   key = TryConvertKey(key, isolate());
2000 
2001   Handle<Object> store_handle;
2002 
2003   uint32_t index;
2004   if ((key->IsInternalizedString() &&
2005        !String::cast(*key)->AsArrayIndex(&index)) ||
2006       key->IsSymbol()) {
2007     ASSIGN_RETURN_ON_EXCEPTION(
2008         isolate(), store_handle,
2009         StoreIC::Store(object, Handle<Name>::cast(key), value,
2010                        JSReceiver::MAY_BE_STORE_FROM_KEYED),
2011         Object);
2012     if (vector_needs_update()) {
2013       if (ConfigureVectorState(MEGAMORPHIC, key)) {
2014         set_slow_stub_reason("unhandled internalized string key");
2015         TraceIC("StoreIC", key);
2016       }
2017     }
2018     return store_handle;
2019   }
2020 
2021   JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
2022 
2023   bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
2024                 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
2025   if (use_ic && !object->IsSmi()) {
2026     // Don't use ICs for maps of the objects in Array's prototype chain. We
2027     // expect to be able to trap element sets to objects with those maps in
2028     // the runtime to enable optimization of element hole access.
2029     Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2030     if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) {
2031       set_slow_stub_reason("map in array prototype");
2032       use_ic = false;
2033     }
2034   }
2035 
2036   Handle<Map> old_receiver_map;
2037   bool is_arguments = false;
2038   bool key_is_valid_index = false;
2039   KeyedAccessStoreMode store_mode = STANDARD_STORE;
2040   if (use_ic && object->IsJSReceiver()) {
2041     Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
2042     old_receiver_map = handle(receiver->map(), isolate());
2043     is_arguments = receiver->IsJSArgumentsObject();
2044     bool is_proxy = receiver->IsJSProxy();
2045     // For JSTypedArray {object}s we can handle negative indices as OOB
2046     // accesses, since integer indexed properties are never looked up
2047     // on the prototype chain. For this we simply map the negative {key}s
2048     // to the [2**31,2**32-1] range, which is safe since JSTypedArray::length
2049     // is always an unsigned Smi.
2050     key_is_valid_index =
2051         key->IsSmi() && (Smi::ToInt(*key) >= 0 || object->IsJSTypedArray());
2052     if (!is_arguments && !is_proxy) {
2053       if (key_is_valid_index) {
2054         uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key));
2055         Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
2056         store_mode = GetStoreMode(receiver_object, index, value);
2057       }
2058     }
2059   }
2060 
2061   DCHECK(store_handle.is_null());
2062   bool receiver_was_cow =
2063       object->IsJSArray() &&
2064       Handle<JSArray>::cast(object)->elements()->IsCowArray();
2065   ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2066                              Runtime::SetObjectProperty(isolate(), object, key,
2067                                                         value, language_mode()),
2068                              Object);
2069 
2070   if (use_ic) {
2071     if (!old_receiver_map.is_null()) {
2072       if (is_arguments) {
2073         set_slow_stub_reason("arguments receiver");
2074       } else if (key_is_valid_index) {
2075         if (old_receiver_map->is_abandoned_prototype_map()) {
2076           set_slow_stub_reason("receiver with prototype map");
2077         } else if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly(
2078                        isolate())) {
2079           // We should go generic if receiver isn't a dictionary, but our
2080           // prototype chain does have dictionary elements. This ensures that
2081           // other non-dictionary receivers in the polymorphic case benefit
2082           // from fast path keyed stores.
2083           UpdateStoreElement(old_receiver_map, store_mode, receiver_was_cow);
2084         } else {
2085           set_slow_stub_reason("dictionary or proxy prototype");
2086         }
2087       } else {
2088         set_slow_stub_reason("non-smi-like key");
2089       }
2090     } else {
2091       set_slow_stub_reason("non-JSObject receiver");
2092     }
2093   }
2094 
2095   if (vector_needs_update()) {
2096     ConfigureVectorState(MEGAMORPHIC, key);
2097   }
2098   TraceIC("StoreIC", key);
2099 
2100   return store_handle;
2101 }
2102 
2103 namespace {
StoreOwnElement(Isolate * isolate,Handle<JSArray> array,Handle<Object> index,Handle<Object> value)2104 void StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
2105                      Handle<Object> index, Handle<Object> value) {
2106   DCHECK(index->IsNumber());
2107   bool success = false;
2108   LookupIterator it = LookupIterator::PropertyOrElement(
2109       isolate, array, index, &success, LookupIterator::OWN);
2110   DCHECK(success);
2111 
2112   CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE,
2113                                                     kThrowOnError)
2114             .FromJust());
2115 }
2116 }  // namespace
2117 
Store(Handle<JSArray> array,Handle<Object> index,Handle<Object> value)2118 void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
2119                                   Handle<Object> value) {
2120   DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate()));
2121   DCHECK(index->IsNumber());
2122 
2123   if (!FLAG_use_ic || MigrateDeprecated(array)) {
2124     StoreOwnElement(isolate(), array, index, value);
2125     TraceIC("StoreInArrayLiteralIC", index);
2126     return;
2127   }
2128 
2129   // TODO(neis): Convert HeapNumber to Smi if possible?
2130 
2131   KeyedAccessStoreMode store_mode = STANDARD_STORE;
2132   if (index->IsSmi()) {
2133     DCHECK_GE(Smi::ToInt(*index), 0);
2134     uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2135     store_mode = GetStoreMode(array, index32, value);
2136   }
2137 
2138   Handle<Map> old_array_map(array->map(), isolate());
2139   bool array_was_cow = array->elements()->IsCowArray();
2140   StoreOwnElement(isolate(), array, index, value);
2141 
2142   if (index->IsSmi()) {
2143     DCHECK(!old_array_map->is_abandoned_prototype_map());
2144     UpdateStoreElement(old_array_map, store_mode, array_was_cow);
2145   } else {
2146     set_slow_stub_reason("index out of Smi range");
2147   }
2148 
2149   if (vector_needs_update()) {
2150     ConfigureVectorState(MEGAMORPHIC, index);
2151   }
2152   TraceIC("StoreInArrayLiteralIC", index);
2153 }
2154 
2155 // ----------------------------------------------------------------------------
2156 // Static IC stub generators.
2157 //
2158 
RUNTIME_FUNCTION(Runtime_LoadIC_Miss)2159 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2160   HandleScope scope(isolate);
2161   DCHECK_EQ(4, args.length());
2162   // Runtime functions don't follow the IC's calling convention.
2163   Handle<Object> receiver = args.at(0);
2164   Handle<Name> key = args.at<Name>(1);
2165   Handle<Smi> slot = args.at<Smi>(2);
2166   Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2167   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2168   // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2169   // LoadIC miss handler if the handler misses. Since the vector Nexus is
2170   // set up outside the IC, handle that here.
2171   FeedbackSlotKind kind = vector->GetKind(vector_slot);
2172   if (IsLoadICKind(kind)) {
2173     LoadIC ic(isolate, vector, vector_slot);
2174     ic.UpdateState(receiver, key);
2175     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2176 
2177   } else if (IsLoadGlobalICKind(kind)) {
2178     DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2179     receiver = isolate->global_object();
2180     LoadGlobalIC ic(isolate, vector, vector_slot);
2181     ic.UpdateState(receiver, key);
2182     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2183 
2184   } else {
2185     DCHECK(IsKeyedLoadICKind(kind));
2186     KeyedLoadIC ic(isolate, vector, vector_slot);
2187     ic.UpdateState(receiver, key);
2188     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2189   }
2190 }
2191 
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss)2192 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2193   HandleScope scope(isolate);
2194   DCHECK_EQ(3, args.length());
2195   // Runtime functions don't follow the IC's calling convention.
2196   Handle<JSGlobalObject> global = isolate->global_object();
2197   Handle<String> name = args.at<String>(0);
2198   Handle<Smi> slot = args.at<Smi>(1);
2199   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2200   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2201 
2202   LoadGlobalIC ic(isolate, vector, vector_slot);
2203   ic.UpdateState(global, name);
2204 
2205   Handle<Object> result;
2206   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2207   return *result;
2208 }
2209 
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow)2210 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2211   HandleScope scope(isolate);
2212   DCHECK_EQ(3, args.length());
2213   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2214 
2215   Handle<Context> native_context = isolate->native_context();
2216   Handle<ScriptContextTable> script_contexts(
2217       native_context->script_context_table(), isolate);
2218 
2219   ScriptContextTable::LookupResult lookup_result;
2220   if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2221                                  &lookup_result)) {
2222     Handle<Context> script_context = ScriptContextTable::GetContext(
2223         isolate, script_contexts, lookup_result.context_index);
2224     Handle<Object> result =
2225         FixedArray::get(*script_context, lookup_result.slot_index, isolate);
2226     if (*result == ReadOnlyRoots(isolate).the_hole_value()) {
2227       THROW_NEW_ERROR_RETURN_FAILURE(
2228           isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2229     }
2230     return *result;
2231   }
2232 
2233   Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2234   Handle<Object> result;
2235   bool is_found = false;
2236   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2237       isolate, result,
2238       Runtime::GetObjectProperty(isolate, global, name, &is_found));
2239   if (!is_found) {
2240     Handle<Smi> slot = args.at<Smi>(1);
2241     Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2242     FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2243     FeedbackSlotKind kind = vector->GetKind(vector_slot);
2244     // It is actually a LoadGlobalICs here but the predicate handles this case
2245     // properly.
2246     if (LoadIC::ShouldThrowReferenceError(kind)) {
2247       THROW_NEW_ERROR_RETURN_FAILURE(
2248           isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2249     }
2250   }
2251   return *result;
2252 }
2253 
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss)2254 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2255   HandleScope scope(isolate);
2256   DCHECK_EQ(4, args.length());
2257   // Runtime functions don't follow the IC's calling convention.
2258   Handle<Object> receiver = args.at(0);
2259   Handle<Object> key = args.at(1);
2260   Handle<Smi> slot = args.at<Smi>(2);
2261   Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2262   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2263   KeyedLoadIC ic(isolate, vector, vector_slot);
2264   ic.UpdateState(receiver, key);
2265   RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2266 }
2267 
RUNTIME_FUNCTION(Runtime_StoreIC_Miss)2268 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2269   HandleScope scope(isolate);
2270   DCHECK_EQ(5, args.length());
2271   // Runtime functions don't follow the IC's calling convention.
2272   Handle<Object> value = args.at(0);
2273   Handle<Smi> slot = args.at<Smi>(1);
2274   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2275   Handle<Object> receiver = args.at(3);
2276   Handle<Name> key = args.at<Name>(4);
2277   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2278   FeedbackSlotKind kind = vector->GetKind(vector_slot);
2279   if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
2280     StoreIC ic(isolate, vector, vector_slot);
2281     ic.UpdateState(receiver, key);
2282     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2283   } else if (IsStoreGlobalICKind(kind)) {
2284     DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2285     receiver = isolate->global_object();
2286     StoreGlobalIC ic(isolate, vector, vector_slot);
2287     ic.UpdateState(receiver, key);
2288     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2289   } else {
2290     DCHECK(IsKeyedStoreICKind(kind));
2291     KeyedStoreIC ic(isolate, vector, vector_slot);
2292     ic.UpdateState(receiver, key);
2293     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2294   }
2295 }
2296 
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss)2297 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2298   HandleScope scope(isolate);
2299   DCHECK_EQ(4, args.length());
2300   // Runtime functions don't follow the IC's calling convention.
2301   Handle<Object> value = args.at(0);
2302   Handle<Smi> slot = args.at<Smi>(1);
2303   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2304   Handle<Name> key = args.at<Name>(3);
2305   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2306   StoreGlobalIC ic(isolate, vector, vector_slot);
2307   Handle<JSGlobalObject> global = isolate->global_object();
2308   ic.UpdateState(global, key);
2309   RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2310 }
2311 
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow)2312 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
2313   HandleScope scope(isolate);
2314   DCHECK_EQ(5, args.length());
2315   // Runtime functions don't follow the IC's calling convention.
2316   Handle<Object> value = args.at(0);
2317   Handle<Smi> slot = args.at<Smi>(1);
2318   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2319   CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
2320 
2321 #ifdef DEBUG
2322   {
2323     FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2324     FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2325     DCHECK(IsStoreGlobalICKind(slot_kind));
2326     Handle<Object> receiver = args.at(3);
2327     DCHECK(receiver->IsJSGlobalProxy());
2328   }
2329 #endif
2330 
2331   Handle<JSGlobalObject> global = isolate->global_object();
2332   Handle<Context> native_context = isolate->native_context();
2333   Handle<ScriptContextTable> script_contexts(
2334       native_context->script_context_table(), isolate);
2335 
2336   ScriptContextTable::LookupResult lookup_result;
2337   if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2338                                  &lookup_result)) {
2339     Handle<Context> script_context = ScriptContextTable::GetContext(
2340         isolate, script_contexts, lookup_result.context_index);
2341     if (lookup_result.mode == VariableMode::kConst) {
2342       THROW_NEW_ERROR_RETURN_FAILURE(
2343           isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
2344     }
2345 
2346     Handle<Object> previous_value =
2347         FixedArray::get(*script_context, lookup_result.slot_index, isolate);
2348 
2349     if (previous_value->IsTheHole(isolate)) {
2350       THROW_NEW_ERROR_RETURN_FAILURE(
2351           isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2352     }
2353 
2354     script_context->set(lookup_result.slot_index, *value);
2355     return *value;
2356   }
2357 
2358   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2359   LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2360   RETURN_RESULT_OR_FAILURE(
2361       isolate,
2362       Runtime::SetObjectProperty(isolate, global, name, value, language_mode));
2363 }
2364 
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss)2365 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2366   HandleScope scope(isolate);
2367   DCHECK_EQ(5, args.length());
2368   // Runtime functions don't follow the IC's calling convention.
2369   Handle<Object> value = args.at(0);
2370   Handle<Smi> slot = args.at<Smi>(1);
2371   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2372   Handle<Object> receiver = args.at(3);
2373   Handle<Object> key = args.at(4);
2374   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2375   FeedbackSlotKind kind = vector->GetKind(vector_slot);
2376 
2377   // The elements store stubs miss into this function, but they are shared by
2378   // different ICs.
2379   if (IsKeyedStoreICKind(kind)) {
2380     KeyedStoreIC ic(isolate, vector, vector_slot);
2381     ic.UpdateState(receiver, key);
2382     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2383   } else {
2384     DCHECK(IsStoreInArrayLiteralICKind(kind));
2385     DCHECK(receiver->IsJSArray());
2386     DCHECK(key->IsNumber());
2387     StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2388     ic.UpdateState(receiver, key);
2389     ic.Store(Handle<JSArray>::cast(receiver), key, value);
2390     return *value;
2391   }
2392 }
2393 
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow)2394 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2395   HandleScope scope(isolate);
2396   DCHECK_EQ(5, args.length());
2397   // Runtime functions don't follow the IC's calling convention.
2398   Handle<Object> value = args.at(0);
2399   Handle<Smi> slot = args.at<Smi>(1);
2400   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2401   Handle<Object> object = args.at(3);
2402   Handle<Object> key = args.at(4);
2403   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2404   FeedbackSlotKind kind = vector->GetKind(vector_slot);
2405   DCHECK(IsStoreICKind(kind) || IsKeyedStoreICKind(kind));
2406   LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
2407   RETURN_RESULT_OR_FAILURE(
2408       isolate,
2409       Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2410 }
2411 
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow)2412 RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
2413   HandleScope scope(isolate);
2414   DCHECK_EQ(3, args.length());
2415   // Runtime functions don't follow the IC's calling convention.
2416   Handle<Object> value = args.at(0);
2417   Handle<Object> array = args.at(1);
2418   Handle<Object> index = args.at(2);
2419   StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value);
2420   return *value;
2421 }
2422 
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss)2423 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2424   HandleScope scope(isolate);
2425   DCHECK_EQ(6, args.length());
2426   // Runtime functions don't follow the IC's calling convention.
2427   Handle<Object> object = args.at(0);
2428   Handle<Object> key = args.at(1);
2429   Handle<Object> value = args.at(2);
2430   Handle<Map> map = args.at<Map>(3);
2431   Handle<Smi> slot = args.at<Smi>(4);
2432   Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2433   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2434   FeedbackSlotKind kind = vector->GetKind(vector_slot);
2435 
2436   if (object->IsJSObject()) {
2437     JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2438                                      map->elements_kind());
2439   }
2440 
2441   if (IsStoreInArrayLiteralICKind(kind)) {
2442     StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value);
2443     return *value;
2444   } else {
2445     DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
2446     LanguageMode language_mode = GetLanguageModeFromSlotKind(kind);
2447     RETURN_RESULT_OR_FAILURE(
2448         isolate,
2449         Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2450   }
2451 }
2452 
CanFastCloneObject(Handle<Map> map)2453 static bool CanFastCloneObject(Handle<Map> map) {
2454   DisallowHeapAllocation no_gc;
2455   if (map->IsNullOrUndefinedMap()) return true;
2456   if (!map->IsJSObjectMap() ||
2457       !IsSmiOrObjectElementsKind(map->elements_kind()) ||
2458       !map->OnlyHasSimpleProperties()) {
2459     return false;
2460   }
2461 
2462   DescriptorArray* descriptors = map->instance_descriptors();
2463   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
2464     PropertyDetails details = descriptors->GetDetails(i);
2465     Name* key = descriptors->GetKey(i);
2466     if (details.kind() != kData || !details.IsEnumerable() ||
2467         key->IsPrivateField()) {
2468       return false;
2469     }
2470   }
2471 
2472   return true;
2473 }
2474 
FastCloneObjectMap(Isolate * isolate,Handle<HeapObject> source,int flags)2475 static Handle<Map> FastCloneObjectMap(Isolate* isolate,
2476                                       Handle<HeapObject> source, int flags) {
2477   Handle<Map> source_map(source->map(), isolate);
2478   SLOW_DCHECK(source->IsNullOrUndefined() || CanFastCloneObject(source_map));
2479   Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2480                                  isolate);
2481   DCHECK(constructor->has_initial_map());
2482   Handle<Map> initial_map(constructor->initial_map(), isolate);
2483   Handle<Map> map = initial_map;
2484 
2485   if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() !=
2486                                          initial_map->GetInObjectProperties()) {
2487     int inobject_properties = source_map->GetInObjectProperties();
2488     int instance_size =
2489         JSObject::kHeaderSize + kPointerSize * inobject_properties;
2490     int unused = source_map->UnusedInObjectProperties();
2491     DCHECK(instance_size <= JSObject::kMaxInstanceSize);
2492     map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties,
2493                               unused);
2494   }
2495 
2496   if (flags & ObjectLiteral::kHasNullPrototype) {
2497     if (map.is_identical_to(initial_map)) {
2498       map = Map::Copy(isolate, map, "ObjectWithNullProto");
2499     }
2500     Map::SetPrototype(isolate, map, isolate->factory()->null_value());
2501   }
2502 
2503   if (source->IsNullOrUndefined() || !source_map->NumberOfOwnDescriptors()) {
2504     return map;
2505   }
2506 
2507   if (map.is_identical_to(initial_map)) {
2508     map = Map::Copy(isolate, map, "InitializeClonedDescriptors");
2509   }
2510 
2511   Handle<DescriptorArray> source_descriptors(source_map->instance_descriptors(),
2512                                              isolate);
2513   int size = source_map->NumberOfOwnDescriptors();
2514   int slack = 0;
2515   Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone(
2516       isolate, source_descriptors, size, slack);
2517   Handle<LayoutDescriptor> layout =
2518       LayoutDescriptor::New(isolate, map, descriptors, size);
2519   map->InitializeDescriptors(*descriptors, *layout);
2520   map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map);
2521 
2522   // Update bitfields
2523   map->set_may_have_interesting_symbols(
2524       source_map->may_have_interesting_symbols());
2525 
2526   return map;
2527 }
2528 
CloneObjectSlowPath(Isolate * isolate,Handle<HeapObject> source,int flags)2529 static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
2530                                                  Handle<HeapObject> source,
2531                                                  int flags) {
2532   Handle<JSObject> new_object;
2533   if (flags & ObjectLiteral::kHasNullPrototype) {
2534     new_object = isolate->factory()->NewJSObjectWithNullProto();
2535   } else {
2536     Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2537                                    isolate);
2538     new_object = isolate->factory()->NewJSObject(constructor);
2539   }
2540 
2541   if (source->IsNullOrUndefined()) {
2542     return new_object;
2543   }
2544 
2545   MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source,
2546                                                    nullptr, false),
2547                MaybeHandle<JSObject>());
2548   return new_object;
2549 }
2550 
RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss)2551 RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
2552   HandleScope scope(isolate);
2553   DCHECK_EQ(4, args.length());
2554   Handle<HeapObject> source = args.at<HeapObject>(0);
2555   int flags = args.smi_at(1);
2556 
2557   MigrateDeprecated(source);
2558 
2559   FeedbackSlot slot = FeedbackVector::ToSlot(args.smi_at(2));
2560   Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2561 
2562   FeedbackNexus nexus(vector, slot);
2563   Handle<Map> source_map(source->map(), isolate);
2564 
2565   if (!CanFastCloneObject(source_map) || nexus.IsMegamorphic()) {
2566     // Migrate to slow mode if needed.
2567     nexus.ConfigureMegamorphic();
2568     RETURN_RESULT_OR_FAILURE(isolate,
2569                              CloneObjectSlowPath(isolate, source, flags));
2570   }
2571 
2572   Handle<Map> result_map = FastCloneObjectMap(isolate, source, flags);
2573   nexus.ConfigureCloneObject(source_map, result_map);
2574 
2575   return *result_map;
2576 }
2577 
RUNTIME_FUNCTION(Runtime_CloneObjectIC_Slow)2578 RUNTIME_FUNCTION(Runtime_CloneObjectIC_Slow) {
2579   HandleScope scope(isolate);
2580   DCHECK_EQ(2, args.length());
2581   Handle<HeapObject> source = args.at<HeapObject>(0);
2582   int flags = args.smi_at(1);
2583   RETURN_RESULT_OR_FAILURE(isolate,
2584                            CloneObjectSlowPath(isolate, source, flags));
2585 }
2586 
RUNTIME_FUNCTION(Runtime_StoreCallbackProperty)2587 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2588   Handle<JSObject> receiver = args.at<JSObject>(0);
2589   Handle<JSObject> holder = args.at<JSObject>(1);
2590   Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2591   Handle<Name> name = args.at<Name>(3);
2592   Handle<Object> value = args.at(4);
2593   CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
2594   HandleScope scope(isolate);
2595 
2596   if (V8_UNLIKELY(FLAG_runtime_stats)) {
2597     RETURN_RESULT_OR_FAILURE(
2598         isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
2599                                             language_mode));
2600   }
2601 
2602   DCHECK(info->IsCompatibleReceiver(*receiver));
2603 
2604   ShouldThrow should_throw =
2605       is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
2606   PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
2607                                       should_throw);
2608   arguments.CallAccessorSetter(info, name, value);
2609   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2610   return *value;
2611 }
2612 
RUNTIME_FUNCTION(Runtime_LoadCallbackProperty)2613 RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) {
2614   Handle<JSObject> receiver = args.at<JSObject>(0);
2615   Handle<JSObject> holder = args.at<JSObject>(1);
2616   Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2617   Handle<Name> name = args.at<Name>(3);
2618   HandleScope scope(isolate);
2619 
2620   DCHECK(info->IsCompatibleReceiver(*receiver));
2621 
2622   PropertyCallbackArguments custom_args(isolate, info->data(), *receiver,
2623                                         *holder, kThrowOnError);
2624   Handle<Object> result = custom_args.CallAccessorGetter(info, name);
2625   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2626   if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2627   return *result;
2628 }
2629 
RUNTIME_FUNCTION(Runtime_LoadAccessorProperty)2630 RUNTIME_FUNCTION(Runtime_LoadAccessorProperty) {
2631   HandleScope scope(isolate);
2632   DCHECK_EQ(args.length(), 3);
2633   Handle<JSObject> receiver = args.at<JSObject>(0);
2634   int handler_kind = args.smi_at(1);
2635   Handle<CallHandlerInfo> call_handler_info = args.at<CallHandlerInfo>(2);
2636 
2637   Object* holder = *receiver;
2638   if (handler_kind == LoadHandler::kApiGetterHolderIsPrototype) {
2639     holder = receiver->map()->prototype();
2640   } else {
2641     DCHECK_EQ(handler_kind, LoadHandler::kApiGetter);
2642   }
2643 
2644   // Call the accessor without additional arguments.
2645   FunctionCallbackArguments custom(isolate, call_handler_info->data(),
2646                                    *receiver, holder, nullptr, nullptr, 0);
2647   Handle<Object> result_handle = custom.Call(*call_handler_info);
2648   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2649   if (result_handle.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2650   return *result_handle;
2651 }
2652 
2653 /**
2654  * Loads a property with an interceptor performing post interceptor
2655  * lookup if interceptor failed.
2656  */
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor)2657 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2658   HandleScope scope(isolate);
2659   DCHECK_EQ(5, args.length());
2660   Handle<Name> name = args.at<Name>(0);
2661   Handle<Object> receiver = args.at(1);
2662   Handle<JSObject> holder = args.at<JSObject>(2);
2663 
2664   if (!receiver->IsJSReceiver()) {
2665     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2666         isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2667   }
2668 
2669   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
2670   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2671                                       *holder, kDontThrow);
2672   Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
2673 
2674   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2675 
2676   if (!result.is_null()) return *result;
2677 
2678   LookupIterator it(receiver, name, holder);
2679   // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2680   while (it.state() != LookupIterator::INTERCEPTOR ||
2681          !it.GetHolder<JSObject>().is_identical_to(holder)) {
2682     DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2683     it.Next();
2684   }
2685   // Skip past the interceptor.
2686   it.Next();
2687   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2688 
2689   if (it.IsFound()) return *result;
2690 
2691   Handle<Smi> slot = args.at<Smi>(3);
2692   Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2693   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2694   FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2695   // It could actually be any kind of load IC slot here but the predicate
2696   // handles all the cases properly.
2697   if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
2698     return ReadOnlyRoots(isolate).undefined_value();
2699   }
2700 
2701   // Throw a reference error.
2702   THROW_NEW_ERROR_RETURN_FAILURE(
2703       isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
2704 }
2705 
2706 
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor)2707 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
2708   HandleScope scope(isolate);
2709   DCHECK_EQ(5, args.length());
2710   // Runtime functions don't follow the IC's calling convention.
2711   Handle<Object> value = args.at(0);
2712   Handle<Smi> slot = args.at<Smi>(1);
2713   Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2714   Handle<JSObject> receiver = args.at<JSObject>(3);
2715   Handle<Name> name = args.at<Name>(4);
2716   FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2717   LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2718 
2719   // TODO(ishell): Cache interceptor_holder in the store handler like we do
2720   // for LoadHandler::kInterceptor case.
2721   Handle<JSObject> interceptor_holder = receiver;
2722   if (receiver->IsJSGlobalProxy()) {
2723     FeedbackSlotKind kind = vector->GetKind(vector_slot);
2724     if (IsStoreGlobalICKind(kind)) {
2725       interceptor_holder = Handle<JSObject>::cast(isolate->global_object());
2726     }
2727   }
2728   DCHECK(interceptor_holder->HasNamedInterceptor());
2729   Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
2730                                       isolate);
2731 
2732   DCHECK(!interceptor->non_masking());
2733   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2734                                       *receiver, kDontThrow);
2735 
2736   Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
2737   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2738   if (!result.is_null()) return *value;
2739 
2740   LookupIterator it(receiver, name, receiver);
2741   // Skip past any access check on the receiver.
2742   if (it.state() == LookupIterator::ACCESS_CHECK) {
2743     DCHECK(it.HasAccess());
2744     it.Next();
2745   }
2746   // Skip past the interceptor on the receiver.
2747   DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2748   it.Next();
2749 
2750   MAYBE_RETURN(Object::SetProperty(&it, value, language_mode,
2751                                    JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
2752                ReadOnlyRoots(isolate).exception());
2753   return *value;
2754 }
2755 
2756 
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor)2757 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2758   // TODO(verwaest): This should probably get the holder and receiver as input.
2759   HandleScope scope(isolate);
2760   Handle<JSObject> receiver = args.at<JSObject>(0);
2761   DCHECK_GE(args.smi_at(1), 0);
2762   uint32_t index = args.smi_at(1);
2763 
2764   Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
2765                                       isolate);
2766   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2767                                       *receiver, kDontThrow);
2768   Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
2769 
2770   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2771 
2772   if (result.is_null()) {
2773     LookupIterator it(isolate, receiver, index, receiver);
2774     DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2775     it.Next();
2776     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2777                                        Object::GetProperty(&it));
2778   }
2779 
2780   return *result;
2781 }
2782 }  // namespace internal
2783 }  // namespace v8
2784