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