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