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