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 <iostream>
8 
9 #include "src/accessors.h"
10 #include "src/api-arguments-inl.h"
11 #include "src/api.h"
12 #include "src/arguments.h"
13 #include "src/base/bits.h"
14 #include "src/codegen.h"
15 #include "src/conversions.h"
16 #include "src/execution.h"
17 #include "src/field-type.h"
18 #include "src/frames-inl.h"
19 #include "src/ic/call-optimization.h"
20 #include "src/ic/handler-compiler.h"
21 #include "src/ic/handler-configuration-inl.h"
22 #include "src/ic/ic-compiler.h"
23 #include "src/ic/ic-inl.h"
24 #include "src/ic/stub-cache.h"
25 #include "src/isolate-inl.h"
26 #include "src/macro-assembler.h"
27 #include "src/prototype.h"
28 #include "src/runtime-profiler.h"
29 #include "src/runtime/runtime-utils.h"
30 #include "src/runtime/runtime.h"
31 #include "src/tracing/trace-event.h"
32 
33 namespace v8 {
34 namespace internal {
35 
TransitionMarkFromState(IC::State state)36 char IC::TransitionMarkFromState(IC::State state) {
37   switch (state) {
38     case UNINITIALIZED:
39       return '0';
40     case PREMONOMORPHIC:
41       return '.';
42     case MONOMORPHIC:
43       return '1';
44     case RECOMPUTE_HANDLER:
45       return '^';
46     case POLYMORPHIC:
47       return 'P';
48     case MEGAMORPHIC:
49       return 'N';
50     case GENERIC:
51       return 'G';
52   }
53   UNREACHABLE();
54   return 0;
55 }
56 
57 
GetTransitionMarkModifier(KeyedAccessStoreMode mode)58 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
59   if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
60   if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
61     return ".IGNORE_OOB";
62   }
63   if (IsGrowStoreMode(mode)) return ".GROW";
64   return "";
65 }
66 
67 
68 #ifdef DEBUG
69 
70 #define TRACE_GENERIC_IC(isolate, type, reason)                \
71   do {                                                         \
72     if (FLAG_trace_ic) {                                       \
73       PrintF("[%s patching generic stub in ", type);           \
74       JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
75       PrintF(" (%s)]\n", reason);                              \
76     }                                                          \
77   } while (false)
78 
79 #else
80 
81 #define TRACE_GENERIC_IC(isolate, type, reason)      \
82   do {                                               \
83     if (FLAG_trace_ic) {                             \
84       PrintF("[%s patching generic stub in ", type); \
85       PrintF("(see below) (%s)]\n", reason);         \
86     }                                                \
87   } while (false)
88 
89 #endif  // DEBUG
90 
91 
TraceIC(const char * type,Handle<Object> name)92 void IC::TraceIC(const char* type, Handle<Object> name) {
93   if (FLAG_trace_ic) {
94     if (AddressIsDeoptimizedCode()) return;
95     DCHECK(UseVector());
96     State new_state = nexus()->StateFromFeedback();
97     TraceIC(type, name, state(), new_state);
98   }
99 }
100 
101 
TraceIC(const char * type,Handle<Object> name,State old_state,State new_state)102 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
103                  State new_state) {
104   if (!FLAG_trace_ic) return;
105   PrintF("[%s%s in ", is_keyed() ? "Keyed" : "", type);
106 
107   // TODO(jkummerow): Add support for "apply". The logic is roughly:
108   // marker = [fp_ + kMarkerOffset];
109   // if marker is smi and marker.value == INTERNAL and
110   //     the frame's code == builtin(Builtins::kFunctionApply):
111   // then print "apply from" and advance one frame
112 
113   Object* maybe_function =
114       Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
115   if (maybe_function->IsJSFunction()) {
116     JSFunction* function = JSFunction::cast(maybe_function);
117     int code_offset = 0;
118     if (function->IsInterpreted()) {
119       code_offset = InterpretedFrame::GetBytecodeOffset(fp());
120     } else {
121       code_offset =
122           static_cast<int>(pc() - function->code()->instruction_start());
123     }
124     JavaScriptFrame::PrintFunctionAndOffset(function, function->abstract_code(),
125                                             code_offset, stdout, true);
126   }
127 
128   const char* modifier = "";
129   if (kind() == Code::KEYED_STORE_IC) {
130     KeyedAccessStoreMode mode =
131         casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
132     modifier = GetTransitionMarkModifier(mode);
133   }
134   Map* map = nullptr;
135   if (!receiver_map().is_null()) {
136     map = *receiver_map();
137   }
138   PrintF(" (%c->%c%s) map=(%p", TransitionMarkFromState(old_state),
139          TransitionMarkFromState(new_state), modifier,
140          reinterpret_cast<void*>(map));
141   if (map != nullptr) {
142     PrintF(" dict=%u own=%u type=", map->is_dictionary_map(),
143            map->NumberOfOwnDescriptors());
144     std::cout << map->instance_type();
145   }
146   PrintF(") ");
147   name->ShortPrint(stdout);
148   PrintF("]\n");
149 }
150 
151 
152 #define TRACE_IC(type, name) TraceIC(type, name)
153 
154 
IC(FrameDepth depth,Isolate * isolate,FeedbackNexus * nexus)155 IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
156     : isolate_(isolate),
157       vector_set_(false),
158       target_maps_set_(false),
159       nexus_(nexus) {
160   // To improve the performance of the (much used) IC code, we unfold a few
161   // levels of the stack frame iteration code. This yields a ~35% speedup when
162   // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
163   const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
164   Address* constant_pool = NULL;
165   if (FLAG_enable_embedded_constant_pool) {
166     constant_pool = reinterpret_cast<Address*>(
167         entry + ExitFrameConstants::kConstantPoolOffset);
168   }
169   Address* pc_address =
170       reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
171   Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
172   // If there's another JavaScript frame on the stack or a
173   // StubFailureTrampoline, we need to look one frame further down the stack to
174   // find the frame pointer and the return address stack slot.
175   if (depth == EXTRA_CALL_FRAME) {
176     if (FLAG_enable_embedded_constant_pool) {
177       constant_pool = reinterpret_cast<Address*>(
178           fp + StandardFrameConstants::kConstantPoolOffset);
179     }
180     const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
181     pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
182     fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
183   }
184 #ifdef DEBUG
185   StackFrameIterator it(isolate);
186   for (int i = 0; i < depth + 1; i++) it.Advance();
187   StackFrame* frame = it.frame();
188   DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
189 #endif
190   // For interpreted functions, some bytecode handlers construct a
191   // frame. We have to skip the constructed frame to find the interpreted
192   // function's frame. Check if the there is an additional frame, and if there
193   // is skip this frame. However, the pc should not be updated. The call to
194   // ICs happen from bytecode handlers.
195   Object* frame_type =
196       Memory::Object_at(fp + TypedFrameConstants::kFrameTypeOffset);
197   if (frame_type == Smi::FromInt(StackFrame::STUB)) {
198     fp = Memory::Address_at(fp + TypedFrameConstants::kCallerFPOffset);
199   }
200   fp_ = fp;
201   if (FLAG_enable_embedded_constant_pool) {
202     constant_pool_address_ = constant_pool;
203   }
204   pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
205   Code* target = this->target();
206   kind_ = target->kind();
207   state_ = UseVector() ? nexus->StateFromFeedback() : StateFromCode(target);
208   old_state_ = state_;
209   extra_ic_state_ = target->extra_ic_state();
210 }
211 
212 // The ICs that don't pass slot and vector through the stack have to
213 // save/restore them in the dispatcher.
ShouldPushPopSlotAndVector(Code::Kind kind)214 bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
215   if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
216       kind == Code::KEYED_LOAD_IC || kind == Code::CALL_IC) {
217     return true;
218   }
219   if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
220     return !StoreWithVectorDescriptor::kPassLastArgsOnStack;
221   }
222   return false;
223 }
224 
StateFromCode(Code * code)225 InlineCacheState IC::StateFromCode(Code* code) {
226   Isolate* isolate = code->GetIsolate();
227   switch (code->kind()) {
228     case Code::BINARY_OP_IC: {
229       BinaryOpICState state(isolate, code->extra_ic_state());
230       return state.GetICState();
231     }
232     case Code::COMPARE_IC: {
233       CompareICStub stub(isolate, code->extra_ic_state());
234       return stub.GetICState();
235     }
236     case Code::TO_BOOLEAN_IC: {
237       ToBooleanICStub stub(isolate, code->extra_ic_state());
238       return stub.GetICState();
239     }
240     default:
241       if (code->is_debug_stub()) return UNINITIALIZED;
242       UNREACHABLE();
243       return UNINITIALIZED;
244   }
245 }
246 
GetSharedFunctionInfo() const247 SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
248   // Compute the JavaScript frame for the frame pointer of this IC
249   // structure. We need this to be able to find the function
250   // corresponding to the frame.
251   StackFrameIterator it(isolate());
252   while (it.frame()->fp() != this->fp()) it.Advance();
253   JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
254   // Find the function on the stack and both the active code for the
255   // function and the original code.
256   JSFunction* function = frame->function();
257   return function->shared();
258 }
259 
260 
GetCode() const261 Code* IC::GetCode() const {
262   HandleScope scope(isolate());
263   Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
264   Code* code = shared->code();
265   return code;
266 }
267 
LookupForRead(LookupIterator * it)268 static void LookupForRead(LookupIterator* it) {
269   for (; it->IsFound(); it->Next()) {
270     switch (it->state()) {
271       case LookupIterator::NOT_FOUND:
272       case LookupIterator::TRANSITION:
273         UNREACHABLE();
274       case LookupIterator::JSPROXY:
275         return;
276       case LookupIterator::INTERCEPTOR: {
277         // If there is a getter, return; otherwise loop to perform the lookup.
278         Handle<JSObject> holder = it->GetHolder<JSObject>();
279         if (!holder->GetNamedInterceptor()->getter()->IsUndefined(
280                 it->isolate())) {
281           return;
282         }
283         break;
284       }
285       case LookupIterator::ACCESS_CHECK:
286         // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
287         // access checks for global proxies.
288         if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
289           break;
290         }
291         return;
292       case LookupIterator::ACCESSOR:
293       case LookupIterator::INTEGER_INDEXED_EXOTIC:
294       case LookupIterator::DATA:
295         return;
296     }
297   }
298 }
299 
ShouldRecomputeHandler(Handle<String> name)300 bool IC::ShouldRecomputeHandler(Handle<String> name) {
301   if (!RecomputeHandlerForName(name)) return false;
302 
303   DCHECK(UseVector());
304   maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
305 
306   // This is a contextual access, always just update the handler and stay
307   // monomorphic.
308   if (kind() == Code::LOAD_GLOBAL_IC) return true;
309 
310   // The current map wasn't handled yet. There's no reason to stay monomorphic,
311   // *unless* we're moving from a deprecated map to its replacement, or
312   // to a more general elements kind.
313   // TODO(verwaest): Check if the current map is actually what the old map
314   // would transition to.
315   if (maybe_handler_.is_null()) {
316     if (!receiver_map()->IsJSObjectMap()) return false;
317     Map* first_map = FirstTargetMap();
318     if (first_map == NULL) return false;
319     Handle<Map> old_map(first_map);
320     if (old_map->is_deprecated()) return true;
321     return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
322                                                receiver_map()->elements_kind());
323   }
324 
325   return true;
326 }
327 
RecomputeHandlerForName(Handle<Object> name)328 bool IC::RecomputeHandlerForName(Handle<Object> name) {
329   if (is_keyed()) {
330     // Determine whether the failure is due to a name failure.
331     if (!name->IsName()) return false;
332     DCHECK(UseVector());
333     Name* stub_name = nexus()->FindFirstName();
334     if (*name != stub_name) return false;
335   }
336 
337   return true;
338 }
339 
340 
UpdateState(Handle<Object> receiver,Handle<Object> name)341 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
342   update_receiver_map(receiver);
343   if (!name->IsString()) return;
344   if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
345   if (receiver->IsUndefined(isolate()) || receiver->IsNull(isolate())) return;
346 
347   // Remove the target from the code cache if it became invalid
348   // because of changes in the prototype chain to avoid hitting it
349   // again.
350   if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
351     MarkRecomputeHandler(name);
352   }
353 }
354 
355 
TypeError(MessageTemplate::Template index,Handle<Object> object,Handle<Object> key)356 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
357                                   Handle<Object> object, Handle<Object> key) {
358   HandleScope scope(isolate());
359   THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
360 }
361 
362 
ReferenceError(Handle<Name> name)363 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
364   HandleScope scope(isolate());
365   THROW_NEW_ERROR(
366       isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
367 }
368 
369 
ComputeTypeInfoCountDelta(IC::State old_state,IC::State new_state,int * polymorphic_delta,int * generic_delta)370 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
371                                       int* polymorphic_delta,
372                                       int* generic_delta) {
373   switch (old_state) {
374     case UNINITIALIZED:
375     case PREMONOMORPHIC:
376       if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
377       if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
378         *polymorphic_delta = 1;
379       } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
380         *generic_delta = 1;
381       }
382       break;
383     case MONOMORPHIC:
384     case POLYMORPHIC:
385       if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
386       *polymorphic_delta = -1;
387       if (new_state == MEGAMORPHIC || new_state == GENERIC) {
388         *generic_delta = 1;
389       }
390       break;
391     case MEGAMORPHIC:
392     case GENERIC:
393       if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
394       *generic_delta = -1;
395       if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
396         *polymorphic_delta = 1;
397       }
398       break;
399     case RECOMPUTE_HANDLER:
400       UNREACHABLE();
401   }
402 }
403 
404 // static
OnTypeFeedbackChanged(Isolate * isolate,Code * host)405 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
406   if (host->kind() != Code::FUNCTION) return;
407 
408   TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
409   info->change_own_type_change_checksum();
410   host->set_profiler_ticks(0);
411   isolate->runtime_profiler()->NotifyICChanged();
412   // TODO(2029): When an optimized function is patched, it would
413   // be nice to propagate the corresponding type information to its
414   // unoptimized version for the benefit of later inlining.
415 }
416 
PostPatching(Address address,Code * target,Code * old_target)417 void IC::PostPatching(Address address, Code* target, Code* old_target) {
418   // Type vector based ICs update these statistics at a different time because
419   // they don't always patch on state change.
420   if (ICUseVector(target->kind())) return;
421 
422   DCHECK(old_target->is_inline_cache_stub());
423   DCHECK(target->is_inline_cache_stub());
424   State old_state = StateFromCode(old_target);
425   State new_state = StateFromCode(target);
426 
427   Isolate* isolate = target->GetIsolate();
428   Code* host =
429       isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
430   if (host->kind() != Code::FUNCTION) return;
431 
432   // Not all Code objects have TypeFeedbackInfo.
433   if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
434     if (FLAG_type_info_threshold > 0) {
435       int polymorphic_delta = 0;  // "Polymorphic" here includes monomorphic.
436       int generic_delta = 0;      // "Generic" here includes megamorphic.
437       ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
438                                 &generic_delta);
439       TypeFeedbackInfo* info =
440           TypeFeedbackInfo::cast(host->type_feedback_info());
441       info->change_ic_with_type_info_count(polymorphic_delta);
442       info->change_ic_generic_count(generic_delta);
443     }
444     TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
445     info->change_own_type_change_checksum();
446   }
447   host->set_profiler_ticks(0);
448   isolate->runtime_profiler()->NotifyICChanged();
449   // TODO(2029): When an optimized function is patched, it would
450   // be nice to propagate the corresponding type information to its
451   // unoptimized version for the benefit of later inlining.
452 }
453 
Clear(Isolate * isolate,Address address,Address constant_pool)454 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
455   Code* target = GetTargetAtAddress(address, constant_pool);
456 
457   // Don't clear debug break inline cache as it will remove the break point.
458   if (target->is_debug_stub()) return;
459 
460   if (target->kind() == Code::COMPARE_IC) {
461     CompareIC::Clear(isolate, address, target, constant_pool);
462   }
463 }
464 
465 
Clear(Isolate * isolate,Code * host,KeyedLoadICNexus * nexus)466 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
467   if (IsCleared(nexus)) return;
468   // Make sure to also clear the map used in inline fast cases.  If we
469   // do not clear these maps, cached code can keep objects alive
470   // through the embedded maps.
471   nexus->ConfigurePremonomorphic();
472   OnTypeFeedbackChanged(isolate, host);
473 }
474 
475 
Clear(Isolate * isolate,Code * host,CallICNexus * nexus)476 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
477   // Determine our state.
478   Object* feedback = nexus->vector()->Get(nexus->slot());
479   State state = nexus->StateFromFeedback();
480 
481   if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
482     nexus->ConfigureUninitialized();
483     // The change in state must be processed.
484     OnTypeFeedbackChanged(isolate, host);
485   }
486 }
487 
488 
Clear(Isolate * isolate,Code * host,LoadICNexus * nexus)489 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
490   if (IsCleared(nexus)) return;
491   nexus->ConfigurePremonomorphic();
492   OnTypeFeedbackChanged(isolate, host);
493 }
494 
Clear(Isolate * isolate,Code * host,LoadGlobalICNexus * nexus)495 void LoadGlobalIC::Clear(Isolate* isolate, Code* host,
496                          LoadGlobalICNexus* nexus) {
497   if (IsCleared(nexus)) return;
498   nexus->ConfigureUninitialized();
499   OnTypeFeedbackChanged(isolate, host);
500 }
501 
Clear(Isolate * isolate,Code * host,StoreICNexus * nexus)502 void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
503   if (IsCleared(nexus)) return;
504   nexus->ConfigurePremonomorphic();
505   OnTypeFeedbackChanged(isolate, host);
506 }
507 
508 
Clear(Isolate * isolate,Code * host,KeyedStoreICNexus * nexus)509 void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
510                          KeyedStoreICNexus* nexus) {
511   if (IsCleared(nexus)) return;
512   nexus->ConfigurePremonomorphic();
513   OnTypeFeedbackChanged(isolate, host);
514 }
515 
516 
Clear(Isolate * isolate,Address address,Code * target,Address constant_pool)517 void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
518                       Address constant_pool) {
519   DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
520   CompareICStub stub(target->stub_key(), isolate);
521   // Only clear CompareICs that can retain objects.
522   if (stub.state() != CompareICState::KNOWN_RECEIVER) return;
523   SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
524                      constant_pool);
525   PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK);
526 }
527 
MigrateDeprecated(Handle<Object> object)528 static bool MigrateDeprecated(Handle<Object> object) {
529   if (!object->IsJSObject()) return false;
530   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
531   if (!receiver->map()->is_deprecated()) return false;
532   JSObject::MigrateInstance(Handle<JSObject>::cast(object));
533   return true;
534 }
535 
ConfigureVectorState(IC::State new_state,Handle<Object> key)536 void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
537   DCHECK(UseVector());
538   if (new_state == PREMONOMORPHIC) {
539     nexus()->ConfigurePremonomorphic();
540   } else if (new_state == MEGAMORPHIC) {
541     if (kind() == Code::LOAD_IC || kind() == Code::STORE_IC) {
542       nexus()->ConfigureMegamorphic();
543     } else if (kind() == Code::KEYED_LOAD_IC) {
544       KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
545       nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
546     } else {
547       DCHECK(kind() == Code::KEYED_STORE_IC);
548       KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
549       nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
550     }
551   } else {
552     UNREACHABLE();
553   }
554 
555   vector_set_ = true;
556   OnTypeFeedbackChanged(isolate(), get_host());
557 }
558 
ConfigureVectorState(Handle<Name> name,Handle<Map> map,Handle<Object> handler)559 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
560                               Handle<Object> handler) {
561   DCHECK(UseVector());
562   if (kind() == Code::LOAD_IC) {
563     LoadICNexus* nexus = casted_nexus<LoadICNexus>();
564     nexus->ConfigureMonomorphic(map, handler);
565   } else if (kind() == Code::LOAD_GLOBAL_IC) {
566     LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
567     nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
568   } else if (kind() == Code::KEYED_LOAD_IC) {
569     KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
570     nexus->ConfigureMonomorphic(name, map, handler);
571   } else if (kind() == Code::STORE_IC) {
572     StoreICNexus* nexus = casted_nexus<StoreICNexus>();
573     nexus->ConfigureMonomorphic(map, handler);
574   } else {
575     DCHECK(kind() == Code::KEYED_STORE_IC);
576     KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
577     nexus->ConfigureMonomorphic(name, map, handler);
578   }
579 
580   vector_set_ = true;
581   OnTypeFeedbackChanged(isolate(), get_host());
582 }
583 
ConfigureVectorState(Handle<Name> name,MapHandleList * maps,List<Handle<Object>> * handlers)584 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
585                               List<Handle<Object>>* handlers) {
586   DCHECK(UseVector());
587   if (kind() == Code::LOAD_IC) {
588     LoadICNexus* nexus = casted_nexus<LoadICNexus>();
589     nexus->ConfigurePolymorphic(maps, handlers);
590   } else if (kind() == Code::KEYED_LOAD_IC) {
591     KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
592     nexus->ConfigurePolymorphic(name, maps, handlers);
593   } else if (kind() == Code::STORE_IC) {
594     StoreICNexus* nexus = casted_nexus<StoreICNexus>();
595     nexus->ConfigurePolymorphic(maps, handlers);
596   } else {
597     DCHECK(kind() == Code::KEYED_STORE_IC);
598     KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
599     nexus->ConfigurePolymorphic(name, maps, handlers);
600   }
601 
602   vector_set_ = true;
603   OnTypeFeedbackChanged(isolate(), get_host());
604 }
605 
606 
ConfigureVectorState(MapHandleList * maps,MapHandleList * transitioned_maps,CodeHandleList * handlers)607 void IC::ConfigureVectorState(MapHandleList* maps,
608                               MapHandleList* transitioned_maps,
609                               CodeHandleList* handlers) {
610   DCHECK(UseVector());
611   DCHECK(kind() == Code::KEYED_STORE_IC);
612   KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
613   nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
614 
615   vector_set_ = true;
616   OnTypeFeedbackChanged(isolate(), get_host());
617 }
618 
619 
Load(Handle<Object> object,Handle<Name> name)620 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
621   // If the object is undefined or null it's illegal to try to get any
622   // of its properties; throw a TypeError in that case.
623   if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
624     return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
625   }
626 
627   bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
628 
629   if (state() != UNINITIALIZED) {
630     JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
631     update_receiver_map(object);
632   }
633   // Named lookup in the object.
634   LookupIterator it(object, name);
635   LookupForRead(&it);
636 
637   if (it.IsFound() || !ShouldThrowReferenceError()) {
638     // Update inline cache and stub cache.
639     if (use_ic) UpdateCaches(&it);
640 
641     // Get the property.
642     Handle<Object> result;
643 
644     ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
645                                Object);
646     if (it.IsFound()) {
647       return result;
648     } else if (!ShouldThrowReferenceError()) {
649       LOG(isolate(), SuspectReadEvent(*name, *object));
650       return result;
651     }
652   }
653   return ReferenceError(name);
654 }
655 
Load(Handle<Name> name)656 MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
657   Handle<JSGlobalObject> global = isolate()->global_object();
658 
659   if (name->IsString()) {
660     // Look up in script context table.
661     Handle<String> str_name = Handle<String>::cast(name);
662     Handle<ScriptContextTable> script_contexts(
663         global->native_context()->script_context_table());
664 
665     ScriptContextTable::LookupResult lookup_result;
666     if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
667       Handle<Object> result =
668           FixedArray::get(*ScriptContextTable::GetContext(
669                               script_contexts, lookup_result.context_index),
670                           lookup_result.slot_index, isolate());
671       if (result->IsTheHole(isolate())) {
672         // Do not install stubs and stay pre-monomorphic for
673         // uninitialized accesses.
674         return ReferenceError(name);
675       }
676 
677       if (FLAG_use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
678         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub);
679         LoadScriptContextFieldStub stub(isolate(), &lookup_result);
680         PatchCache(name, stub.GetCode());
681         TRACE_IC("LoadGlobalIC", name);
682       }
683       return result;
684     }
685   }
686   return LoadIC::Load(global, name);
687 }
688 
AddOneReceiverMapIfMissing(MapHandleList * receiver_maps,Handle<Map> new_receiver_map)689 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
690                                        Handle<Map> new_receiver_map) {
691   DCHECK(!new_receiver_map.is_null());
692   for (int current = 0; current < receiver_maps->length(); ++current) {
693     if (!receiver_maps->at(current).is_null() &&
694         receiver_maps->at(current).is_identical_to(new_receiver_map)) {
695       return false;
696     }
697   }
698   receiver_maps->Add(new_receiver_map);
699   return true;
700 }
701 
UpdatePolymorphicIC(Handle<Name> name,Handle<Object> handler)702 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
703   DCHECK(IsHandler(*handler));
704   if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
705   Handle<Map> map = receiver_map();
706   MapHandleList maps;
707   List<Handle<Object>> handlers;
708 
709   TargetMaps(&maps);
710   int number_of_maps = maps.length();
711   int deprecated_maps = 0;
712   int handler_to_overwrite = -1;
713 
714   for (int i = 0; i < number_of_maps; i++) {
715     Handle<Map> current_map = maps.at(i);
716     if (current_map->is_deprecated()) {
717       // Filter out deprecated maps to ensure their instances get migrated.
718       ++deprecated_maps;
719     } else if (map.is_identical_to(current_map)) {
720       // If the receiver type is already in the polymorphic IC, this indicates
721       // there was a prototoype chain failure. In that case, just overwrite the
722       // handler.
723       handler_to_overwrite = i;
724     } else if (handler_to_overwrite == -1 &&
725                IsTransitionOfMonomorphicTarget(*current_map, *map)) {
726       handler_to_overwrite = i;
727     }
728   }
729 
730   int number_of_valid_maps =
731       number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
732 
733   if (number_of_valid_maps >= 4) return false;
734   if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
735     return false;
736   }
737   DCHECK(UseVector());
738   if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
739 
740   number_of_valid_maps++;
741   if (number_of_valid_maps > 1 && is_keyed()) return false;
742   if (number_of_valid_maps == 1) {
743     ConfigureVectorState(name, receiver_map(), handler);
744   } else {
745     if (handler_to_overwrite >= 0) {
746       handlers.Set(handler_to_overwrite, handler);
747       if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
748         maps.Set(handler_to_overwrite, map);
749       }
750     } else {
751       maps.Add(map);
752       handlers.Add(handler);
753     }
754 
755     ConfigureVectorState(name, &maps, &handlers);
756   }
757 
758   return true;
759 }
760 
UpdateMonomorphicIC(Handle<Object> handler,Handle<Name> name)761 void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
762   DCHECK(IsHandler(*handler));
763   ConfigureVectorState(name, receiver_map(), handler);
764 }
765 
766 
CopyICToMegamorphicCache(Handle<Name> name)767 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
768   MapHandleList maps;
769   List<Handle<Object>> handlers;
770   TargetMaps(&maps);
771   if (!nexus()->FindHandlers(&handlers, maps.length())) return;
772   for (int i = 0; i < maps.length(); i++) {
773     UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
774   }
775 }
776 
777 
IsTransitionOfMonomorphicTarget(Map * source_map,Map * target_map)778 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
779   if (source_map == NULL) return true;
780   if (target_map == NULL) return false;
781   ElementsKind target_elements_kind = target_map->elements_kind();
782   bool more_general_transition = IsMoreGeneralElementsKindTransition(
783       source_map->elements_kind(), target_elements_kind);
784   Map* transitioned_map = nullptr;
785   if (more_general_transition) {
786     MapHandleList map_list;
787     map_list.Add(handle(target_map));
788     transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list);
789   }
790   return transitioned_map == target_map;
791 }
792 
PatchCache(Handle<Name> name,Handle<Object> handler)793 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
794   DCHECK(IsHandler(*handler));
795   // Currently only LoadIC and KeyedLoadIC support non-code handlers.
796   DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC ||
797                                          kind() == Code::KEYED_LOAD_IC ||
798                                          kind() == Code::STORE_IC ||
799                                          kind() == Code::KEYED_STORE_IC);
800   switch (state()) {
801     case UNINITIALIZED:
802     case PREMONOMORPHIC:
803       UpdateMonomorphicIC(handler, name);
804       break;
805     case RECOMPUTE_HANDLER:
806     case MONOMORPHIC:
807       if (kind() == Code::LOAD_GLOBAL_IC) {
808         UpdateMonomorphicIC(handler, name);
809         break;
810       }
811     // Fall through.
812     case POLYMORPHIC:
813       if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
814         if (UpdatePolymorphicIC(name, handler)) break;
815         // For keyed stubs, we can't know whether old handlers were for the
816         // same key.
817         CopyICToMegamorphicCache(name);
818       }
819       DCHECK(UseVector());
820       ConfigureVectorState(MEGAMORPHIC, name);
821     // Fall through.
822     case MEGAMORPHIC:
823       UpdateMegamorphicCache(*receiver_map(), *name, *handler);
824       // Indicate that we've handled this case.
825       DCHECK(UseVector());
826       vector_set_ = true;
827       break;
828     case GENERIC:
829       UNREACHABLE();
830       break;
831   }
832 }
833 
ChooseMegamorphicStub(Isolate * isolate,ExtraICState extra_state)834 Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
835                                                  ExtraICState extra_state) {
836   DCHECK(!FLAG_tf_store_ic_stub);
837   LanguageMode mode = StoreICState::GetLanguageMode(extra_state);
838   return is_strict(mode)
839              ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
840              : isolate->builtins()->KeyedStoreIC_Megamorphic();
841 }
842 
SimpleFieldLoad(FieldIndex index)843 Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
844   if (FLAG_tf_load_ic_stub) {
845     TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
846     return LoadHandler::LoadField(isolate(), index);
847   }
848   TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
849   LoadFieldStub stub(isolate(), index);
850   return stub.GetCode();
851 }
852 
853 namespace {
854 
855 template <bool fill_array = true>
InitPrototypeChecks(Isolate * isolate,Handle<Map> receiver_map,Handle<JSObject> holder,Handle<Name> name,Handle<FixedArray> array,int first_index)856 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
857                         Handle<JSObject> holder, Handle<Name> name,
858                         Handle<FixedArray> array, int first_index) {
859   DCHECK(holder.is_null() || holder->HasFastProperties());
860 
861   // We don't encode the requirement to check access rights because we already
862   // passed the access check for current native context and the access
863   // can't be revoked.
864 
865   HandleScope scope(isolate);
866   int checks_count = 0;
867 
868   if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
869     // The validity cell check for primitive and global proxy receivers does
870     // not guarantee that certain native context ever had access to other
871     // native context. However, a handler created for one native context could
872     // be used in other native context through the megamorphic stub cache.
873     // So we record the original native context to which this handler
874     // corresponds.
875     if (fill_array) {
876       Handle<Context> native_context = isolate->native_context();
877       array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
878                  native_context->self_weak_cell());
879     }
880     checks_count++;
881 
882   } else if (receiver_map->IsJSGlobalObjectMap()) {
883     if (fill_array) {
884       Handle<JSGlobalObject> global = isolate->global_object();
885       Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
886           global, name, PropertyCellType::kInvalidated);
887       DCHECK(cell->value()->IsTheHole(isolate));
888       Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
889       array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell);
890     }
891     checks_count++;
892   }
893 
894   // Create/count entries for each global or dictionary prototype appeared in
895   // the prototype chain contains from receiver till holder.
896   PrototypeIterator::WhereToEnd end = name->IsPrivate()
897                                           ? PrototypeIterator::END_AT_NON_HIDDEN
898                                           : PrototypeIterator::END_AT_NULL;
899   for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
900        iter.Advance()) {
901     Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
902     if (holder.is_identical_to(current)) break;
903     Handle<Map> current_map(current->map(), isolate);
904 
905     if (current_map->IsJSGlobalObjectMap()) {
906       if (fill_array) {
907         Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current);
908         Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
909             global, name, PropertyCellType::kInvalidated);
910         DCHECK(cell->value()->IsTheHole(isolate));
911         Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
912         array->set(first_index + checks_count, *weak_cell);
913       }
914       checks_count++;
915 
916     } else if (current_map->is_dictionary_map()) {
917       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
918       if (fill_array) {
919         DCHECK_EQ(NameDictionary::kNotFound,
920                   current->property_dictionary()->FindEntry(name));
921         Handle<WeakCell> weak_cell =
922             Map::GetOrCreatePrototypeWeakCell(current, isolate);
923         array->set(first_index + checks_count, *weak_cell);
924       }
925       checks_count++;
926     }
927   }
928   return checks_count;
929 }
930 
931 // Returns 0 if the validity cell check is enough to ensure that the
932 // prototype chain from |receiver_map| till |holder| did not change.
933 // If the |holder| is an empty handle then the full prototype chain is
934 // checked.
935 // Returns -1 if the handler has to be compiled or the number of prototype
936 // checks otherwise.
GetPrototypeCheckCount(Isolate * isolate,Handle<Map> receiver_map,Handle<JSObject> holder,Handle<Name> name)937 int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
938                            Handle<JSObject> holder, Handle<Name> name) {
939   return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
940                                     Handle<FixedArray>(), 0);
941 }
942 
943 }  // namespace
944 
LoadFromPrototype(Handle<Map> receiver_map,Handle<JSObject> holder,Handle<Name> name,Handle<Object> smi_handler)945 Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
946                                          Handle<JSObject> holder,
947                                          Handle<Name> name,
948                                          Handle<Object> smi_handler) {
949   int checks_count =
950       GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
951   DCHECK_LE(0, checks_count);
952 
953   if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
954     DCHECK(!receiver_map->is_dictionary_map());
955     DCHECK_LE(1, checks_count);  // For native context.
956     smi_handler =
957         LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
958   } else if (receiver_map->is_dictionary_map() &&
959              !receiver_map->IsJSGlobalObjectMap()) {
960     smi_handler =
961         LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler);
962   }
963 
964   Handle<Cell> validity_cell =
965       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
966   DCHECK(!validity_cell.is_null());
967 
968   Handle<WeakCell> holder_cell =
969       Map::GetOrCreatePrototypeWeakCell(holder, isolate());
970 
971   if (checks_count == 0) {
972     return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
973                                            validity_cell);
974   }
975   Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray(
976       LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
977   handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
978   handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
979   handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
980   InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
981                       LoadHandler::kFirstPrototypeIndex);
982   return handler_array;
983 }
984 
LoadNonExistent(Handle<Map> receiver_map,Handle<Name> name)985 Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
986                                        Handle<Name> name) {
987   Handle<JSObject> holder;  // null handle
988   int checks_count =
989       GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
990   DCHECK_LE(0, checks_count);
991 
992   bool do_negative_lookup_on_receiver =
993       receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap();
994   Handle<Object> smi_handler =
995       LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver);
996 
997   if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
998     DCHECK(!receiver_map->is_dictionary_map());
999     DCHECK_LE(1, checks_count);  // For native context.
1000     smi_handler =
1001         LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
1002   }
1003 
1004   Handle<Object> validity_cell =
1005       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1006   if (validity_cell.is_null()) {
1007     DCHECK_EQ(0, checks_count);
1008     validity_cell = handle(Smi::FromInt(0), isolate());
1009   }
1010 
1011   Factory* factory = isolate()->factory();
1012   if (checks_count == 0) {
1013     return factory->NewTuple3(factory->null_value(), smi_handler,
1014                               validity_cell);
1015   }
1016   Handle<FixedArray> handler_array(factory->NewFixedArray(
1017       LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
1018   handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
1019   handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
1020   handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value());
1021   InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1022                       LoadHandler::kFirstPrototypeIndex);
1023   return handler_array;
1024 }
1025 
IsCompatibleReceiver(LookupIterator * lookup,Handle<Map> receiver_map)1026 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
1027   DCHECK(lookup->state() == LookupIterator::ACCESSOR);
1028   Isolate* isolate = lookup->isolate();
1029   Handle<Object> accessors = lookup->GetAccessors();
1030   if (accessors->IsAccessorInfo()) {
1031     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1032     if (info->getter() != NULL &&
1033         !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) {
1034       return false;
1035     }
1036   } else if (accessors->IsAccessorPair()) {
1037     Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1038                           isolate);
1039     if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
1040       return false;
1041     }
1042     Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1043     Handle<Object> receiver = lookup->GetReceiver();
1044     if (holder->HasFastProperties()) {
1045       if (getter->IsJSFunction()) {
1046         Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1047         if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() &&
1048             is_sloppy(function->shared()->language_mode())) {
1049           // Calling sloppy non-builtins with a value as the receiver
1050           // requires boxing.
1051           return false;
1052         }
1053       }
1054       CallOptimization call_optimization(getter);
1055       if (call_optimization.is_simple_api_call() &&
1056           !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) {
1057         return false;
1058       }
1059     }
1060   }
1061   return true;
1062 }
1063 
1064 
UpdateCaches(LookupIterator * lookup)1065 void LoadIC::UpdateCaches(LookupIterator* lookup) {
1066   if (state() == UNINITIALIZED && kind() != Code::LOAD_GLOBAL_IC) {
1067     // This is the first time we execute this inline cache. Set the target to
1068     // the pre monomorphic stub to delay setting the monomorphic state.
1069     TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
1070     ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
1071     TRACE_IC("LoadIC", lookup->name());
1072     return;
1073   }
1074 
1075   Handle<Object> code;
1076   if (lookup->state() == LookupIterator::JSPROXY ||
1077       lookup->state() == LookupIterator::ACCESS_CHECK) {
1078     code = slow_stub();
1079   } else if (!lookup->IsFound()) {
1080     if (kind() == Code::LOAD_IC) {
1081       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
1082       code = LoadNonExistent(receiver_map(), lookup->name());
1083     } else if (kind() == Code::LOAD_GLOBAL_IC) {
1084       code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
1085                                                               receiver_map());
1086       // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1087       if (code.is_null()) code = slow_stub();
1088     } else {
1089       code = slow_stub();
1090     }
1091   } else {
1092     if (kind() == Code::LOAD_GLOBAL_IC &&
1093         lookup->state() == LookupIterator::DATA &&
1094         lookup->GetHolder<Object>()->IsJSGlobalObject()) {
1095 #if DEBUG
1096       Handle<Object> holder = lookup->GetHolder<Object>();
1097       Handle<Object> receiver = lookup->GetReceiver();
1098       DCHECK_EQ(*receiver, *holder);
1099 #endif
1100       // Now update the cell in the feedback vector.
1101       LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
1102       nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1103       TRACE_IC("LoadGlobalIC", lookup->name());
1104       return;
1105     } else if (lookup->state() == LookupIterator::ACCESSOR) {
1106       if (!IsCompatibleReceiver(lookup, receiver_map())) {
1107         TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1108         code = slow_stub();
1109       }
1110     } else if (lookup->state() == LookupIterator::INTERCEPTOR) {
1111       if (kind() == Code::LOAD_GLOBAL_IC) {
1112         // The interceptor handler requires name but it is not passed explicitly
1113         // to LoadGlobalIC and the LoadGlobalIC dispatcher also does not load
1114         // it so we will just use slow stub.
1115         code = slow_stub();
1116       } else {
1117         // Perform a lookup behind the interceptor. Copy the LookupIterator
1118         // since the original iterator will be used to fetch the value.
1119         LookupIterator it = *lookup;
1120         it.Next();
1121         LookupForRead(&it);
1122         if (it.state() == LookupIterator::ACCESSOR &&
1123             !IsCompatibleReceiver(&it, receiver_map())) {
1124           TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1125           code = slow_stub();
1126         }
1127       }
1128     }
1129     if (code.is_null()) code = ComputeHandler(lookup);
1130   }
1131 
1132   PatchCache(lookup->name(), code);
1133   TRACE_IC("LoadIC", lookup->name());
1134 }
1135 
stub_cache()1136 StubCache* IC::stub_cache() {
1137   switch (kind()) {
1138     case Code::LOAD_IC:
1139     case Code::KEYED_LOAD_IC:
1140       return isolate()->load_stub_cache();
1141 
1142     case Code::STORE_IC:
1143     case Code::KEYED_STORE_IC:
1144       return isolate()->store_stub_cache();
1145 
1146     default:
1147       break;
1148   }
1149   UNREACHABLE();
1150   return nullptr;
1151 }
1152 
UpdateMegamorphicCache(Map * map,Name * name,Object * handler)1153 void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
1154   stub_cache()->Set(name, map, handler);
1155 }
1156 
TraceHandlerCacheHitStats(LookupIterator * lookup)1157 void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
1158   if (!FLAG_runtime_call_stats) return;
1159 
1160   if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
1161       kind() == Code::KEYED_LOAD_IC) {
1162     switch (lookup->state()) {
1163       case LookupIterator::ACCESS_CHECK:
1164         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck);
1165         break;
1166       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1167         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Exotic);
1168         break;
1169       case LookupIterator::INTERCEPTOR:
1170         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Interceptor);
1171         break;
1172       case LookupIterator::JSPROXY:
1173         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_JSProxy);
1174         break;
1175       case LookupIterator::NOT_FOUND:
1176         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_NonExistent);
1177         break;
1178       case LookupIterator::ACCESSOR:
1179         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
1180         break;
1181       case LookupIterator::DATA:
1182         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Data);
1183         break;
1184       case LookupIterator::TRANSITION:
1185         TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition);
1186         break;
1187     }
1188   } else if (kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC) {
1189     switch (lookup->state()) {
1190       case LookupIterator::ACCESS_CHECK:
1191         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck);
1192         break;
1193       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1194         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Exotic);
1195         break;
1196       case LookupIterator::INTERCEPTOR:
1197         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Interceptor);
1198         break;
1199       case LookupIterator::JSPROXY:
1200         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_JSProxy);
1201         break;
1202       case LookupIterator::NOT_FOUND:
1203         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_NonExistent);
1204         break;
1205       case LookupIterator::ACCESSOR:
1206         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
1207         break;
1208       case LookupIterator::DATA:
1209         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Data);
1210         break;
1211       case LookupIterator::TRANSITION:
1212         TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Transition);
1213         break;
1214     }
1215   } else {
1216     TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
1217   }
1218 }
1219 
ComputeHandler(LookupIterator * lookup,Handle<Object> value)1220 Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
1221                                   Handle<Object> value) {
1222   // Try to find a globally shared handler stub.
1223   Handle<Object> shared_handler = GetMapIndependentHandler(lookup);
1224   if (!shared_handler.is_null()) {
1225     DCHECK(IC::IsHandler(*shared_handler));
1226     return shared_handler;
1227   }
1228 
1229   // Otherwise check the map's handler cache for a map-specific handler, and
1230   // compile one if the cache comes up empty.
1231   bool receiver_is_holder =
1232       lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1233   CacheHolderFlag flag;
1234   Handle<Map> stub_holder_map;
1235   if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
1236       kind() == Code::KEYED_LOAD_IC) {
1237     stub_holder_map = IC::GetHandlerCacheHolder(
1238         receiver_map(), receiver_is_holder, isolate(), &flag);
1239   } else {
1240     DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
1241     // Store handlers cannot be cached on prototypes.
1242     flag = kCacheOnReceiver;
1243     stub_holder_map = receiver_map();
1244   }
1245 
1246   Handle<Object> handler = PropertyHandlerCompiler::Find(
1247       lookup->name(), stub_holder_map, kind(), flag);
1248   // Use the cached value if it exists, and if it is different from the
1249   // handler that just missed.
1250   if (!handler.is_null()) {
1251     Handle<Object> current_handler;
1252     if (maybe_handler_.ToHandle(&current_handler)) {
1253       if (!current_handler.is_identical_to(handler)) {
1254         TraceHandlerCacheHitStats(lookup);
1255         return handler;
1256       }
1257     } else {
1258       // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1259       // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1260       // cache (which just missed) is different from the cached handler.
1261       if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1262         Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1263         Object* megamorphic_cached_handler =
1264             stub_cache()->Get(*lookup->name(), map);
1265         if (megamorphic_cached_handler != *handler) {
1266           TraceHandlerCacheHitStats(lookup);
1267           return handler;
1268         }
1269       } else {
1270         TraceHandlerCacheHitStats(lookup);
1271         return handler;
1272       }
1273     }
1274   }
1275 
1276   handler = CompileHandler(lookup, value, flag);
1277   DCHECK(IC::IsHandler(*handler));
1278   if (handler->IsCode()) {
1279     Handle<Code> code = Handle<Code>::cast(handler);
1280     DCHECK_EQ(Code::ExtractCacheHolderFromFlags(code->flags()), flag);
1281     Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1282   }
1283   return handler;
1284 }
1285 
GetMapIndependentHandler(LookupIterator * lookup)1286 Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
1287   Handle<Object> receiver = lookup->GetReceiver();
1288   if (receiver->IsString() &&
1289       Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1290     FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1291     return SimpleFieldLoad(index);
1292   }
1293 
1294   if (receiver->IsStringWrapper() &&
1295       Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1296     TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
1297     StringLengthStub string_length_stub(isolate());
1298     return string_length_stub.GetCode();
1299   }
1300 
1301   // Use specialized code for getting prototype of functions.
1302   if (receiver->IsJSFunction() &&
1303       Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1304       receiver->IsConstructor() &&
1305       !Handle<JSFunction>::cast(receiver)
1306            ->map()
1307            ->has_non_instance_prototype()) {
1308     Handle<Code> stub;
1309     TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
1310     FunctionPrototypeStub function_prototype_stub(isolate());
1311     return function_prototype_stub.GetCode();
1312   }
1313 
1314   Handle<Map> map = receiver_map();
1315   Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1316   bool receiver_is_holder = receiver.is_identical_to(holder);
1317   switch (lookup->state()) {
1318     case LookupIterator::INTERCEPTOR:
1319       break;  // Custom-compiled handler.
1320 
1321     case LookupIterator::ACCESSOR: {
1322       // Use simple field loads for some well-known callback properties.
1323       // The method will only return true for absolute truths based on the
1324       // receiver maps.
1325       int object_offset;
1326       if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1327                                              &object_offset)) {
1328         FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1329         return SimpleFieldLoad(index);
1330       }
1331 
1332       if (IsCompatibleReceiver(lookup, map)) {
1333         Handle<Object> accessors = lookup->GetAccessors();
1334         if (accessors->IsAccessorPair()) {
1335           if (!holder->HasFastProperties()) {
1336             TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1337             return slow_stub();
1338           }
1339           // When debugging we need to go the slow path to flood the accessor.
1340           if (GetSharedFunctionInfo()->HasDebugInfo()) {
1341             TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1342             return slow_stub();
1343           }
1344           break;  // Custom-compiled handler.
1345         } else if (accessors->IsAccessorInfo()) {
1346           Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1347           if (v8::ToCData<Address>(info->getter()) == nullptr) {
1348             TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1349             return slow_stub();
1350           }
1351           // Ruled out by IsCompatibleReceiver() above.
1352           DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
1353           if (!holder->HasFastProperties() ||
1354               (info->is_sloppy() && !receiver->IsJSReceiver())) {
1355             DCHECK(!holder->HasFastProperties() || !receiver_is_holder);
1356             TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1357             return slow_stub();
1358           }
1359           if (FLAG_tf_load_ic_stub) {
1360             Handle<Object> smi_handler = LoadHandler::LoadApiGetter(
1361                 isolate(), lookup->GetAccessorIndex());
1362             if (receiver_is_holder) {
1363               TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
1364               return smi_handler;
1365             }
1366             if (kind() != Code::LOAD_GLOBAL_IC) {
1367               TRACE_HANDLER_STATS(isolate(),
1368                                   LoadIC_LoadApiGetterFromPrototypeDH);
1369               return LoadFromPrototype(map, holder, lookup->name(),
1370                                        smi_handler);
1371             }
1372           } else {
1373             if (receiver_is_holder) {
1374               TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub);
1375               int index = lookup->GetAccessorIndex();
1376               LoadApiGetterStub stub(isolate(), true, index);
1377               return stub.GetCode();
1378             }
1379           }
1380           break;  // Custom-compiled handler.
1381         }
1382       }
1383       TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1384       return slow_stub();
1385     }
1386 
1387     case LookupIterator::DATA: {
1388       if (lookup->is_dictionary_holder()) {
1389         if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) {
1390           TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1391           return slow_stub();
1392         }
1393         if (holder->IsJSGlobalObject()) {
1394           break;  // Custom-compiled handler.
1395         }
1396         // There is only one shared stub for loading normalized
1397         // properties. It does not traverse the prototype chain, so the
1398         // property must be found in the object for the stub to be
1399         // applicable.
1400         if (!receiver_is_holder) {
1401           TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1402           return slow_stub();
1403         }
1404         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
1405         return isolate()->builtins()->LoadIC_Normal();
1406       }
1407 
1408       // -------------- Fields --------------
1409       if (lookup->property_details().type() == DATA) {
1410         FieldIndex field = lookup->GetFieldIndex();
1411         Handle<Object> smi_handler = SimpleFieldLoad(field);
1412         if (receiver_is_holder) {
1413           return smi_handler;
1414         }
1415         if (FLAG_tf_load_ic_stub && kind() != Code::LOAD_GLOBAL_IC) {
1416           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
1417           return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1418         }
1419         break;  // Custom-compiled handler.
1420       }
1421 
1422       // -------------- Constant properties --------------
1423       DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1424       if (FLAG_tf_load_ic_stub) {
1425         Handle<Object> smi_handler =
1426             LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
1427         if (receiver_is_holder) {
1428           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
1429           return smi_handler;
1430         }
1431         if (kind() != Code::LOAD_GLOBAL_IC) {
1432           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
1433           return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1434         }
1435       } else {
1436         if (receiver_is_holder) {
1437           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub);
1438           LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1439           return stub.GetCode();
1440         }
1441       }
1442       break;  // Custom-compiled handler.
1443     }
1444 
1445     case LookupIterator::INTEGER_INDEXED_EXOTIC:
1446       TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1447       return slow_stub();
1448     case LookupIterator::ACCESS_CHECK:
1449     case LookupIterator::JSPROXY:
1450     case LookupIterator::NOT_FOUND:
1451     case LookupIterator::TRANSITION:
1452       UNREACHABLE();
1453   }
1454 
1455   return Handle<Code>::null();
1456 }
1457 
CompileHandler(LookupIterator * lookup,Handle<Object> unused,CacheHolderFlag cache_holder)1458 Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
1459                                       Handle<Object> unused,
1460                                       CacheHolderFlag cache_holder) {
1461   Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1462 #ifdef DEBUG
1463   // Only used by DCHECKs below.
1464   Handle<Object> receiver = lookup->GetReceiver();
1465   bool receiver_is_holder = receiver.is_identical_to(holder);
1466 #endif
1467   // Non-map-specific handler stubs have already been selected.
1468   DCHECK(!receiver->IsString() ||
1469          !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
1470   DCHECK(!receiver->IsStringWrapper() ||
1471          !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
1472 
1473   DCHECK(!(
1474       receiver->IsJSFunction() &&
1475       Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1476       receiver->IsConstructor() &&
1477       !Handle<JSFunction>::cast(receiver)
1478            ->map()
1479            ->has_non_instance_prototype()));
1480 
1481   Handle<Map> map = receiver_map();
1482   switch (lookup->state()) {
1483     case LookupIterator::INTERCEPTOR: {
1484       DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
1485       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
1486       NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1487       // Perform a lookup behind the interceptor. Copy the LookupIterator since
1488       // the original iterator will be used to fetch the value.
1489       LookupIterator it = *lookup;
1490       it.Next();
1491       LookupForRead(&it);
1492       return compiler.CompileLoadInterceptor(&it);
1493     }
1494 
1495     case LookupIterator::ACCESSOR: {
1496 #ifdef DEBUG
1497       int object_offset;
1498       DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1499                                                  &object_offset));
1500 #endif
1501 
1502       DCHECK(IsCompatibleReceiver(lookup, map));
1503       Handle<Object> accessors = lookup->GetAccessors();
1504       if (accessors->IsAccessorPair()) {
1505         if (lookup->TryLookupCachedProperty()) {
1506           DCHECK_EQ(LookupIterator::DATA, lookup->state());
1507           return ComputeHandler(lookup);
1508         }
1509         DCHECK(holder->HasFastProperties());
1510         DCHECK(!GetSharedFunctionInfo()->HasDebugInfo());
1511         Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1512                               isolate());
1513         CallOptimization call_optimization(getter);
1514         NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1515         if (call_optimization.is_simple_api_call()) {
1516           TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
1517           int index = lookup->GetAccessorIndex();
1518           Handle<Code> code = compiler.CompileLoadCallback(
1519               lookup->name(), call_optimization, index, slow_stub());
1520           return code;
1521         }
1522         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
1523         int expected_arguments = Handle<JSFunction>::cast(getter)
1524                                      ->shared()
1525                                      ->internal_formal_parameter_count();
1526         return compiler.CompileLoadViaGetter(
1527             lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1528       } else {
1529         DCHECK(accessors->IsAccessorInfo());
1530         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1531         DCHECK(v8::ToCData<Address>(info->getter()) != nullptr);
1532         DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
1533         DCHECK(holder->HasFastProperties());
1534         DCHECK(!receiver_is_holder);
1535         DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
1536         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
1537         NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1538         Handle<Code> code =
1539             compiler.CompileLoadCallback(lookup->name(), info, slow_stub());
1540         return code;
1541       }
1542       UNREACHABLE();
1543     }
1544 
1545     case LookupIterator::DATA: {
1546       if (lookup->is_dictionary_holder()) {
1547         DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
1548         DCHECK(holder->IsJSGlobalObject());
1549         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
1550         NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1551         Handle<PropertyCell> cell = lookup->GetPropertyCell();
1552         Handle<Code> code = compiler.CompileLoadGlobal(
1553             cell, lookup->name(), lookup->IsConfigurable());
1554         return code;
1555       }
1556 
1557       // -------------- Fields --------------
1558       if (lookup->property_details().type() == DATA) {
1559         FieldIndex field = lookup->GetFieldIndex();
1560         DCHECK(!receiver_is_holder);
1561         TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
1562         NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1563         return compiler.CompileLoadField(lookup->name(), field);
1564       }
1565 
1566       // -------------- Constant properties --------------
1567       DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1568       DCHECK(!receiver_is_holder);
1569       TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant);
1570       NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1571       return compiler.CompileLoadConstant(lookup->name(),
1572                                           lookup->GetConstantIndex());
1573     }
1574 
1575     case LookupIterator::INTEGER_INDEXED_EXOTIC:
1576     case LookupIterator::ACCESS_CHECK:
1577     case LookupIterator::JSPROXY:
1578     case LookupIterator::NOT_FOUND:
1579     case LookupIterator::TRANSITION:
1580       UNREACHABLE();
1581   }
1582   UNREACHABLE();
1583   return slow_stub();
1584 }
1585 
1586 
TryConvertKey(Handle<Object> key,Isolate * isolate)1587 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1588   // This helper implements a few common fast cases for converting
1589   // non-smi keys of keyed loads/stores to a smi or a string.
1590   if (key->IsHeapNumber()) {
1591     double value = Handle<HeapNumber>::cast(key)->value();
1592     if (std::isnan(value)) {
1593       key = isolate->factory()->nan_string();
1594     } else {
1595       int int_value = FastD2I(value);
1596       if (value == int_value && Smi::IsValid(int_value)) {
1597         key = handle(Smi::FromInt(int_value), isolate);
1598       }
1599     }
1600   } else if (key->IsUndefined(isolate)) {
1601     key = isolate->factory()->undefined_string();
1602   }
1603   return key;
1604 }
1605 
UpdateLoadElement(Handle<HeapObject> receiver)1606 void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
1607   Handle<Map> receiver_map(receiver->map(), isolate());
1608   DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
1609          receiver_map->instance_type() != JS_PROXY_TYPE);  // Checked by caller.
1610   MapHandleList target_receiver_maps;
1611   TargetMaps(&target_receiver_maps);
1612 
1613   if (target_receiver_maps.length() == 0) {
1614     Handle<Object> handler =
1615         ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
1616     return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1617   }
1618 
1619   for (int i = 0; i < target_receiver_maps.length(); i++) {
1620     Handle<Map> map = target_receiver_maps.at(i);
1621     if (map.is_null()) continue;
1622     if (map->instance_type() == JS_VALUE_TYPE) {
1623       TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSValue");
1624       return;
1625     }
1626     if (map->instance_type() == JS_PROXY_TYPE) {
1627       TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSProxy");
1628       return;
1629     }
1630   }
1631 
1632   // The first time a receiver is seen that is a transitioned version of the
1633   // previous monomorphic receiver type, assume the new ElementsKind is the
1634   // monomorphic type. This benefits global arrays that only transition
1635   // once, and all call sites accessing them are faster if they remain
1636   // monomorphic. If this optimistic assumption is not true, the IC will
1637   // miss again and it will become polymorphic and support both the
1638   // untransitioned and transitioned maps.
1639   if (state() == MONOMORPHIC && !receiver->IsString() &&
1640       IsMoreGeneralElementsKindTransition(
1641           target_receiver_maps.at(0)->elements_kind(),
1642           Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1643     Handle<Object> handler =
1644         ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
1645     return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1646   }
1647 
1648   DCHECK(state() != GENERIC);
1649 
1650   // Determine the list of receiver maps that this call site has seen,
1651   // adding the map that was just encountered.
1652   if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1653     // If the miss wasn't due to an unseen map, a polymorphic stub
1654     // won't help, use the generic stub.
1655     TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
1656     return;
1657   }
1658 
1659   // If the maximum number of receiver maps has been exceeded, use the generic
1660   // version of the IC.
1661   if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1662     TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
1663     return;
1664   }
1665 
1666   List<Handle<Object>> handlers(target_receiver_maps.length());
1667   ElementHandlerCompiler compiler(isolate());
1668   compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1669   ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
1670 }
1671 
1672 
Load(Handle<Object> object,Handle<Object> key)1673 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1674                                       Handle<Object> key) {
1675   if (MigrateDeprecated(object)) {
1676     Handle<Object> result;
1677     ASSIGN_RETURN_ON_EXCEPTION(
1678         isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1679         Object);
1680     return result;
1681   }
1682 
1683   Handle<Object> load_handle;
1684 
1685   // Check for non-string values that can be converted into an
1686   // internalized string directly or is representable as a smi.
1687   key = TryConvertKey(key, isolate());
1688 
1689   uint32_t index;
1690   if ((key->IsInternalizedString() &&
1691        !String::cast(*key)->AsArrayIndex(&index)) ||
1692       key->IsSymbol()) {
1693     ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1694                                LoadIC::Load(object, Handle<Name>::cast(key)),
1695                                Object);
1696   } else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1697              !object->IsJSValue()) {
1698     if ((object->IsJSObject() && key->IsSmi()) ||
1699         (object->IsString() && key->IsNumber())) {
1700       UpdateLoadElement(Handle<HeapObject>::cast(object));
1701       if (is_vector_set()) {
1702         TRACE_IC("LoadIC", key);
1703       }
1704     }
1705   }
1706 
1707   if (!is_vector_set()) {
1708     ConfigureVectorState(MEGAMORPHIC, key);
1709     TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1710     TRACE_IC("LoadIC", key);
1711   }
1712 
1713   if (!load_handle.is_null()) return load_handle;
1714 
1715   Handle<Object> result;
1716   ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1717                              Runtime::GetObjectProperty(isolate(), object, key),
1718                              Object);
1719   return result;
1720 }
1721 
1722 
LookupForWrite(LookupIterator * it,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1723 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1724                              JSReceiver::StoreFromKeyed store_mode) {
1725   // Disable ICs for non-JSObjects for now.
1726   Handle<Object> object = it->GetReceiver();
1727   if (!object->IsJSObject()) return false;
1728   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1729   DCHECK(!receiver->map()->is_deprecated());
1730 
1731   for (; it->IsFound(); it->Next()) {
1732     switch (it->state()) {
1733       case LookupIterator::NOT_FOUND:
1734       case LookupIterator::TRANSITION:
1735         UNREACHABLE();
1736       case LookupIterator::JSPROXY:
1737         return false;
1738       case LookupIterator::INTERCEPTOR: {
1739         Handle<JSObject> holder = it->GetHolder<JSObject>();
1740         InterceptorInfo* info = holder->GetNamedInterceptor();
1741         if (it->HolderIsReceiverOrHiddenPrototype()) {
1742           return !info->non_masking() && receiver.is_identical_to(holder) &&
1743                  !info->setter()->IsUndefined(it->isolate());
1744         } else if (!info->getter()->IsUndefined(it->isolate()) ||
1745                    !info->query()->IsUndefined(it->isolate())) {
1746           return false;
1747         }
1748         break;
1749       }
1750       case LookupIterator::ACCESS_CHECK:
1751         if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1752         break;
1753       case LookupIterator::ACCESSOR:
1754         return !it->IsReadOnly();
1755       case LookupIterator::INTEGER_INDEXED_EXOTIC:
1756         return false;
1757       case LookupIterator::DATA: {
1758         if (it->IsReadOnly()) return false;
1759         Handle<JSObject> holder = it->GetHolder<JSObject>();
1760         if (receiver.is_identical_to(holder)) {
1761           it->PrepareForDataProperty(value);
1762           // The previous receiver map might just have been deprecated,
1763           // so reload it.
1764           update_receiver_map(receiver);
1765           return true;
1766         }
1767 
1768         // Receiver != holder.
1769         if (receiver->IsJSGlobalProxy()) {
1770           PrototypeIterator iter(it->isolate(), receiver);
1771           return it->GetHolder<Object>().is_identical_to(
1772               PrototypeIterator::GetCurrent(iter));
1773         }
1774 
1775         if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1776 
1777         if (it->ExtendingNonExtensible(receiver)) return false;
1778         it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1779         return it->IsCacheableTransition();
1780       }
1781     }
1782   }
1783 
1784   receiver = it->GetStoreTarget();
1785   if (it->ExtendingNonExtensible(receiver)) return false;
1786   it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1787   return it->IsCacheableTransition();
1788 }
1789 
1790 
Store(Handle<Object> object,Handle<Name> name,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1791 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1792                                    Handle<Object> value,
1793                                    JSReceiver::StoreFromKeyed store_mode) {
1794   if (object->IsJSGlobalObject() && name->IsString()) {
1795     // Look up in script context table.
1796     Handle<String> str_name = Handle<String>::cast(name);
1797     Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
1798     Handle<ScriptContextTable> script_contexts(
1799         global->native_context()->script_context_table());
1800 
1801     ScriptContextTable::LookupResult lookup_result;
1802     if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1803       Handle<Context> script_context = ScriptContextTable::GetContext(
1804           script_contexts, lookup_result.context_index);
1805       if (lookup_result.mode == CONST) {
1806         return TypeError(MessageTemplate::kConstAssign, object, name);
1807       }
1808 
1809       Handle<Object> previous_value =
1810           FixedArray::get(*script_context, lookup_result.slot_index, isolate());
1811 
1812       if (previous_value->IsTheHole(isolate())) {
1813         // Do not install stubs and stay pre-monomorphic for
1814         // uninitialized accesses.
1815         return ReferenceError(name);
1816       }
1817 
1818       if (FLAG_use_ic &&
1819           StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1820         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
1821         StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1822         PatchCache(name, stub.GetCode());
1823       }
1824 
1825       script_context->set(lookup_result.slot_index, *value);
1826       return value;
1827     }
1828   }
1829 
1830   // TODO(verwaest): Let SetProperty do the migration, since storing a property
1831   // might deprecate the current map again, if value does not fit.
1832   if (MigrateDeprecated(object) || object->IsJSProxy()) {
1833     Handle<Object> result;
1834     ASSIGN_RETURN_ON_EXCEPTION(
1835         isolate(), result,
1836         Object::SetProperty(object, name, value, language_mode()), Object);
1837     return result;
1838   }
1839 
1840   // If the object is undefined or null it's illegal to try to set any
1841   // properties on it; throw a TypeError in that case.
1842   if (object->IsUndefined(isolate()) || object->IsNull(isolate())) {
1843     return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1844   }
1845 
1846   if (state() != UNINITIALIZED) {
1847     JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1848   }
1849   LookupIterator it(object, name);
1850   if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1851 
1852   MAYBE_RETURN_NULL(
1853       Object::SetProperty(&it, value, language_mode(), store_mode));
1854   return value;
1855 }
1856 
UpdateCaches(LookupIterator * lookup,Handle<Object> value,JSReceiver::StoreFromKeyed store_mode)1857 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1858                            JSReceiver::StoreFromKeyed store_mode) {
1859   if (state() == UNINITIALIZED) {
1860     // This is the first time we execute this inline cache. Set the target to
1861     // the pre monomorphic stub to delay setting the monomorphic state.
1862     TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1863     ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
1864     TRACE_IC("StoreIC", lookup->name());
1865     return;
1866   }
1867 
1868   bool use_ic = LookupForWrite(lookup, value, store_mode);
1869   if (!use_ic) {
1870     TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1871   }
1872   Handle<Object> handler = use_ic ? ComputeHandler(lookup, value)
1873                                   : Handle<Object>::cast(slow_stub());
1874 
1875   PatchCache(lookup->name(), handler);
1876   TRACE_IC("StoreIC", lookup->name());
1877 }
1878 
StoreTransition(Handle<Map> receiver_map,Handle<JSObject> holder,Handle<Map> transition,Handle<Name> name)1879 Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
1880                                         Handle<JSObject> holder,
1881                                         Handle<Map> transition,
1882                                         Handle<Name> name) {
1883   int descriptor = transition->LastAdded();
1884   Handle<DescriptorArray> descriptors(transition->instance_descriptors());
1885   PropertyDetails details = descriptors->GetDetails(descriptor);
1886   Representation representation = details.representation();
1887   DCHECK(!representation.IsNone());
1888 
1889   // Declarative handlers don't support access checks.
1890   DCHECK(!transition->is_access_check_needed());
1891 
1892   Handle<Object> smi_handler;
1893   if (details.type() == DATA_CONSTANT) {
1894     smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
1895 
1896   } else {
1897     DCHECK_EQ(DATA, details.type());
1898     bool extend_storage =
1899         Map::cast(transition->GetBackPointer())->unused_property_fields() == 0;
1900 
1901     FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
1902     smi_handler = StoreHandler::TransitionToField(
1903         isolate(), descriptor, index, representation, extend_storage);
1904   }
1905   // |holder| is either a receiver if the property is non-existent or
1906   // one of the prototypes.
1907   DCHECK(!holder.is_null());
1908   bool is_nonexistent = holder->map() == transition->GetBackPointer();
1909   if (is_nonexistent) holder = Handle<JSObject>::null();
1910 
1911   int checks_count =
1912       GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
1913   DCHECK_LE(0, checks_count);
1914   DCHECK(!receiver_map->IsJSGlobalObjectMap());
1915 
1916   Handle<Object> validity_cell =
1917       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1918   if (validity_cell.is_null()) {
1919     DCHECK_EQ(0, checks_count);
1920     validity_cell = handle(Smi::FromInt(0), isolate());
1921   }
1922 
1923   Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
1924 
1925   Factory* factory = isolate()->factory();
1926   if (checks_count == 0) {
1927     return factory->NewTuple3(transition_cell, smi_handler, validity_cell);
1928   }
1929   Handle<FixedArray> handler_array(factory->NewFixedArray(
1930       StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
1931   handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
1932   handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
1933   handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
1934   InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1935                       StoreHandler::kFirstPrototypeIndex);
1936   return handler_array;
1937 }
1938 
PropertyCellStoreHandler(Isolate * isolate,Handle<JSObject> receiver,Handle<JSGlobalObject> holder,Handle<Name> name,Handle<PropertyCell> cell,PropertyCellType type)1939 static Handle<Code> PropertyCellStoreHandler(
1940     Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
1941     Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1942   auto constant_type = Nothing<PropertyCellConstantType>();
1943   if (type == PropertyCellType::kConstantType) {
1944     constant_type = Just(cell->GetConstantType());
1945   }
1946   StoreGlobalStub stub(isolate, type, constant_type,
1947                        receiver->IsJSGlobalProxy());
1948   auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1949   // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1950   HeapObject::UpdateMapCodeCache(receiver, name, code);
1951   return code;
1952 }
1953 
GetMapIndependentHandler(LookupIterator * lookup)1954 Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
1955   DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1956 
1957   // This is currently guaranteed by checks in StoreIC::Store.
1958   Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1959   Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1960   DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1961 
1962   switch (lookup->state()) {
1963     case LookupIterator::TRANSITION: {
1964       auto store_target = lookup->GetStoreTarget();
1965       if (store_target->IsJSGlobalObject()) {
1966         break;  // Custom-compiled handler.
1967       }
1968       // Currently not handled by CompileStoreTransition.
1969       if (!holder->HasFastProperties()) {
1970         TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1971         TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1972         return slow_stub();
1973       }
1974       DCHECK(lookup->IsCacheableTransition());
1975       if (FLAG_tf_store_ic_stub) {
1976         Handle<Map> transition = lookup->transition_map();
1977         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
1978         return StoreTransition(receiver_map(), holder, transition,
1979                                lookup->name());
1980       }
1981       break;  // Custom-compiled handler.
1982     }
1983 
1984     case LookupIterator::INTERCEPTOR: {
1985       DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1986       TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1987       StoreInterceptorStub stub(isolate());
1988       return stub.GetCode();
1989     }
1990 
1991     case LookupIterator::ACCESSOR: {
1992       if (!holder->HasFastProperties()) {
1993         TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1994         TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1995         return slow_stub();
1996       }
1997       Handle<Object> accessors = lookup->GetAccessors();
1998       if (accessors->IsAccessorInfo()) {
1999         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
2000         if (v8::ToCData<Address>(info->setter()) == nullptr) {
2001           TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == nullptr");
2002           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2003           return slow_stub();
2004         }
2005         if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
2006             !lookup->HolderIsReceiverOrHiddenPrototype()) {
2007           TRACE_GENERIC_IC(isolate(), "StoreIC",
2008                            "special data property in prototype chain");
2009           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2010           return slow_stub();
2011         }
2012         if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
2013                                                    receiver_map())) {
2014           TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
2015           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2016           return slow_stub();
2017         }
2018         if (info->is_sloppy() && !receiver->IsJSReceiver()) {
2019           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2020           return slow_stub();
2021         }
2022         break;  // Custom-compiled handler.
2023       } else if (accessors->IsAccessorPair()) {
2024         Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
2025                               isolate());
2026         if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
2027           TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
2028           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2029           return slow_stub();
2030         }
2031         CallOptimization call_optimization(setter);
2032         if (call_optimization.is_simple_api_call()) {
2033           if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
2034             break;  // Custom-compiled handler.
2035           }
2036           TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver");
2037           TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2038           return slow_stub();
2039         }
2040         break;  // Custom-compiled handler.
2041       }
2042       TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2043       return slow_stub();
2044     }
2045 
2046     case LookupIterator::DATA: {
2047       if (lookup->is_dictionary_holder()) {
2048         if (holder->IsJSGlobalObject()) {
2049           break;  // Custom-compiled handler.
2050         }
2051         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
2052         DCHECK(holder.is_identical_to(receiver));
2053         return isolate()->builtins()->StoreIC_Normal();
2054       }
2055 
2056       // -------------- Fields --------------
2057       if (lookup->property_details().type() == DATA) {
2058         if (FLAG_tf_store_ic_stub) {
2059           TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
2060           int descriptor = lookup->GetFieldDescriptorIndex();
2061           FieldIndex index = lookup->GetFieldIndex();
2062           return StoreHandler::StoreField(isolate(), descriptor, index,
2063                                           lookup->representation());
2064         } else {
2065           bool use_stub = true;
2066           if (lookup->representation().IsHeapObject()) {
2067             // Only use a generic stub if no types need to be tracked.
2068             Handle<FieldType> field_type = lookup->GetFieldType();
2069             use_stub = !field_type->IsClass();
2070           }
2071           if (use_stub) {
2072             TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldStub);
2073             StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
2074                                 lookup->representation());
2075             return stub.GetCode();
2076           }
2077         }
2078         break;  // Custom-compiled handler.
2079       }
2080 
2081       // -------------- Constant properties --------------
2082       DCHECK(lookup->property_details().type() == DATA_CONSTANT);
2083       TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
2084       TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2085       return slow_stub();
2086     }
2087 
2088     case LookupIterator::INTEGER_INDEXED_EXOTIC:
2089     case LookupIterator::ACCESS_CHECK:
2090     case LookupIterator::JSPROXY:
2091     case LookupIterator::NOT_FOUND:
2092       UNREACHABLE();
2093   }
2094   return Handle<Code>::null();
2095 }
2096 
CompileHandler(LookupIterator * lookup,Handle<Object> value,CacheHolderFlag cache_holder)2097 Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
2098                                        Handle<Object> value,
2099                                        CacheHolderFlag cache_holder) {
2100   DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
2101 
2102   // This is currently guaranteed by checks in StoreIC::Store.
2103   Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
2104   Handle<JSObject> holder = lookup->GetHolder<JSObject>();
2105   DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
2106 
2107   switch (lookup->state()) {
2108     case LookupIterator::TRANSITION: {
2109       auto store_target = lookup->GetStoreTarget();
2110       if (store_target->IsJSGlobalObject()) {
2111         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
2112         Handle<PropertyCell> cell = lookup->transition_cell();
2113         cell->set_value(*value);
2114         Handle<Code> code = PropertyCellStoreHandler(
2115             isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
2116             lookup->name(), cell, PropertyCellType::kConstant);
2117         cell->set_value(isolate()->heap()->the_hole_value());
2118         return code;
2119       }
2120       DCHECK(!FLAG_tf_store_ic_stub);
2121       Handle<Map> transition = lookup->transition_map();
2122       // Currently not handled by CompileStoreTransition.
2123       DCHECK(holder->HasFastProperties());
2124 
2125       DCHECK(lookup->IsCacheableTransition());
2126       TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
2127       NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
2128       return compiler.CompileStoreTransition(transition, lookup->name());
2129     }
2130 
2131     case LookupIterator::INTERCEPTOR:
2132       UNREACHABLE();
2133 
2134     case LookupIterator::ACCESSOR: {
2135       DCHECK(holder->HasFastProperties());
2136       Handle<Object> accessors = lookup->GetAccessors();
2137       if (accessors->IsAccessorInfo()) {
2138         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
2139         DCHECK(v8::ToCData<Address>(info->setter()) != 0);
2140         DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
2141                lookup->HolderIsReceiverOrHiddenPrototype());
2142         DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
2143                                                      receiver_map()));
2144         DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
2145         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
2146         NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
2147         Handle<Code> code = compiler.CompileStoreCallback(
2148             receiver, lookup->name(), info, language_mode());
2149         return code;
2150       } else {
2151         DCHECK(accessors->IsAccessorPair());
2152         Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
2153                               isolate());
2154         DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
2155         CallOptimization call_optimization(setter);
2156         NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
2157         if (call_optimization.is_simple_api_call()) {
2158           DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
2159           TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
2160           Handle<Code> code = compiler.CompileStoreCallback(
2161               receiver, lookup->name(), call_optimization,
2162               lookup->GetAccessorIndex(), slow_stub());
2163           return code;
2164         }
2165         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
2166         int expected_arguments = JSFunction::cast(*setter)
2167                                      ->shared()
2168                                      ->internal_formal_parameter_count();
2169         return compiler.CompileStoreViaSetter(receiver, lookup->name(),
2170                                               lookup->GetAccessorIndex(),
2171                                               expected_arguments);
2172       }
2173     }
2174 
2175     case LookupIterator::DATA: {
2176       if (lookup->is_dictionary_holder()) {
2177         DCHECK(holder->IsJSGlobalObject());
2178         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
2179         DCHECK(holder.is_identical_to(receiver) ||
2180                receiver->map()->prototype() == *holder);
2181         auto cell = lookup->GetPropertyCell();
2182         auto updated_type =
2183             PropertyCell::UpdatedType(cell, value, lookup->property_details());
2184         auto code = PropertyCellStoreHandler(
2185             isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
2186             lookup->name(), cell, updated_type);
2187         return code;
2188       }
2189 
2190       // -------------- Fields --------------
2191       if (lookup->property_details().type() == DATA) {
2192         DCHECK(!FLAG_tf_store_ic_stub);
2193 #ifdef DEBUG
2194         bool use_stub = true;
2195         if (lookup->representation().IsHeapObject()) {
2196           // Only use a generic stub if no types need to be tracked.
2197           Handle<FieldType> field_type = lookup->GetFieldType();
2198           use_stub = !field_type->IsClass();
2199         }
2200         DCHECK(!use_stub);
2201 #endif
2202         TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField);
2203         NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
2204         return compiler.CompileStoreField(lookup);
2205       }
2206 
2207       // -------------- Constant properties --------------
2208       DCHECK(lookup->property_details().type() == DATA_CONSTANT);
2209       UNREACHABLE();
2210     }
2211 
2212     case LookupIterator::INTEGER_INDEXED_EXOTIC:
2213     case LookupIterator::ACCESS_CHECK:
2214     case LookupIterator::JSPROXY:
2215     case LookupIterator::NOT_FOUND:
2216       UNREACHABLE();
2217   }
2218   UNREACHABLE();
2219   return slow_stub();
2220 }
2221 
UpdateStoreElement(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)2222 void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
2223                                       KeyedAccessStoreMode store_mode) {
2224   MapHandleList target_receiver_maps;
2225   TargetMaps(&target_receiver_maps);
2226   if (target_receiver_maps.length() == 0) {
2227     Handle<Map> monomorphic_map =
2228         ComputeTransitionedMap(receiver_map, store_mode);
2229     store_mode = GetNonTransitioningStoreMode(store_mode);
2230     Handle<Code> handler =
2231         PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(monomorphic_map,
2232                                                                 store_mode);
2233     return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
2234   }
2235 
2236   for (int i = 0; i < target_receiver_maps.length(); i++) {
2237     if (!target_receiver_maps.at(i).is_null() &&
2238         target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
2239       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "JSValue");
2240       return;
2241     }
2242   }
2243 
2244   // There are several special cases where an IC that is MONOMORPHIC can still
2245   // transition to a different GetNonTransitioningStoreMode IC that handles a
2246   // superset of the original IC. Handle those here if the receiver map hasn't
2247   // changed or it has transitioned to a more general kind.
2248   KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
2249   Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
2250   if (state() == MONOMORPHIC) {
2251     Handle<Map> transitioned_receiver_map = receiver_map;
2252     if (IsTransitionStoreMode(store_mode)) {
2253       transitioned_receiver_map =
2254           ComputeTransitionedMap(receiver_map, store_mode);
2255     }
2256     if ((receiver_map.is_identical_to(previous_receiver_map) &&
2257          IsTransitionStoreMode(store_mode)) ||
2258         IsTransitionOfMonomorphicTarget(*previous_receiver_map,
2259                                         *transitioned_receiver_map)) {
2260       // If the "old" and "new" maps are in the same elements map family, or
2261       // if they at least come from the same origin for a transitioning store,
2262       // stay MONOMORPHIC and use the map for the most generic ElementsKind.
2263       store_mode = GetNonTransitioningStoreMode(store_mode);
2264       Handle<Code> handler =
2265           PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
2266               transitioned_receiver_map, store_mode);
2267       ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
2268       return;
2269     }
2270     if (receiver_map.is_identical_to(previous_receiver_map) &&
2271         old_store_mode == STANDARD_STORE &&
2272         (store_mode == STORE_AND_GROW_NO_TRANSITION ||
2273          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
2274          store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
2275       // A "normal" IC that handles stores can switch to a version that can
2276       // grow at the end of the array, handle OOB accesses or copy COW arrays
2277       // and still stay MONOMORPHIC.
2278       Handle<Code> handler =
2279           PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(receiver_map,
2280                                                                   store_mode);
2281       return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
2282     }
2283   }
2284 
2285   DCHECK(state() != GENERIC);
2286 
2287   bool map_added =
2288       AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
2289 
2290   if (IsTransitionStoreMode(store_mode)) {
2291     Handle<Map> transitioned_receiver_map =
2292         ComputeTransitionedMap(receiver_map, store_mode);
2293     map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
2294                                             transitioned_receiver_map);
2295   }
2296 
2297   if (!map_added) {
2298     // If the miss wasn't due to an unseen map, a polymorphic stub
2299     // won't help, use the megamorphic stub which can handle everything.
2300     TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
2301     return;
2302   }
2303 
2304   // If the maximum number of receiver maps has been exceeded, use the
2305   // megamorphic version of the IC.
2306   if (target_receiver_maps.length() > kMaxKeyedPolymorphism) return;
2307 
2308   // Make sure all polymorphic handlers have the same store mode, otherwise the
2309   // megamorphic stub must be used.
2310   store_mode = GetNonTransitioningStoreMode(store_mode);
2311   if (old_store_mode != STANDARD_STORE) {
2312     if (store_mode == STANDARD_STORE) {
2313       store_mode = old_store_mode;
2314     } else if (store_mode != old_store_mode) {
2315       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
2316       return;
2317     }
2318   }
2319 
2320   // If the store mode isn't the standard mode, make sure that all polymorphic
2321   // receivers are either external arrays, or all "normal" arrays. Otherwise,
2322   // use the megamorphic stub.
2323   if (store_mode != STANDARD_STORE) {
2324     int external_arrays = 0;
2325     for (int i = 0; i < target_receiver_maps.length(); ++i) {
2326       if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
2327         external_arrays++;
2328       }
2329     }
2330     if (external_arrays != 0 &&
2331         external_arrays != target_receiver_maps.length()) {
2332       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2333                        "unsupported combination of external and normal arrays");
2334       return;
2335     }
2336   }
2337 
2338   MapHandleList transitioned_maps(target_receiver_maps.length());
2339   CodeHandleList handlers(target_receiver_maps.length());
2340   PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
2341       &target_receiver_maps, &transitioned_maps, &handlers, store_mode);
2342   ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
2343 }
2344 
2345 
ComputeTransitionedMap(Handle<Map> map,KeyedAccessStoreMode store_mode)2346 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
2347     Handle<Map> map, KeyedAccessStoreMode store_mode) {
2348   switch (store_mode) {
2349     case STORE_TRANSITION_TO_OBJECT:
2350     case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
2351       ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
2352                               ? FAST_HOLEY_ELEMENTS
2353                               : FAST_ELEMENTS;
2354       return Map::TransitionElementsTo(map, kind);
2355     }
2356     case STORE_TRANSITION_TO_DOUBLE:
2357     case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
2358       ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
2359                               ? FAST_HOLEY_DOUBLE_ELEMENTS
2360                               : FAST_DOUBLE_ELEMENTS;
2361       return Map::TransitionElementsTo(map, kind);
2362     }
2363     case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
2364       DCHECK(map->has_fixed_typed_array_elements());
2365     // Fall through
2366     case STORE_NO_TRANSITION_HANDLE_COW:
2367     case STANDARD_STORE:
2368     case STORE_AND_GROW_NO_TRANSITION:
2369       return map;
2370   }
2371   UNREACHABLE();
2372   return MaybeHandle<Map>().ToHandleChecked();
2373 }
2374 
2375 
IsOutOfBoundsAccess(Handle<JSObject> receiver,uint32_t index)2376 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
2377   uint32_t length = 0;
2378   if (receiver->IsJSArray()) {
2379     JSArray::cast(*receiver)->length()->ToArrayLength(&length);
2380   } else {
2381     length = static_cast<uint32_t>(receiver->elements()->length());
2382   }
2383   return index >= length;
2384 }
2385 
2386 
GetStoreMode(Handle<JSObject> receiver,uint32_t index,Handle<Object> value)2387 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2388                                          uint32_t index, Handle<Object> value) {
2389   bool oob_access = IsOutOfBoundsAccess(receiver, index);
2390   // Don't consider this a growing store if the store would send the receiver to
2391   // dictionary mode.
2392   bool allow_growth = receiver->IsJSArray() && oob_access &&
2393                       !receiver->WouldConvertToSlowElements(index);
2394   if (allow_growth) {
2395     // Handle growing array in stub if necessary.
2396     if (receiver->HasFastSmiElements()) {
2397       if (value->IsHeapNumber()) {
2398         return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
2399       }
2400       if (value->IsHeapObject()) {
2401         return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2402       }
2403     } else if (receiver->HasFastDoubleElements()) {
2404       if (!value->IsSmi() && !value->IsHeapNumber()) {
2405         return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2406       }
2407     }
2408     return STORE_AND_GROW_NO_TRANSITION;
2409   } else {
2410     // Handle only in-bounds elements accesses.
2411     if (receiver->HasFastSmiElements()) {
2412       if (value->IsHeapNumber()) {
2413         return STORE_TRANSITION_TO_DOUBLE;
2414       } else if (value->IsHeapObject()) {
2415         return STORE_TRANSITION_TO_OBJECT;
2416       }
2417     } else if (receiver->HasFastDoubleElements()) {
2418       if (!value->IsSmi() && !value->IsHeapNumber()) {
2419         return STORE_TRANSITION_TO_OBJECT;
2420       }
2421     }
2422     if (!FLAG_trace_external_array_abuse &&
2423         receiver->map()->has_fixed_typed_array_elements() && oob_access) {
2424       return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2425     }
2426     Heap* heap = receiver->GetHeap();
2427     if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2428       return STORE_NO_TRANSITION_HANDLE_COW;
2429     } else {
2430       return STANDARD_STORE;
2431     }
2432   }
2433 }
2434 
2435 
Store(Handle<Object> object,Handle<Object> key,Handle<Object> value)2436 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2437                                         Handle<Object> key,
2438                                         Handle<Object> value) {
2439   // TODO(verwaest): Let SetProperty do the migration, since storing a property
2440   // might deprecate the current map again, if value does not fit.
2441   if (MigrateDeprecated(object)) {
2442     Handle<Object> result;
2443     ASSIGN_RETURN_ON_EXCEPTION(
2444         isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2445                                                       value, language_mode()),
2446         Object);
2447     return result;
2448   }
2449 
2450   // Check for non-string values that can be converted into an
2451   // internalized string directly or is representable as a smi.
2452   key = TryConvertKey(key, isolate());
2453 
2454   Handle<Object> store_handle;
2455 
2456   uint32_t index;
2457   if ((key->IsInternalizedString() &&
2458        !String::cast(*key)->AsArrayIndex(&index)) ||
2459       key->IsSymbol()) {
2460     ASSIGN_RETURN_ON_EXCEPTION(
2461         isolate(), store_handle,
2462         StoreIC::Store(object, Handle<Name>::cast(key), value,
2463                        JSReceiver::MAY_BE_STORE_FROM_KEYED),
2464         Object);
2465     if (!is_vector_set()) {
2466       ConfigureVectorState(MEGAMORPHIC, key);
2467       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2468                        "unhandled internalized string key");
2469       TRACE_IC("StoreIC", key);
2470     }
2471     return store_handle;
2472   }
2473 
2474   bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
2475                 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
2476   if (use_ic && !object->IsSmi()) {
2477     // Don't use ICs for maps of the objects in Array's prototype chain. We
2478     // expect to be able to trap element sets to objects with those maps in
2479     // the runtime to enable optimization of element hole access.
2480     Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2481     if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2482       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2483       use_ic = false;
2484     }
2485   }
2486 
2487   Handle<Map> old_receiver_map;
2488   bool sloppy_arguments_elements = false;
2489   bool key_is_valid_index = false;
2490   KeyedAccessStoreMode store_mode = STANDARD_STORE;
2491   if (use_ic && object->IsJSObject()) {
2492     Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2493     old_receiver_map = handle(receiver->map(), isolate());
2494     sloppy_arguments_elements =
2495         !is_sloppy(language_mode()) &&
2496         receiver->elements()->map() ==
2497             isolate()->heap()->sloppy_arguments_elements_map();
2498     if (!sloppy_arguments_elements) {
2499       key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
2500       if (key_is_valid_index) {
2501         uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2502         store_mode = GetStoreMode(receiver, index, value);
2503       }
2504     }
2505   }
2506 
2507   DCHECK(store_handle.is_null());
2508   ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2509                              Runtime::SetObjectProperty(isolate(), object, key,
2510                                                         value, language_mode()),
2511                              Object);
2512 
2513   if (use_ic) {
2514     if (!old_receiver_map.is_null()) {
2515       if (sloppy_arguments_elements) {
2516         TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2517       } else if (key_is_valid_index) {
2518         // We should go generic if receiver isn't a dictionary, but our
2519         // prototype chain does have dictionary elements. This ensures that
2520         // other non-dictionary receivers in the polymorphic case benefit
2521         // from fast path keyed stores.
2522         if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2523           UpdateStoreElement(old_receiver_map, store_mode);
2524         } else {
2525           TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2526                            "dictionary or proxy prototype");
2527         }
2528       } else {
2529         TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2530       }
2531     } else {
2532       TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2533     }
2534   }
2535 
2536   if (!is_vector_set()) {
2537     ConfigureVectorState(MEGAMORPHIC, key);
2538     TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2539   }
2540   TRACE_IC("StoreIC", key);
2541 
2542   return store_handle;
2543 }
2544 
2545 
HandleMiss(Handle<Object> function)2546 void CallIC::HandleMiss(Handle<Object> function) {
2547   Handle<Object> name = isolate()->factory()->empty_string();
2548   CallICNexus* nexus = casted_nexus<CallICNexus>();
2549   Object* feedback = nexus->GetFeedback();
2550 
2551   // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2552   DCHECK(!feedback->IsSmi());
2553 
2554   if (feedback->IsWeakCell() || !function->IsJSFunction() ||
2555       feedback->IsAllocationSite()) {
2556     // We are going generic.
2557     nexus->ConfigureMegamorphic();
2558   } else {
2559     DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
2560     Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2561 
2562     Handle<JSFunction> array_function =
2563         Handle<JSFunction>(isolate()->native_context()->array_function());
2564     if (array_function.is_identical_to(js_function)) {
2565       // Alter the slot.
2566       nexus->ConfigureMonomorphicArray();
2567     } else if (js_function->context()->native_context() !=
2568                *isolate()->native_context()) {
2569       // Don't collect cross-native context feedback for the CallIC.
2570       // TODO(bmeurer): We should collect the SharedFunctionInfo as
2571       // feedback in this case instead.
2572       nexus->ConfigureMegamorphic();
2573     } else {
2574       nexus->ConfigureMonomorphic(js_function);
2575     }
2576   }
2577 
2578   if (function->IsJSFunction()) {
2579     Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2580     name = handle(js_function->shared()->name(), isolate());
2581   }
2582 
2583   OnTypeFeedbackChanged(isolate(), get_host());
2584   TRACE_IC("CallIC", name);
2585 }
2586 
2587 
2588 #undef TRACE_IC
2589 
2590 
2591 // ----------------------------------------------------------------------------
2592 // Static IC stub generators.
2593 //
2594 
2595 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_CallIC_Miss)2596 RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
2597   HandleScope scope(isolate);
2598   DCHECK_EQ(3, args.length());
2599   // Runtime functions don't follow the IC's calling convention.
2600   Handle<Object> function = args.at<Object>(0);
2601   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2602   Handle<Smi> slot = args.at<Smi>(2);
2603   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2604   CallICNexus nexus(vector, vector_slot);
2605   CallIC ic(isolate, &nexus);
2606   ic.HandleMiss(function);
2607   return *function;
2608 }
2609 
2610 
2611 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadIC_Miss)2612 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2613   HandleScope scope(isolate);
2614   DCHECK_EQ(4, args.length());
2615   // Runtime functions don't follow the IC's calling convention.
2616   Handle<Object> receiver = args.at<Object>(0);
2617   Handle<Smi> slot = args.at<Smi>(2);
2618   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2619   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2620   // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2621   // LoadIC miss handler if the handler misses. Since the vector Nexus is
2622   // set up outside the IC, handle that here.
2623   FeedbackVectorSlotKind kind = vector->GetKind(vector_slot);
2624   if (kind == FeedbackVectorSlotKind::LOAD_IC) {
2625     Handle<Name> key = args.at<Name>(1);
2626     LoadICNexus nexus(vector, vector_slot);
2627     LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2628     ic.UpdateState(receiver, key);
2629     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2630 
2631   } else if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
2632     Handle<Name> key(vector->GetName(vector_slot), isolate);
2633     DCHECK_NE(*key, isolate->heap()->empty_string());
2634     DCHECK_EQ(*isolate->global_object(), *receiver);
2635     LoadGlobalICNexus nexus(vector, vector_slot);
2636     LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2637     ic.UpdateState(receiver, key);
2638     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2639 
2640   } else {
2641     Handle<Name> key = args.at<Name>(1);
2642     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind);
2643     KeyedLoadICNexus nexus(vector, vector_slot);
2644     KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2645     ic.UpdateState(receiver, key);
2646     RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2647   }
2648 }
2649 
2650 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss)2651 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2652   HandleScope scope(isolate);
2653   DCHECK_EQ(2, args.length());
2654   // Runtime functions don't follow the IC's calling convention.
2655   Handle<JSGlobalObject> global = isolate->global_object();
2656   Handle<Smi> slot = args.at<Smi>(0);
2657   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2658   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2659   DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
2660             vector->GetKind(vector_slot));
2661   Handle<String> name(vector->GetName(vector_slot), isolate);
2662   DCHECK_NE(*name, isolate->heap()->empty_string());
2663 
2664   LoadGlobalICNexus nexus(vector, vector_slot);
2665   LoadGlobalIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2666   ic.UpdateState(global, name);
2667 
2668   Handle<Object> result;
2669   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2670   return *result;
2671 }
2672 
RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow)2673 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2674   HandleScope scope(isolate);
2675   DCHECK_EQ(2, args.length());
2676   CONVERT_SMI_ARG_CHECKED(slot, 0);
2677   CONVERT_ARG_HANDLE_CHECKED(TypeFeedbackVector, vector, 1);
2678 
2679   FeedbackVectorSlot vector_slot = vector->ToSlot(slot);
2680   DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
2681             vector->GetKind(vector_slot));
2682   Handle<String> name(vector->GetName(vector_slot), isolate);
2683   DCHECK_NE(*name, isolate->heap()->empty_string());
2684 
2685   Handle<JSGlobalObject> global = isolate->global_object();
2686 
2687   Handle<ScriptContextTable> script_contexts(
2688       global->native_context()->script_context_table());
2689 
2690   ScriptContextTable::LookupResult lookup_result;
2691   if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
2692     Handle<Context> script_context = ScriptContextTable::GetContext(
2693         script_contexts, lookup_result.context_index);
2694     Handle<Object> result =
2695         FixedArray::get(*script_context, lookup_result.slot_index, isolate);
2696     if (*result == isolate->heap()->the_hole_value()) {
2697       THROW_NEW_ERROR_RETURN_FAILURE(
2698           isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2699     }
2700     return *result;
2701   }
2702 
2703   Handle<Object> result;
2704   bool is_found = false;
2705   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2706       isolate, result,
2707       Runtime::GetObjectProperty(isolate, global, name, &is_found));
2708   if (!is_found) {
2709     LoadICNexus nexus(isolate);
2710     LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2711     // It is actually a LoadGlobalICs here but the predicate handles this case
2712     // properly.
2713     if (ic.ShouldThrowReferenceError()) {
2714       THROW_NEW_ERROR_RETURN_FAILURE(
2715           isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2716     }
2717   }
2718   return *result;
2719 }
2720 
2721 // Used from ic-<arch>.cc
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss)2722 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2723   HandleScope scope(isolate);
2724   DCHECK_EQ(4, args.length());
2725   // Runtime functions don't follow the IC's calling convention.
2726   Handle<Object> receiver = args.at<Object>(0);
2727   Handle<Object> key = args.at<Object>(1);
2728   Handle<Smi> slot = args.at<Smi>(2);
2729   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2730   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2731   KeyedLoadICNexus nexus(vector, vector_slot);
2732   KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2733   ic.UpdateState(receiver, key);
2734   RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2735 }
2736 
2737 
RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure)2738 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
2739   HandleScope scope(isolate);
2740   typedef LoadWithVectorDescriptor Descriptor;
2741   DCHECK_EQ(Descriptor::kParameterCount, args.length());
2742   Handle<Object> receiver = args.at<Object>(Descriptor::kReceiver);
2743   Handle<Object> key = args.at<Object>(Descriptor::kName);
2744   Handle<Smi> slot = args.at<Smi>(Descriptor::kSlot);
2745   Handle<TypeFeedbackVector> vector =
2746       args.at<TypeFeedbackVector>(Descriptor::kVector);
2747   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2748   KeyedLoadICNexus nexus(vector, vector_slot);
2749   KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2750   ic.UpdateState(receiver, key);
2751   RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2752 }
2753 
2754 
2755 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_StoreIC_Miss)2756 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2757   HandleScope scope(isolate);
2758   DCHECK_EQ(5, args.length());
2759   // Runtime functions don't follow the IC's calling convention.
2760   Handle<Object> value = args.at<Object>(0);
2761   Handle<Smi> slot = args.at<Smi>(1);
2762   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
2763   Handle<Object> receiver = args.at<Object>(3);
2764   Handle<Name> key = args.at<Name>(4);
2765   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2766   if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2767     StoreICNexus nexus(vector, vector_slot);
2768     StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2769     ic.UpdateState(receiver, key);
2770     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2771   } else {
2772     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2773               vector->GetKind(vector_slot));
2774     KeyedStoreICNexus nexus(vector, vector_slot);
2775     KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2776     ic.UpdateState(receiver, key);
2777     RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2778   }
2779 }
2780 
2781 
2782 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss)2783 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2784   HandleScope scope(isolate);
2785   DCHECK_EQ(5, args.length());
2786   // Runtime functions don't follow the IC's calling convention.
2787   Handle<Object> value = args.at<Object>(0);
2788   Handle<Smi> slot = args.at<Smi>(1);
2789   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
2790   Handle<Object> receiver = args.at<Object>(3);
2791   Handle<Object> key = args.at<Object>(4);
2792   FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2793   KeyedStoreICNexus nexus(vector, vector_slot);
2794   KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2795   ic.UpdateState(receiver, key);
2796   RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2797 }
2798 
2799 
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow)2800 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2801   HandleScope scope(isolate);
2802   DCHECK_EQ(5, args.length());
2803   // Runtime functions don't follow the IC's calling convention.
2804   Handle<Object> value = args.at<Object>(0);
2805   // slot and vector parameters are not used.
2806   Handle<Object> object = args.at<Object>(3);
2807   Handle<Object> key = args.at<Object>(4);
2808   LanguageMode language_mode;
2809   KeyedStoreICNexus nexus(isolate);
2810   KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2811   language_mode = ic.language_mode();
2812   RETURN_RESULT_OR_FAILURE(
2813       isolate,
2814       Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2815 }
2816 
2817 
RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss)2818 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2819   HandleScope scope(isolate);
2820   // Runtime functions don't follow the IC's calling convention.
2821   Handle<Object> object = args.at<Object>(0);
2822   Handle<Object> key = args.at<Object>(1);
2823   Handle<Object> value = args.at<Object>(2);
2824   Handle<Map> map = args.at<Map>(3);
2825   LanguageMode language_mode;
2826   KeyedStoreICNexus nexus(isolate);
2827   KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2828   language_mode = ic.language_mode();
2829   if (object->IsJSObject()) {
2830     JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2831                                      map->elements_kind());
2832   }
2833   RETURN_RESULT_OR_FAILURE(
2834       isolate,
2835       Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2836 }
2837 
2838 
Transition(Handle<AllocationSite> allocation_site,Handle<Object> left,Handle<Object> right)2839 MaybeHandle<Object> BinaryOpIC::Transition(
2840     Handle<AllocationSite> allocation_site, Handle<Object> left,
2841     Handle<Object> right) {
2842   BinaryOpICState state(isolate(), extra_ic_state());
2843 
2844   // Compute the actual result using the builtin for the binary operation.
2845   Handle<Object> result;
2846   switch (state.op()) {
2847     default:
2848       UNREACHABLE();
2849     case Token::ADD:
2850       ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2851                                  Object::Add(isolate(), left, right), Object);
2852       break;
2853     case Token::SUB:
2854       ASSIGN_RETURN_ON_EXCEPTION(
2855           isolate(), result, Object::Subtract(isolate(), left, right), Object);
2856       break;
2857     case Token::MUL:
2858       ASSIGN_RETURN_ON_EXCEPTION(
2859           isolate(), result, Object::Multiply(isolate(), left, right), Object);
2860       break;
2861     case Token::DIV:
2862       ASSIGN_RETURN_ON_EXCEPTION(
2863           isolate(), result, Object::Divide(isolate(), left, right), Object);
2864       break;
2865     case Token::MOD:
2866       ASSIGN_RETURN_ON_EXCEPTION(
2867           isolate(), result, Object::Modulus(isolate(), left, right), Object);
2868       break;
2869     case Token::BIT_OR:
2870       ASSIGN_RETURN_ON_EXCEPTION(
2871           isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
2872       break;
2873     case Token::BIT_AND:
2874       ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2875                                  Object::BitwiseAnd(isolate(), left, right),
2876                                  Object);
2877       break;
2878     case Token::BIT_XOR:
2879       ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2880                                  Object::BitwiseXor(isolate(), left, right),
2881                                  Object);
2882       break;
2883     case Token::SAR:
2884       ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2885                                  Object::ShiftRight(isolate(), left, right),
2886                                  Object);
2887       break;
2888     case Token::SHR:
2889       ASSIGN_RETURN_ON_EXCEPTION(
2890           isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
2891           Object);
2892       break;
2893     case Token::SHL:
2894       ASSIGN_RETURN_ON_EXCEPTION(
2895           isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
2896       break;
2897   }
2898 
2899   // Do not try to update the target if the code was marked for lazy
2900   // deoptimization. (Since we do not relocate addresses in these
2901   // code objects, an attempt to access the target could fail.)
2902   if (AddressIsDeoptimizedCode()) {
2903     return result;
2904   }
2905 
2906   // Compute the new state.
2907   BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2908   state.Update(left, right, result);
2909 
2910   // Check if we have a string operation here.
2911   Handle<Code> new_target;
2912   if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2913     // Setup the allocation site on-demand.
2914     if (allocation_site.is_null()) {
2915       allocation_site = isolate()->factory()->NewAllocationSite();
2916     }
2917 
2918     // Install the stub with an allocation site.
2919     BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2920     new_target = stub.GetCodeCopyFromTemplate(allocation_site);
2921 
2922     // Sanity check the trampoline stub.
2923     DCHECK_EQ(*allocation_site, new_target->FindFirstAllocationSite());
2924   } else {
2925     // Install the generic stub.
2926     BinaryOpICStub stub(isolate(), state);
2927     new_target = stub.GetCode();
2928 
2929     // Sanity check the generic stub.
2930     DCHECK_NULL(new_target->FindFirstAllocationSite());
2931   }
2932   set_target(*new_target);
2933 
2934   if (FLAG_trace_ic) {
2935     OFStream os(stdout);
2936     os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2937        << static_cast<void*>(*new_target) << " <- ";
2938     JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2939     if (!allocation_site.is_null()) {
2940       os << " using allocation site " << static_cast<void*>(*allocation_site);
2941     }
2942     os << "]" << std::endl;
2943   }
2944 
2945   // Patch the inlined smi code as necessary.
2946   if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2947     PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
2948   } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2949     PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
2950   }
2951 
2952   return result;
2953 }
2954 
2955 
RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss)2956 RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
2957   HandleScope scope(isolate);
2958   DCHECK_EQ(2, args.length());
2959   typedef BinaryOpDescriptor Descriptor;
2960   Handle<Object> left = args.at<Object>(Descriptor::kLeft);
2961   Handle<Object> right = args.at<Object>(Descriptor::kRight);
2962   BinaryOpIC ic(isolate);
2963   RETURN_RESULT_OR_FAILURE(
2964       isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
2965 }
2966 
2967 
RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite)2968 RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
2969   HandleScope scope(isolate);
2970   DCHECK_EQ(3, args.length());
2971   typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
2972   Handle<AllocationSite> allocation_site =
2973       args.at<AllocationSite>(Descriptor::kAllocationSite);
2974   Handle<Object> left = args.at<Object>(Descriptor::kLeft);
2975   Handle<Object> right = args.at<Object>(Descriptor::kRight);
2976   BinaryOpIC ic(isolate);
2977   RETURN_RESULT_OR_FAILURE(isolate,
2978                            ic.Transition(allocation_site, left, right));
2979 }
2980 
GetRawUninitialized(Isolate * isolate,Token::Value op)2981 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2982   CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2983                      CompareICState::UNINITIALIZED,
2984                      CompareICState::UNINITIALIZED);
2985   Code* code = NULL;
2986   CHECK(stub.FindCodeInCache(&code));
2987   return code;
2988 }
2989 
UpdateCaches(Handle<Object> x,Handle<Object> y)2990 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2991   HandleScope scope(isolate());
2992   CompareICStub old_stub(target()->stub_key(), isolate());
2993   CompareICState::State new_left =
2994       CompareICState::NewInputState(old_stub.left(), x);
2995   CompareICState::State new_right =
2996       CompareICState::NewInputState(old_stub.right(), y);
2997   CompareICState::State state = CompareICState::TargetState(
2998       isolate(), old_stub.state(), old_stub.left(), old_stub.right(), op_,
2999       HasInlinedSmiCode(address()), x, y);
3000   CompareICStub stub(isolate(), op_, new_left, new_right, state);
3001   if (state == CompareICState::KNOWN_RECEIVER) {
3002     stub.set_known_map(
3003         Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
3004   }
3005   Handle<Code> new_target = stub.GetCode();
3006   set_target(*new_target);
3007 
3008   if (FLAG_trace_ic) {
3009     PrintF("[CompareIC in ");
3010     JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
3011     PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
3012            CompareICState::GetStateName(old_stub.left()),
3013            CompareICState::GetStateName(old_stub.right()),
3014            CompareICState::GetStateName(old_stub.state()),
3015            CompareICState::GetStateName(new_left),
3016            CompareICState::GetStateName(new_right),
3017            CompareICState::GetStateName(state), Token::Name(op_),
3018            static_cast<void*>(*stub.GetCode()));
3019   }
3020 
3021   // Activate inlined smi code.
3022   if (old_stub.state() == CompareICState::UNINITIALIZED) {
3023     PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
3024   }
3025 
3026   return *new_target;
3027 }
3028 
3029 
3030 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
RUNTIME_FUNCTION(Runtime_CompareIC_Miss)3031 RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
3032   HandleScope scope(isolate);
3033   DCHECK(args.length() == 3);
3034   CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
3035   return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
3036 }
3037 
3038 
RUNTIME_FUNCTION(Runtime_Unreachable)3039 RUNTIME_FUNCTION(Runtime_Unreachable) {
3040   UNREACHABLE();
3041   CHECK(false);
3042   return isolate->heap()->undefined_value();
3043 }
3044 
3045 
ToBoolean(Handle<Object> object)3046 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
3047   ToBooleanICStub stub(isolate(), extra_ic_state());
3048   bool to_boolean_value = stub.UpdateStatus(object);
3049   Handle<Code> code = stub.GetCode();
3050   set_target(*code);
3051   return isolate()->factory()->ToBoolean(to_boolean_value);
3052 }
3053 
3054 
RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss)3055 RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
3056   DCHECK(args.length() == 1);
3057   HandleScope scope(isolate);
3058   Handle<Object> object = args.at<Object>(0);
3059   ToBooleanIC ic(isolate);
3060   return *ic.ToBoolean(object);
3061 }
3062 
3063 
RUNTIME_FUNCTION(Runtime_StoreCallbackProperty)3064 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
3065   Handle<JSObject> receiver = args.at<JSObject>(0);
3066   Handle<JSObject> holder = args.at<JSObject>(1);
3067   Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
3068   Handle<Name> name = args.at<Name>(3);
3069   Handle<Object> value = args.at<Object>(4);
3070   CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
3071   HandleScope scope(isolate);
3072 
3073   if (V8_UNLIKELY(FLAG_runtime_stats)) {
3074     RETURN_RESULT_OR_FAILURE(
3075         isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
3076                                             language_mode));
3077   }
3078 
3079   Handle<AccessorInfo> callback(
3080       callback_or_cell->IsWeakCell()
3081           ? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
3082           : AccessorInfo::cast(*callback_or_cell));
3083 
3084   DCHECK(callback->IsCompatibleReceiver(*receiver));
3085 
3086   Address setter_address = v8::ToCData<Address>(callback->setter());
3087   v8::AccessorNameSetterCallback fun =
3088       FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
3089   DCHECK(fun != NULL);
3090 
3091   Object::ShouldThrow should_throw =
3092       is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
3093   PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
3094                                         *holder, should_throw);
3095   custom_args.Call(fun, name, value);
3096   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3097   return *value;
3098 }
3099 
3100 
3101 /**
3102  * Attempts to load a property with an interceptor (which must be present),
3103  * but doesn't search the prototype chain.
3104  *
3105  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
3106  * provide any value for the given name.
3107  */
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly)3108 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
3109   DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
3110   Handle<Name> name =
3111       args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
3112   Handle<Object> receiver =
3113       args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
3114   Handle<JSObject> holder =
3115       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
3116   HandleScope scope(isolate);
3117 
3118   if (!receiver->IsJSReceiver()) {
3119     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3120         isolate, receiver, Object::ConvertReceiver(isolate, receiver));
3121   }
3122 
3123   InterceptorInfo* interceptor = holder->GetNamedInterceptor();
3124   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3125                                       *holder, Object::DONT_THROW);
3126 
3127   v8::GenericNamedPropertyGetterCallback getter =
3128       v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
3129           interceptor->getter());
3130   Handle<Object> result = arguments.Call(getter, name);
3131 
3132   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3133 
3134   if (!result.is_null()) return *result;
3135   return isolate->heap()->no_interceptor_result_sentinel();
3136 }
3137 
3138 
3139 /**
3140  * Loads a property with an interceptor performing post interceptor
3141  * lookup if interceptor failed.
3142  */
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor)3143 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
3144   HandleScope scope(isolate);
3145   DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
3146   Handle<Name> name =
3147       args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
3148   Handle<Object> receiver =
3149       args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
3150   Handle<JSObject> holder =
3151       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
3152 
3153   if (!receiver->IsJSReceiver()) {
3154     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3155         isolate, receiver, Object::ConvertReceiver(isolate, receiver));
3156   }
3157 
3158   InterceptorInfo* interceptor = holder->GetNamedInterceptor();
3159   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3160                                       *holder, Object::DONT_THROW);
3161 
3162   v8::GenericNamedPropertyGetterCallback getter =
3163       v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
3164           interceptor->getter());
3165   Handle<Object> result = arguments.Call(getter, name);
3166 
3167   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3168 
3169   if (!result.is_null()) return *result;
3170 
3171   LookupIterator it(receiver, name, holder);
3172   // Skip any lookup work until we hit the (possibly non-masking) interceptor.
3173   while (it.state() != LookupIterator::INTERCEPTOR ||
3174          !it.GetHolder<JSObject>().is_identical_to(holder)) {
3175     DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
3176     it.Next();
3177   }
3178   // Skip past the interceptor.
3179   it.Next();
3180   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
3181 
3182   if (it.IsFound()) return *result;
3183 
3184 #ifdef DEBUG
3185   LoadICNexus nexus(isolate);
3186   LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
3187   // It could actually be any kind of LoadICs here but the predicate handles
3188   // all the cases properly.
3189   DCHECK(!ic.ShouldThrowReferenceError());
3190 #endif
3191 
3192   return isolate->heap()->undefined_value();
3193 }
3194 
3195 
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor)3196 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
3197   HandleScope scope(isolate);
3198   DCHECK(args.length() == 3);
3199   StoreICNexus nexus(isolate);
3200   StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
3201   Handle<JSObject> receiver = args.at<JSObject>(0);
3202   Handle<Name> name = args.at<Name>(1);
3203   Handle<Object> value = args.at<Object>(2);
3204 
3205   DCHECK(receiver->HasNamedInterceptor());
3206   InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
3207   DCHECK(!interceptor->non_masking());
3208   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3209                                       *receiver, Object::DONT_THROW);
3210 
3211   v8::GenericNamedPropertySetterCallback setter =
3212       v8::ToCData<v8::GenericNamedPropertySetterCallback>(
3213           interceptor->setter());
3214   Handle<Object> result = arguments.Call(setter, name, value);
3215   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3216   if (!result.is_null()) return *value;
3217 
3218   LookupIterator it(receiver, name, receiver);
3219   // Skip past any access check on the receiver.
3220   if (it.state() == LookupIterator::ACCESS_CHECK) {
3221     DCHECK(it.HasAccess());
3222     it.Next();
3223   }
3224   // Skip past the interceptor on the receiver.
3225   DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
3226   it.Next();
3227 
3228   MAYBE_RETURN(Object::SetProperty(&it, value, ic.language_mode(),
3229                                    JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
3230                isolate->heap()->exception());
3231   return *value;
3232 }
3233 
3234 
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor)3235 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
3236   // TODO(verwaest): This should probably get the holder and receiver as input.
3237   HandleScope scope(isolate);
3238   Handle<JSObject> receiver = args.at<JSObject>(0);
3239   DCHECK(args.smi_at(1) >= 0);
3240   uint32_t index = args.smi_at(1);
3241 
3242   InterceptorInfo* interceptor = receiver->GetIndexedInterceptor();
3243   PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3244                                       *receiver, Object::DONT_THROW);
3245 
3246   v8::IndexedPropertyGetterCallback getter =
3247       v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
3248   Handle<Object> result = arguments.Call(getter, index);
3249 
3250   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
3251 
3252   if (result.is_null()) {
3253     LookupIterator it(isolate, receiver, index, receiver);
3254     DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
3255     it.Next();
3256     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3257                                        Object::GetProperty(&it));
3258   }
3259 
3260   return *result;
3261 }
3262 }  // namespace internal
3263 }  // namespace v8
3264