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