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