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.
7 #include "src/accessors.h"
9 #include "src/arguments.h"
10 #include "src/base/bits.h"
11 #include "src/codegen.h"
12 #include "src/conversions.h"
13 #include "src/execution.h"
14 #include "src/ic/call-optimization.h"
15 #include "src/ic/handler-compiler.h"
16 #include "src/ic/ic-inl.h"
17 #include "src/ic/ic-compiler.h"
18 #include "src/ic/stub-cache.h"
19 #include "src/prototype.h"
20 #include "src/runtime/runtime.h"
25 char IC::TransitionMarkFromState(IC::State state) {
33 case PROTOTYPE_FAILURE:
42 // We never see the debugger states here, because the state is
43 // computed from the original code - not the patched code. Let
44 // these cases fall through to the unreachable code below.
47 // Type-vector-based ICs resolve state to one of the above.
56 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
57 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
58 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
61 if (IsGrowStoreMode(mode)) return ".GROW";
68 #define TRACE_GENERIC_IC(isolate, type, reason) \
70 if (FLAG_trace_ic) { \
71 PrintF("[%s patching generic stub in ", type); \
72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
73 PrintF(" (%s)]\n", reason); \
79 #define TRACE_GENERIC_IC(isolate, type, reason) \
81 if (FLAG_trace_ic) { \
82 PrintF("[%s patching generic stub in ", type); \
83 PrintF("(see below) (%s)]\n", reason); \
90 void IC::TraceIC(const char* type, Handle<Object> name) {
93 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
94 TraceIC(type, name, state(), new_state);
99 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
102 Code* new_target = raw_target();
103 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
105 // TODO(jkummerow): Add support for "apply". The logic is roughly:
106 // marker = [fp_ + kMarkerOffset];
107 // if marker is smi and marker.value == INTERNAL and
108 // the frame's code == builtin(Builtins::kFunctionApply):
109 // then print "apply from" and advance one frame
111 Object* maybe_function =
112 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
113 if (maybe_function->IsJSFunction()) {
114 JSFunction* function = JSFunction::cast(maybe_function);
115 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
119 ExtraICState extra_state = new_target->extra_ic_state();
120 const char* modifier = "";
121 if (new_target->kind() == Code::KEYED_STORE_IC) {
122 modifier = GetTransitionMarkModifier(
123 KeyedStoreIC::GetKeyedAccessStoreMode(extra_state));
125 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
126 TransitionMarkFromState(new_state), modifier);
131 name->ShortPrint(stdout);
138 #define TRACE_IC(type, name) TraceIC(type, name)
141 IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
142 bool for_queries_only)
146 target_maps_set_(false),
148 // To improve the performance of the (much used) IC code, we unfold a few
149 // levels of the stack frame iteration code. This yields a ~35% speedup when
150 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
151 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
152 Address constant_pool = NULL;
153 if (FLAG_enable_ool_constant_pool) {
155 Memory::Address_at(entry + ExitFrameConstants::kConstantPoolOffset);
157 Address* pc_address =
158 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
159 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
160 // If there's another JavaScript frame on the stack or a
161 // StubFailureTrampoline, we need to look one frame further down the stack to
162 // find the frame pointer and the return address stack slot.
163 if (depth == EXTRA_CALL_FRAME) {
164 if (FLAG_enable_ool_constant_pool) {
166 Memory::Address_at(fp + StandardFrameConstants::kConstantPoolOffset);
168 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
169 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
170 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
173 StackFrameIterator it(isolate);
174 for (int i = 0; i < depth + 1; i++) it.Advance();
175 StackFrame* frame = it.frame();
176 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
179 if (FLAG_enable_ool_constant_pool) {
180 raw_constant_pool_ = handle(
181 ConstantPoolArray::cast(reinterpret_cast<Object*>(constant_pool)),
184 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
185 target_ = handle(raw_target(), isolate);
186 kind_ = target_->kind();
187 state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
188 : target_->ic_state();
190 extra_ic_state_ = target_->extra_ic_state();
194 SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
195 // Compute the JavaScript frame for the frame pointer of this IC
196 // structure. We need this to be able to find the function
197 // corresponding to the frame.
198 StackFrameIterator it(isolate());
199 while (it.frame()->fp() != this->fp()) it.Advance();
200 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
201 // Find the function on the stack and both the active code for the
202 // function and the original code.
203 JSFunction* function = frame->function();
204 return function->shared();
208 Code* IC::GetCode() const {
209 HandleScope scope(isolate());
210 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
211 Code* code = shared->code();
216 Code* IC::GetOriginalCode() const {
217 HandleScope scope(isolate());
218 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
219 DCHECK(Debug::HasDebugInfo(shared));
220 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
221 DCHECK(original_code->IsCode());
222 return original_code;
226 bool IC::AddressIsOptimizedCode() const {
228 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
229 return host->kind() == Code::OPTIMIZED_FUNCTION;
233 bool IC::AddressIsDeoptimizedCode() const {
235 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
236 return host->kind() == Code::OPTIMIZED_FUNCTION &&
237 host->marked_for_deoptimization();
241 static void LookupForRead(LookupIterator* it) {
242 for (; it->IsFound(); it->Next()) {
243 switch (it->state()) {
244 case LookupIterator::NOT_FOUND:
245 case LookupIterator::TRANSITION:
247 case LookupIterator::JSPROXY:
249 case LookupIterator::INTERCEPTOR: {
250 // If there is a getter, return; otherwise loop to perform the lookup.
251 Handle<JSObject> holder = it->GetHolder<JSObject>();
252 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
257 case LookupIterator::ACCESS_CHECK:
258 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
259 // access checks for global proxies.
260 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
264 case LookupIterator::ACCESSOR:
265 case LookupIterator::INTEGER_INDEXED_EXOTIC:
266 case LookupIterator::DATA:
273 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
274 Handle<String> name) {
275 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
277 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
279 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
282 // The current map wasn't handled yet. There's no reason to stay monomorphic,
283 // *unless* we're moving from a deprecated map to its replacement, or
284 // to a more general elements kind.
285 // TODO(verwaest): Check if the current map is actually what the old map
286 // would transition to.
287 if (maybe_handler_.is_null()) {
288 if (!receiver_map()->IsJSObjectMap()) return false;
289 Map* first_map = FirstTargetMap();
290 if (first_map == NULL) return false;
291 Handle<Map> old_map(first_map);
292 if (old_map->is_deprecated()) return true;
293 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
294 receiver_map()->elements_kind())) {
300 CacheHolderFlag flag;
301 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
303 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
304 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
305 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
307 if (state() == MONOMORPHIC) {
308 int index = ic_holder_map->IndexInCodeCache(*name, *target());
310 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
314 if (receiver->IsGlobalObject()) {
315 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
316 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
317 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
318 if (!it.IsFound()) return false;
319 return it.property_details().cell_type() == PropertyCellType::kConstant;
326 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
327 if (target()->is_keyed_stub()) {
328 // Determine whether the failure is due to a name failure.
329 if (!name->IsName()) return false;
331 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
332 if (*name != stub_name) return false;
339 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
340 update_receiver_map(receiver);
341 if (!name->IsString()) return;
342 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
343 if (receiver->IsUndefined() || receiver->IsNull()) return;
345 // Remove the target from the code cache if it became invalid
346 // because of changes in the prototype chain to avoid hitting it
348 if (TryRemoveInvalidPrototypeDependentStub(receiver,
349 Handle<String>::cast(name))) {
350 MarkPrototypeFailure(name);
354 // The builtins object is special. It only changes when JavaScript
355 // builtins are loaded lazily. It is important to keep inline
356 // caches for the builtins object monomorphic. Therefore, if we get
357 // an inline cache miss for the builtins object after lazily loading
358 // JavaScript builtins, we return uninitialized as the state to
359 // force the inline cache back to monomorphic state.
360 if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
364 MaybeHandle<Object> IC::TypeError(const char* type, Handle<Object> object,
365 Handle<Object> key) {
366 HandleScope scope(isolate());
367 Handle<Object> args[2] = {key, object};
368 THROW_NEW_ERROR(isolate(), NewTypeError(type, HandleVector(args, 2)), Object);
372 MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) {
373 HandleScope scope(isolate());
374 THROW_NEW_ERROR(isolate(), NewReferenceError(type, HandleVector(&name, 1)),
379 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
380 int* polymorphic_delta,
381 int* generic_delta) {
385 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
386 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
387 *polymorphic_delta = 1;
388 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
394 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
395 *polymorphic_delta = -1;
396 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
402 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
404 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
405 *polymorphic_delta = 1;
408 case PROTOTYPE_FAILURE:
416 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
417 State old_state, State new_state,
418 bool target_remains_ic_stub) {
420 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
421 if (host->kind() != Code::FUNCTION) return;
423 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
424 // Not all Code objects have TypeFeedbackInfo.
425 host->type_feedback_info()->IsTypeFeedbackInfo()) {
426 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
427 int generic_delta = 0; // "Generic" here includes megamorphic.
428 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
430 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
431 info->change_ic_with_type_info_count(polymorphic_delta);
432 info->change_ic_generic_count(generic_delta);
434 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
435 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
436 info->change_own_type_change_checksum();
438 host->set_profiler_ticks(0);
439 isolate->runtime_profiler()->NotifyICChanged();
440 // TODO(2029): When an optimized function is patched, it would
441 // be nice to propagate the corresponding type information to its
442 // unoptimized version for the benefit of later inlining.
447 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
448 TypeFeedbackVector* vector, State old_state,
450 if (host->kind() != Code::FUNCTION) return;
452 if (FLAG_type_info_threshold > 0) {
453 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
454 int generic_delta = 0; // "Generic" here includes megamorphic.
455 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
457 vector->change_ic_with_type_info_count(polymorphic_delta);
458 vector->change_ic_generic_count(generic_delta);
460 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
461 info->change_own_type_change_checksum();
462 host->set_profiler_ticks(0);
463 isolate->runtime_profiler()->NotifyICChanged();
464 // TODO(2029): When an optimized function is patched, it would
465 // be nice to propagate the corresponding type information to its
466 // unoptimized version for the benefit of later inlining.
470 void IC::PostPatching(Address address, Code* target, Code* old_target) {
471 // Type vector based ICs update these statistics at a different time because
472 // they don't always patch on state change.
473 if (ICUseVector(target->kind())) return;
475 Isolate* isolate = target->GetHeap()->isolate();
476 State old_state = UNINITIALIZED;
477 State new_state = UNINITIALIZED;
478 bool target_remains_ic_stub = false;
479 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
480 old_state = old_target->ic_state();
481 new_state = target->ic_state();
482 target_remains_ic_stub = true;
485 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
486 target_remains_ic_stub);
490 void IC::Clear(Isolate* isolate, Address address,
491 ConstantPoolArray* constant_pool) {
492 Code* target = GetTargetAtAddress(address, constant_pool);
494 // Don't clear debug break inline cache as it will remove the break point.
495 if (target->is_debug_stub()) return;
497 switch (target->kind()) {
499 if (FLAG_vector_ics) return;
500 return LoadIC::Clear(isolate, address, target, constant_pool);
501 case Code::KEYED_LOAD_IC:
502 if (FLAG_vector_ics) return;
503 return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
505 return StoreIC::Clear(isolate, address, target, constant_pool);
506 case Code::KEYED_STORE_IC:
507 return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
508 case Code::COMPARE_IC:
509 return CompareIC::Clear(isolate, address, target, constant_pool);
510 case Code::COMPARE_NIL_IC:
511 return CompareNilIC::Clear(address, target, constant_pool);
512 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
513 case Code::BINARY_OP_IC:
514 case Code::TO_BOOLEAN_IC:
515 // Clearing these is tricky and does not
516 // make any performance difference.
524 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
525 ConstantPoolArray* constant_pool) {
526 DCHECK(!FLAG_vector_ics);
527 if (IsCleared(target)) return;
529 // Make sure to also clear the map used in inline fast cases. If we
530 // do not clear these maps, cached code can keep objects alive
531 // through the embedded maps.
532 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
536 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
537 if (IsCleared(nexus)) return;
538 // Make sure to also clear the map used in inline fast cases. If we
539 // do not clear these maps, cached code can keep objects alive
540 // through the embedded maps.
541 State state = nexus->StateFromFeedback();
542 nexus->ConfigurePremonomorphic();
543 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
547 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
548 // Determine our state.
549 Object* feedback = nexus->vector()->Get(nexus->slot());
550 State state = nexus->StateFromFeedback();
552 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
553 nexus->ConfigureUninitialized();
554 // The change in state must be processed.
555 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
560 void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
561 ConstantPoolArray* constant_pool) {
562 DCHECK(!FLAG_vector_ics);
563 if (IsCleared(target)) return;
564 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC,
565 target->extra_ic_state());
566 SetTargetAtAddress(address, code, constant_pool);
570 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
571 if (IsCleared(nexus)) return;
572 State state = nexus->StateFromFeedback();
573 nexus->ConfigurePremonomorphic();
574 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
578 void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
579 ConstantPoolArray* constant_pool) {
580 if (IsCleared(target)) return;
581 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
582 target->extra_ic_state());
583 SetTargetAtAddress(address, code, constant_pool);
587 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
588 ConstantPoolArray* constant_pool) {
589 if (IsCleared(target)) return;
591 address, *pre_monomorphic_stub(
592 isolate, StoreIC::GetLanguageMode(target->extra_ic_state())),
597 void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
598 ConstantPoolArray* constant_pool) {
599 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
600 CompareICStub stub(target->stub_key(), isolate);
601 // Only clear CompareICs that can retain objects.
602 if (stub.state() != CompareICState::KNOWN_OBJECT) return;
603 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
605 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
610 Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate) {
611 if (FLAG_compiled_keyed_generic_loads) {
612 return KeyedLoadGenericStub(isolate).GetCode();
614 return isolate->builtins()->KeyedLoadIC_Megamorphic();
619 static bool MigrateDeprecated(Handle<Object> object) {
620 if (!object->IsJSObject()) return false;
621 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
622 if (!receiver->map()->is_deprecated()) return false;
623 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
628 void IC::ConfigureVectorState(IC::State new_state) {
630 if (kind() == Code::LOAD_IC) {
631 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
632 if (new_state == PREMONOMORPHIC) {
633 nexus->ConfigurePremonomorphic();
634 } else if (new_state == MEGAMORPHIC) {
635 nexus->ConfigureMegamorphic();
639 } else if (kind() == Code::KEYED_LOAD_IC) {
640 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
641 if (new_state == PREMONOMORPHIC) {
642 nexus->ConfigurePremonomorphic();
643 } else if (new_state == MEGAMORPHIC) {
644 nexus->ConfigureMegamorphic();
653 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
658 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
659 Handle<Code> handler) {
661 if (kind() == Code::LOAD_IC) {
662 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
663 nexus->ConfigureMonomorphic(map, handler);
665 DCHECK(kind() == Code::KEYED_LOAD_IC);
666 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
667 nexus->ConfigureMonomorphic(name, map, handler);
671 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
676 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
677 CodeHandleList* handlers) {
679 if (kind() == Code::LOAD_IC) {
680 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
681 nexus->ConfigurePolymorphic(maps, handlers);
683 DCHECK(kind() == Code::KEYED_LOAD_IC);
684 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
685 nexus->ConfigurePolymorphic(name, maps, handlers);
689 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
694 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
695 // If the object is undefined or null it's illegal to try to get any
696 // of its properties; throw a TypeError in that case.
697 if (object->IsUndefined() || object->IsNull()) {
698 return TypeError("non_object_property_load", object, name);
701 // Check if the name is trivially convertible to an index and get
702 // the element or char if so.
704 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
705 // Rewrite to the generic keyed load stub.
708 ConfigureVectorState(MEGAMORPHIC);
710 set_target(*megamorphic_stub());
712 TRACE_IC("LoadIC", name);
713 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
715 Handle<Object> result;
716 ASSIGN_RETURN_ON_EXCEPTION(
718 Runtime::GetElementOrCharAt(isolate(), object, index), Object);
722 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
724 if (object->IsGlobalObject() && name->IsString()) {
725 // Look up in script context table.
726 Handle<String> str_name = Handle<String>::cast(name);
727 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
728 Handle<ScriptContextTable> script_contexts(
729 global->native_context()->script_context_table());
731 ScriptContextTable::LookupResult lookup_result;
732 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
733 Handle<Object> result =
734 FixedArray::get(ScriptContextTable::GetContext(
735 script_contexts, lookup_result.context_index),
736 lookup_result.slot_index);
737 if (*result == *isolate()->factory()->the_hole_value()) {
738 // Do not install stubs and stay pre-monomorphic for
739 // uninitialized accesses.
740 return ReferenceError("not_defined", name);
743 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
744 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
745 PatchCache(name, stub.GetCode());
751 // Named lookup in the object.
752 LookupIterator it(object, name);
755 if (it.IsFound() || !IsUndeclaredGlobal(object)) {
756 // Update inline cache and stub cache.
757 if (use_ic) UpdateCaches(&it);
760 Handle<Object> result;
761 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
765 } else if (!IsUndeclaredGlobal(object)) {
766 LOG(isolate(), SuspectReadEvent(*name, *object));
770 return ReferenceError("not_defined", name);
774 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
775 Handle<Map> new_receiver_map) {
776 DCHECK(!new_receiver_map.is_null());
777 for (int current = 0; current < receiver_maps->length(); ++current) {
778 if (!receiver_maps->at(current).is_null() &&
779 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
783 receiver_maps->Add(new_receiver_map);
788 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
789 if (!code->is_handler()) return false;
790 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
791 Handle<Map> map = receiver_map();
793 CodeHandleList handlers;
796 int number_of_maps = maps.length();
797 int deprecated_maps = 0;
798 int handler_to_overwrite = -1;
800 for (int i = 0; i < number_of_maps; i++) {
801 Handle<Map> current_map = maps.at(i);
802 if (current_map->is_deprecated()) {
803 // Filter out deprecated maps to ensure their instances get migrated.
805 } else if (map.is_identical_to(current_map)) {
806 // If the receiver type is already in the polymorphic IC, this indicates
807 // there was a prototoype chain failure. In that case, just overwrite the
809 handler_to_overwrite = i;
810 } else if (handler_to_overwrite == -1 &&
811 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
812 handler_to_overwrite = i;
816 int number_of_valid_maps =
817 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
819 if (number_of_valid_maps >= 4) return false;
820 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
824 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
826 if (!target()->FindHandlers(&handlers, maps.length())) return false;
829 number_of_valid_maps++;
830 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
832 if (number_of_valid_maps == 1) {
834 ConfigureVectorState(name, receiver_map(), code);
836 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, map, code,
840 if (handler_to_overwrite >= 0) {
841 handlers.Set(handler_to_overwrite, code);
842 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
843 maps.Set(handler_to_overwrite, map);
851 ConfigureVectorState(name, &maps, &handlers);
853 ic = PropertyICCompiler::ComputePolymorphic(kind(), &maps, &handlers,
854 number_of_valid_maps, name,
859 if (!UseVector()) set_target(*ic);
864 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
865 DCHECK(handler->is_handler());
867 ConfigureVectorState(name, receiver_map(), handler);
869 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
870 kind(), name, receiver_map(), handler, extra_ic_state());
876 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
878 CodeHandleList handlers;
880 if (!target()->FindHandlers(&handlers, maps.length())) return;
881 for (int i = 0; i < maps.length(); i++) {
882 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
887 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
888 if (source_map == NULL) return true;
889 if (target_map == NULL) return false;
890 ElementsKind target_elements_kind = target_map->elements_kind();
891 bool more_general_transition = IsMoreGeneralElementsKindTransition(
892 source_map->elements_kind(), target_elements_kind);
893 Map* transitioned_map =
894 more_general_transition
895 ? source_map->LookupElementsTransitionMap(target_elements_kind)
898 return transitioned_map == target_map;
902 void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
906 UpdateMonomorphicIC(code, name);
908 case PROTOTYPE_FAILURE:
911 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
912 if (UpdatePolymorphicIC(name, code)) break;
913 // For keyed stubs, we can't know whether old handlers were for the
915 CopyICToMegamorphicCache(name);
918 ConfigureVectorState(MEGAMORPHIC);
920 set_target(*megamorphic_stub());
924 UpdateMegamorphicCache(*receiver_map(), *name, *code);
925 // Indicate that we've handled this case.
942 Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
943 ExtraICState extra_state) {
944 if (FLAG_vector_ics) {
945 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
948 return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state);
952 Handle<Code> LoadIC::load_global(Isolate* isolate, Handle<GlobalObject> global,
953 Handle<String> name) {
954 // This special IC doesn't work with vector ics.
955 DCHECK(!FLAG_vector_ics);
957 Handle<ScriptContextTable> script_contexts(
958 global->native_context()->script_context_table());
960 ScriptContextTable::LookupResult lookup_result;
961 if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
962 return initialize_stub(isolate, LoadICState(CONTEXTUAL).GetExtraICState());
965 Handle<Map> global_map(global->map());
966 Handle<Code> handler = PropertyHandlerCompiler::Find(
967 name, global_map, Code::LOAD_IC, kCacheOnReceiver, Code::NORMAL);
968 if (handler.is_null()) {
969 LookupIterator it(global, name);
970 if (!it.IsFound() || !it.GetHolder<JSObject>().is_identical_to(global) ||
971 it.state() != LookupIterator::DATA) {
972 return initialize_stub(isolate,
973 LoadICState(CONTEXTUAL).GetExtraICState());
975 NamedLoadHandlerCompiler compiler(isolate, global_map, global,
977 Handle<PropertyCell> cell = it.GetPropertyCell();
978 handler = compiler.CompileLoadGlobal(cell, name, it.IsConfigurable());
979 Map::UpdateCodeCache(global_map, name, handler);
981 return PropertyICCompiler::ComputeMonomorphic(
982 Code::LOAD_IC, name, handle(global->map()), handler,
983 LoadICState(CONTEXTUAL).GetExtraICState());
987 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
988 Isolate* isolate, ExtraICState extra_state, State initialization_state) {
989 if (FLAG_vector_ics) {
990 return VectorRawLoadStub(isolate, LoadICState(extra_state)).GetCode();
992 return PropertyICCompiler::ComputeLoad(isolate, initialization_state,
997 Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
998 if (FLAG_vector_ics) {
999 return KeyedLoadICTrampolineStub(isolate).GetCode();
1002 return isolate->builtins()->KeyedLoadIC_Initialize();
1006 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
1007 Isolate* isolate, State initialization_state) {
1008 if (FLAG_vector_ics) {
1009 return VectorRawKeyedLoadStub(isolate).GetCode();
1011 switch (initialization_state) {
1013 return isolate->builtins()->KeyedLoadIC_Initialize();
1014 case PREMONOMORPHIC:
1015 return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
1017 return isolate->builtins()->KeyedLoadIC_Megamorphic();
1021 return Handle<Code>();
1025 Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
1026 LanguageMode language_mode,
1027 State initialization_state) {
1028 switch (initialization_state) {
1030 return is_strict(language_mode)
1031 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
1032 : isolate->builtins()->KeyedStoreIC_Initialize();
1033 case PREMONOMORPHIC:
1034 return is_strict(language_mode)
1035 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
1036 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
1038 return is_strict(language_mode)
1039 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
1040 : isolate->builtins()->KeyedStoreIC_Megamorphic();
1044 return Handle<Code>();
1048 Handle<Code> LoadIC::megamorphic_stub() {
1049 if (kind() == Code::LOAD_IC) {
1050 MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state()));
1051 return stub.GetCode();
1053 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
1054 return KeyedLoadIC::ChooseMegamorphicStub(isolate());
1059 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
1060 ExtraICState extra_state) {
1061 DCHECK(!FLAG_vector_ics);
1062 return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
1066 Handle<Code> KeyedLoadIC::pre_monomorphic_stub(Isolate* isolate) {
1067 return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
1071 Handle<Code> LoadIC::pre_monomorphic_stub() const {
1072 if (kind() == Code::LOAD_IC) {
1073 return LoadIC::pre_monomorphic_stub(isolate(), extra_ic_state());
1075 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
1076 return KeyedLoadIC::pre_monomorphic_stub(isolate());
1081 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
1082 LoadFieldStub stub(isolate(), index);
1083 return stub.GetCode();
1087 void LoadIC::UpdateCaches(LookupIterator* lookup) {
1088 if (state() == UNINITIALIZED) {
1089 // This is the first time we execute this inline cache. Set the target to
1090 // the pre monomorphic stub to delay setting the monomorphic state.
1092 ConfigureVectorState(PREMONOMORPHIC);
1094 set_target(*pre_monomorphic_stub());
1096 TRACE_IC("LoadIC", lookup->name());
1101 if (lookup->state() == LookupIterator::JSPROXY ||
1102 lookup->state() == LookupIterator::ACCESS_CHECK) {
1104 } else if (!lookup->IsFound()) {
1105 if (kind() == Code::LOAD_IC) {
1106 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
1108 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1109 if (code.is_null()) code = slow_stub();
1114 code = ComputeHandler(lookup);
1117 PatchCache(lookup->name(), code);
1118 TRACE_IC("LoadIC", lookup->name());
1122 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1123 isolate()->stub_cache()->Set(name, map, code);
1127 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1128 bool receiver_is_holder =
1129 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1130 CacheHolderFlag flag;
1131 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
1132 receiver_map(), receiver_is_holder, isolate(), &flag);
1134 Handle<Code> code = PropertyHandlerCompiler::Find(
1135 lookup->name(), stub_holder_map, kind(), flag,
1136 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1137 // Use the cached value if it exists, and if it is different from the
1138 // handler that just missed.
1139 if (!code.is_null()) {
1140 if (!maybe_handler_.is_null() &&
1141 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1144 if (maybe_handler_.is_null()) {
1145 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1146 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1147 // cache (which just missed) is different from the cached handler.
1148 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1149 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1150 Code* megamorphic_cached_code =
1151 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1152 if (megamorphic_cached_code != *code) return code;
1159 code = CompileHandler(lookup, value, flag);
1160 DCHECK(code->is_handler());
1162 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1163 // code compiled for this map, otherwise it's already cached in the global
1165 // cache. We are also guarding against installing code with flags that don't
1166 // match the desired CacheHolderFlag computed above, which would lead to
1167 // invalid lookups later.
1168 if (code->type() != Code::NORMAL &&
1169 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1170 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1177 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1178 Handle<Object> unused,
1179 CacheHolderFlag cache_holder) {
1180 Handle<Object> receiver = lookup->GetReceiver();
1181 if (receiver->IsString() &&
1182 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1183 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1184 return SimpleFieldLoad(index);
1187 if (receiver->IsStringWrapper() &&
1188 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1189 StringLengthStub string_length_stub(isolate());
1190 return string_length_stub.GetCode();
1193 // Use specialized code for getting prototype of functions.
1194 if (receiver->IsJSFunction() &&
1195 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1196 Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
1197 !Handle<JSFunction>::cast(receiver)
1199 ->has_non_instance_prototype()) {
1201 FunctionPrototypeStub function_prototype_stub(isolate());
1202 return function_prototype_stub.GetCode();
1205 Handle<Map> map = receiver_map();
1206 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1207 bool receiver_is_holder = receiver.is_identical_to(holder);
1208 switch (lookup->state()) {
1209 case LookupIterator::INTERCEPTOR: {
1210 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1211 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1212 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1213 // the original iterator will be used to fetch the value.
1214 LookupIterator it = *lookup;
1217 return compiler.CompileLoadInterceptor(&it);
1220 case LookupIterator::ACCESSOR: {
1221 // Use simple field loads for some well-known callback properties.
1222 if (receiver_is_holder) {
1223 DCHECK(receiver->IsJSObject());
1224 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
1226 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1229 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map());
1230 return SimpleFieldLoad(index);
1234 Handle<Object> accessors = lookup->GetAccessors();
1235 if (accessors->IsExecutableAccessorInfo()) {
1236 Handle<ExecutableAccessorInfo> info =
1237 Handle<ExecutableAccessorInfo>::cast(accessors);
1238 if (v8::ToCData<Address>(info->getter()) == 0) break;
1239 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1243 if (!holder->HasFastProperties()) break;
1244 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1245 return compiler.CompileLoadCallback(lookup->name(), info);
1247 if (accessors->IsAccessorPair()) {
1248 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1250 if (!getter->IsJSFunction()) break;
1251 if (!holder->HasFastProperties()) break;
1252 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1253 if (!receiver->IsJSObject() && !function->IsBuiltin() &&
1254 is_sloppy(function->shared()->language_mode())) {
1255 // Calling sloppy non-builtins with a value as the receiver
1259 CallOptimization call_optimization(function);
1260 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1261 if (call_optimization.is_simple_api_call() &&
1262 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1263 return compiler.CompileLoadCallback(lookup->name(), call_optimization,
1264 lookup->GetAccessorIndex());
1266 int expected_arguments =
1267 function->shared()->internal_formal_parameter_count();
1268 return compiler.CompileLoadViaGetter(
1269 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1274 case LookupIterator::DATA: {
1275 if (lookup->is_dictionary_holder()) {
1276 if (kind() != Code::LOAD_IC) break;
1277 if (holder->IsGlobalObject()) {
1278 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1280 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1281 Handle<Code> code = compiler.CompileLoadGlobal(
1282 cell, lookup->name(), lookup->IsConfigurable());
1283 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1284 CacheHolderFlag flag;
1285 Handle<Map> stub_holder_map =
1286 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
1287 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1290 // There is only one shared stub for loading normalized
1291 // properties. It does not traverse the prototype chain, so the
1292 // property must be found in the object for the stub to be
1294 if (!receiver_is_holder) break;
1295 return isolate()->builtins()->LoadIC_Normal();
1298 // -------------- Fields --------------
1299 if (lookup->property_details().type() == DATA) {
1300 FieldIndex field = lookup->GetFieldIndex();
1301 if (receiver_is_holder) {
1302 return SimpleFieldLoad(field);
1304 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1305 return compiler.CompileLoadField(lookup->name(), field);
1308 // -------------- Constant properties --------------
1309 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1310 if (receiver_is_holder) {
1311 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1312 return stub.GetCode();
1314 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1315 return compiler.CompileLoadConstant(lookup->name(),
1316 lookup->GetConstantIndex());
1319 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1321 case LookupIterator::ACCESS_CHECK:
1322 case LookupIterator::JSPROXY:
1323 case LookupIterator::NOT_FOUND:
1324 case LookupIterator::TRANSITION:
1332 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1333 // This helper implements a few common fast cases for converting
1334 // non-smi keys of keyed loads/stores to a smi or a string.
1335 if (key->IsHeapNumber()) {
1336 double value = Handle<HeapNumber>::cast(key)->value();
1337 if (std::isnan(value)) {
1338 key = isolate->factory()->nan_string();
1340 int int_value = FastD2I(value);
1341 if (value == int_value && Smi::IsValid(int_value)) {
1342 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1345 } else if (key->IsUndefined()) {
1346 key = isolate->factory()->undefined_string();
1352 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1353 Handle<Code> null_handle;
1354 Handle<Map> receiver_map(receiver->map(), isolate());
1355 MapHandleList target_receiver_maps;
1356 TargetMaps(&target_receiver_maps);
1359 if (target_receiver_maps.length() == 0) {
1360 if (FLAG_vector_ics) {
1361 Handle<Code> handler =
1362 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1363 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1366 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1369 // The first time a receiver is seen that is a transitioned version of the
1370 // previous monomorphic receiver type, assume the new ElementsKind is the
1371 // monomorphic type. This benefits global arrays that only transition
1372 // once, and all call sites accessing them are faster if they remain
1373 // monomorphic. If this optimistic assumption is not true, the IC will
1374 // miss again and it will become polymorphic and support both the
1375 // untransitioned and transitioned maps.
1376 if (state() == MONOMORPHIC && !receiver->IsString() &&
1377 IsMoreGeneralElementsKindTransition(
1378 target_receiver_maps.at(0)->elements_kind(),
1379 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1380 if (FLAG_vector_ics) {
1381 Handle<Code> handler =
1382 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1383 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1386 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1389 DCHECK(state() != GENERIC);
1391 // Determine the list of receiver maps that this call site has seen,
1392 // adding the map that was just encountered.
1393 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1394 // If the miss wasn't due to an unseen map, a polymorphic stub
1395 // won't help, use the generic stub.
1396 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
1397 return megamorphic_stub();
1400 // If the maximum number of receiver maps has been exceeded, use the generic
1401 // version of the IC.
1402 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1403 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
1404 return megamorphic_stub();
1407 if (FLAG_vector_ics) {
1408 CodeHandleList handlers(target_receiver_maps.length());
1409 ElementHandlerCompiler compiler(isolate());
1410 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1411 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps,
1416 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps);
1420 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1421 Handle<Object> key) {
1422 if (MigrateDeprecated(object)) {
1423 Handle<Object> result;
1424 ASSIGN_RETURN_ON_EXCEPTION(
1425 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1430 Handle<Object> load_handle;
1431 Handle<Code> stub = megamorphic_stub();
1433 // Check for non-string values that can be converted into an
1434 // internalized string directly or is representable as a smi.
1435 key = TryConvertKey(key, isolate());
1437 if (key->IsInternalizedString() || key->IsSymbol()) {
1438 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1439 LoadIC::Load(object, Handle<Name>::cast(key)),
1441 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1442 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1443 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1444 if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
1445 stub = LoadElementStub(receiver);
1451 if (!is_target_set()) {
1452 Code* generic = *megamorphic_stub();
1453 if (*stub == generic) {
1454 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1458 TRACE_IC("LoadIC", key);
1461 if (!is_vector_set() || stub.is_null()) {
1462 Code* generic = *megamorphic_stub();
1463 if (!stub.is_null() && *stub == generic) {
1464 ConfigureVectorState(MEGAMORPHIC);
1465 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1468 TRACE_IC("LoadIC", key);
1472 if (!load_handle.is_null()) return load_handle;
1473 Handle<Object> result;
1474 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1475 Runtime::GetObjectProperty(isolate(), object, key),
1481 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1482 JSReceiver::StoreFromKeyed store_mode) {
1483 // Disable ICs for non-JSObjects for now.
1484 Handle<Object> receiver = it->GetReceiver();
1485 if (!receiver->IsJSObject()) return false;
1486 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1488 for (; it->IsFound(); it->Next()) {
1489 switch (it->state()) {
1490 case LookupIterator::NOT_FOUND:
1491 case LookupIterator::TRANSITION:
1493 case LookupIterator::JSPROXY:
1495 case LookupIterator::INTERCEPTOR: {
1496 Handle<JSObject> holder = it->GetHolder<JSObject>();
1497 InterceptorInfo* info = holder->GetNamedInterceptor();
1498 if (it->HolderIsReceiverOrHiddenPrototype()) {
1499 if (!info->setter()->IsUndefined()) return true;
1500 } else if (!info->getter()->IsUndefined() ||
1501 !info->query()->IsUndefined()) {
1506 case LookupIterator::ACCESS_CHECK:
1507 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1509 case LookupIterator::ACCESSOR:
1510 return !it->IsReadOnly();
1511 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1513 case LookupIterator::DATA: {
1514 if (it->IsReadOnly()) return false;
1515 Handle<JSObject> holder = it->GetHolder<JSObject>();
1516 if (receiver.is_identical_to(holder)) {
1517 it->PrepareForDataProperty(value);
1518 // The previous receiver map might just have been deprecated,
1520 update_receiver_map(receiver);
1524 // Receiver != holder.
1525 PrototypeIterator iter(it->isolate(), receiver);
1526 if (receiver->IsJSGlobalProxy()) {
1527 return it->GetHolder<Object>().is_identical_to(
1528 PrototypeIterator::GetCurrent(iter));
1531 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1532 return it->IsCacheableTransition();
1537 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1538 return it->IsCacheableTransition();
1542 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1543 Handle<Object> value,
1544 JSReceiver::StoreFromKeyed store_mode) {
1545 if (object->IsGlobalObject() && name->IsString()) {
1546 // Look up in script context table.
1547 Handle<String> str_name = Handle<String>::cast(name);
1548 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
1549 Handle<ScriptContextTable> script_contexts(
1550 global->native_context()->script_context_table());
1552 ScriptContextTable::LookupResult lookup_result;
1553 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1554 Handle<Context> script_context = ScriptContextTable::GetContext(
1555 script_contexts, lookup_result.context_index);
1556 if (lookup_result.mode == CONST) {
1557 return TypeError("const_assign", object, name);
1560 Handle<Object> previous_value =
1561 FixedArray::get(script_context, lookup_result.slot_index);
1563 if (*previous_value == *isolate()->factory()->the_hole_value()) {
1564 // Do not install stubs and stay pre-monomorphic for
1565 // uninitialized accesses.
1566 return ReferenceError("not_defined", name);
1570 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1571 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1572 PatchCache(name, stub.GetCode());
1575 script_context->set(lookup_result.slot_index, *value);
1580 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1581 // might deprecate the current map again, if value does not fit.
1582 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1583 Handle<Object> result;
1584 ASSIGN_RETURN_ON_EXCEPTION(
1586 Object::SetProperty(object, name, value, language_mode()), Object);
1590 // If the object is undefined or null it's illegal to try to set any
1591 // properties on it; throw a TypeError in that case.
1592 if (object->IsUndefined() || object->IsNull()) {
1593 return TypeError("non_object_property_store", object, name);
1596 // Check if the given name is an array index.
1598 if (name->AsArrayIndex(&index)) {
1599 // Ignore other stores where the receiver is not a JSObject.
1600 // TODO(1475): Must check prototype chains of object wrappers.
1601 if (!object->IsJSObject()) return value;
1602 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1604 Handle<Object> result;
1605 ASSIGN_RETURN_ON_EXCEPTION(
1607 JSObject::SetElement(receiver, index, value, NONE, language_mode()),
1612 // Observed objects are always modified through the runtime.
1613 if (object->IsHeapObject() &&
1614 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1615 Handle<Object> result;
1616 ASSIGN_RETURN_ON_EXCEPTION(
1618 Object::SetProperty(object, name, value, language_mode(), store_mode),
1623 LookupIterator it(object, name);
1624 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1626 // Set the property.
1627 Handle<Object> result;
1628 ASSIGN_RETURN_ON_EXCEPTION(
1630 Object::SetProperty(&it, value, language_mode(), store_mode), Object);
1635 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
1636 CallICState::CallType call_type) {
1637 CallICTrampolineStub stub(isolate, CallICState(argc, call_type));
1638 Handle<Code> code = stub.GetCode();
1643 Handle<Code> CallIC::initialize_stub_in_optimized_code(
1644 Isolate* isolate, int argc, CallICState::CallType call_type) {
1645 CallICStub stub(isolate, CallICState(argc, call_type));
1646 Handle<Code> code = stub.GetCode();
1651 Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1652 LanguageMode language_mode,
1653 State initialization_state) {
1654 DCHECK(initialization_state == UNINITIALIZED ||
1655 initialization_state == PREMONOMORPHIC ||
1656 initialization_state == MEGAMORPHIC);
1657 ExtraICState extra_state = ComputeExtraICState(language_mode);
1658 Handle<Code> ic = PropertyICCompiler::ComputeStore(
1659 isolate, initialization_state, extra_state);
1664 Handle<Code> StoreIC::megamorphic_stub() {
1665 if (kind() == Code::STORE_IC) {
1666 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1669 DCHECK(kind() == Code::KEYED_STORE_IC);
1670 if (is_strict(language_mode())) {
1671 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
1673 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
1679 Handle<Code> StoreIC::slow_stub() const {
1680 if (kind() == Code::STORE_IC) {
1681 return isolate()->builtins()->StoreIC_Slow();
1683 DCHECK(kind() == Code::KEYED_STORE_IC);
1684 return isolate()->builtins()->KeyedStoreIC_Slow();
1689 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1690 LanguageMode language_mode) {
1691 ExtraICState state = ComputeExtraICState(language_mode);
1692 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1696 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1697 JSReceiver::StoreFromKeyed store_mode) {
1698 if (state() == UNINITIALIZED) {
1699 // This is the first time we execute this inline cache. Set the target to
1700 // the pre monomorphic stub to delay setting the monomorphic state.
1701 set_target(*pre_monomorphic_stub());
1702 TRACE_IC("StoreIC", lookup->name());
1706 bool use_ic = LookupForWrite(lookup, value, store_mode);
1708 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1710 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1712 PatchCache(lookup->name(), code);
1713 TRACE_IC("StoreIC", lookup->name());
1717 static Handle<Code> PropertyCellStoreHandler(
1718 Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
1719 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1720 StoreGlobalStub stub(isolate, type == PropertyCellType::kConstant,
1721 receiver->IsJSGlobalProxy());
1722 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1723 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1724 HeapObject::UpdateMapCodeCache(receiver, name, code);
1729 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1730 Handle<Object> value,
1731 CacheHolderFlag cache_holder) {
1732 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1734 // This is currently guaranteed by checks in StoreIC::Store.
1735 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1736 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1737 DCHECK(!receiver->IsAccessCheckNeeded());
1739 switch (lookup->state()) {
1740 case LookupIterator::TRANSITION: {
1741 auto store_target = lookup->GetStoreTarget();
1742 if (store_target->IsGlobalObject()) {
1743 // TODO(dcarney): this currently just deopts. Use the transition cell.
1744 auto cell = isolate()->factory()->NewPropertyCell();
1745 cell->set_value(*value);
1746 auto code = PropertyCellStoreHandler(
1747 isolate(), store_target, Handle<GlobalObject>::cast(store_target),
1748 lookup->name(), cell, PropertyCellType::kConstant);
1749 cell->set_value(isolate()->heap()->the_hole_value());
1752 Handle<Map> transition = lookup->transition_map();
1753 // Currently not handled by CompileStoreTransition.
1754 if (!holder->HasFastProperties()) {
1755 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1759 DCHECK(lookup->IsCacheableTransition());
1760 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1761 return compiler.CompileStoreTransition(transition, lookup->name());
1764 case LookupIterator::INTERCEPTOR: {
1765 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1766 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1767 return compiler.CompileStoreInterceptor(lookup->name());
1770 case LookupIterator::ACCESSOR: {
1771 if (!holder->HasFastProperties()) {
1772 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1775 Handle<Object> accessors = lookup->GetAccessors();
1776 if (accessors->IsExecutableAccessorInfo()) {
1777 Handle<ExecutableAccessorInfo> info =
1778 Handle<ExecutableAccessorInfo>::cast(accessors);
1779 if (v8::ToCData<Address>(info->setter()) == 0) {
1780 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1783 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1785 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1788 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1789 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1790 } else if (accessors->IsAccessorPair()) {
1791 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1793 if (!setter->IsJSFunction()) {
1794 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1797 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1798 CallOptimization call_optimization(function);
1799 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1800 if (call_optimization.is_simple_api_call() &&
1801 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1802 return compiler.CompileStoreCallback(receiver, lookup->name(),
1804 lookup->GetAccessorIndex());
1806 int expected_arguments =
1807 function->shared()->internal_formal_parameter_count();
1808 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
1809 lookup->GetAccessorIndex(),
1810 expected_arguments);
1815 case LookupIterator::DATA: {
1816 if (lookup->is_dictionary_holder()) {
1817 if (holder->IsGlobalObject()) {
1818 DCHECK(holder.is_identical_to(receiver) ||
1819 receiver->map()->prototype() == *holder);
1820 auto cell = lookup->GetPropertyCell();
1821 auto union_type = PropertyCell::UpdatedType(
1822 cell, value, lookup->property_details());
1823 return PropertyCellStoreHandler(isolate(), receiver,
1824 Handle<GlobalObject>::cast(holder),
1825 lookup->name(), cell, union_type);
1827 DCHECK(holder.is_identical_to(receiver));
1828 return isolate()->builtins()->StoreIC_Normal();
1831 // -------------- Fields --------------
1832 if (lookup->property_details().type() == DATA) {
1833 bool use_stub = true;
1834 if (lookup->representation().IsHeapObject()) {
1835 // Only use a generic stub if no types need to be tracked.
1836 Handle<HeapType> field_type = lookup->GetFieldType();
1837 HeapType::Iterator<Map> it = field_type->Classes();
1838 use_stub = it.Done();
1841 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1842 lookup->representation());
1843 return stub.GetCode();
1845 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1846 return compiler.CompileStoreField(lookup);
1849 // -------------- Constant properties --------------
1850 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1851 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1855 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1856 case LookupIterator::ACCESS_CHECK:
1857 case LookupIterator::JSPROXY:
1858 case LookupIterator::NOT_FOUND:
1865 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1866 KeyedAccessStoreMode store_mode) {
1867 // Don't handle megamorphic property accesses for INTERCEPTORS or
1868 // ACCESSOR_CONSTANT
1869 // via megamorphic stubs, since they don't have a map in their relocation info
1870 // and so the stubs can't be harvested for the object needed for a map check.
1871 if (target()->type() != Code::NORMAL) {
1872 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
1873 return megamorphic_stub();
1876 Handle<Map> receiver_map(receiver->map(), isolate());
1877 MapHandleList target_receiver_maps;
1878 TargetMaps(&target_receiver_maps);
1879 if (target_receiver_maps.length() == 0) {
1880 Handle<Map> monomorphic_map =
1881 ComputeTransitionedMap(receiver_map, store_mode);
1882 store_mode = GetNonTransitioningStoreMode(store_mode);
1883 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1884 monomorphic_map, language_mode(), store_mode);
1887 // There are several special cases where an IC that is MONOMORPHIC can still
1888 // transition to a different GetNonTransitioningStoreMode IC that handles a
1889 // superset of the original IC. Handle those here if the receiver map hasn't
1890 // changed or it has transitioned to a more general kind.
1891 KeyedAccessStoreMode old_store_mode =
1892 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
1893 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1894 if (state() == MONOMORPHIC) {
1895 Handle<Map> transitioned_receiver_map = receiver_map;
1896 if (IsTransitionStoreMode(store_mode)) {
1897 transitioned_receiver_map =
1898 ComputeTransitionedMap(receiver_map, store_mode);
1900 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1901 IsTransitionStoreMode(store_mode)) ||
1902 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1903 *transitioned_receiver_map)) {
1904 // If the "old" and "new" maps are in the same elements map family, or
1905 // if they at least come from the same origin for a transitioning store,
1906 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1907 store_mode = GetNonTransitioningStoreMode(store_mode);
1908 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1909 transitioned_receiver_map, language_mode(), store_mode);
1910 } else if (*previous_receiver_map == receiver->map() &&
1911 old_store_mode == STANDARD_STORE &&
1912 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1913 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1914 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1915 // A "normal" IC that handles stores can switch to a version that can
1916 // grow at the end of the array, handle OOB accesses or copy COW arrays
1917 // and still stay MONOMORPHIC.
1918 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1919 receiver_map, language_mode(), store_mode);
1923 DCHECK(state() != GENERIC);
1926 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1928 if (IsTransitionStoreMode(store_mode)) {
1929 Handle<Map> transitioned_receiver_map =
1930 ComputeTransitionedMap(receiver_map, store_mode);
1931 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1932 transitioned_receiver_map);
1936 // If the miss wasn't due to an unseen map, a polymorphic stub
1937 // won't help, use the megamorphic stub which can handle everything.
1938 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
1939 return megamorphic_stub();
1942 // If the maximum number of receiver maps has been exceeded, use the
1943 // megamorphic version of the IC.
1944 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1945 return megamorphic_stub();
1948 // Make sure all polymorphic handlers have the same store mode, otherwise the
1949 // megamorphic stub must be used.
1950 store_mode = GetNonTransitioningStoreMode(store_mode);
1951 if (old_store_mode != STANDARD_STORE) {
1952 if (store_mode == STANDARD_STORE) {
1953 store_mode = old_store_mode;
1954 } else if (store_mode != old_store_mode) {
1955 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
1956 return megamorphic_stub();
1960 // If the store mode isn't the standard mode, make sure that all polymorphic
1961 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1962 // use the megamorphic stub.
1963 if (store_mode != STANDARD_STORE) {
1964 int external_arrays = 0;
1965 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1966 if (target_receiver_maps[i]->has_external_array_elements() ||
1967 target_receiver_maps[i]->has_fixed_typed_array_elements()) {
1971 if (external_arrays != 0 &&
1972 external_arrays != target_receiver_maps.length()) {
1973 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1974 "unsupported combination of external and normal arrays");
1975 return megamorphic_stub();
1979 return PropertyICCompiler::ComputeKeyedStorePolymorphic(
1980 &target_receiver_maps, store_mode, language_mode());
1984 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1985 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1986 switch (store_mode) {
1987 case STORE_TRANSITION_SMI_TO_OBJECT:
1988 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1989 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1990 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1991 return Map::TransitionElementsTo(map, FAST_ELEMENTS);
1992 case STORE_TRANSITION_SMI_TO_DOUBLE:
1993 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1994 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS);
1995 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1996 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1997 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1998 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1999 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS);
2000 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
2001 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
2002 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
2003 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
2004 DCHECK(map->has_external_array_elements());
2006 case STORE_NO_TRANSITION_HANDLE_COW:
2007 case STANDARD_STORE:
2008 case STORE_AND_GROW_NO_TRANSITION:
2012 return MaybeHandle<Map>().ToHandleChecked();
2016 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, int index) {
2017 if (receiver->IsJSArray()) {
2018 return JSArray::cast(*receiver)->length()->IsSmi() &&
2019 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
2021 return index >= receiver->elements()->length();
2025 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
2027 Handle<Object> value) {
2028 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked();
2029 int index = smi_key->value();
2030 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2031 // Don't consider this a growing store if the store would send the receiver to
2033 bool allow_growth = receiver->IsJSArray() && oob_access &&
2034 !receiver->WouldConvertToSlowElements(key);
2036 // Handle growing array in stub if necessary.
2037 if (receiver->HasFastSmiElements()) {
2038 if (value->IsHeapNumber()) {
2039 if (receiver->HasFastHoleyElements()) {
2040 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2042 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
2045 if (value->IsHeapObject()) {
2046 if (receiver->HasFastHoleyElements()) {
2047 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
2049 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
2052 } else if (receiver->HasFastDoubleElements()) {
2053 if (!value->IsSmi() && !value->IsHeapNumber()) {
2054 if (receiver->HasFastHoleyElements()) {
2055 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2057 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
2061 return STORE_AND_GROW_NO_TRANSITION;
2063 // Handle only in-bounds elements accesses.
2064 if (receiver->HasFastSmiElements()) {
2065 if (value->IsHeapNumber()) {
2066 if (receiver->HasFastHoleyElements()) {
2067 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2069 return STORE_TRANSITION_SMI_TO_DOUBLE;
2071 } else if (value->IsHeapObject()) {
2072 if (receiver->HasFastHoleyElements()) {
2073 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
2075 return STORE_TRANSITION_SMI_TO_OBJECT;
2078 } else if (receiver->HasFastDoubleElements()) {
2079 if (!value->IsSmi() && !value->IsHeapNumber()) {
2080 if (receiver->HasFastHoleyElements()) {
2081 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2083 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
2087 if (!FLAG_trace_external_array_abuse &&
2088 receiver->map()->has_external_array_elements() && oob_access) {
2089 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2091 Heap* heap = receiver->GetHeap();
2092 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2093 return STORE_NO_TRANSITION_HANDLE_COW;
2095 return STANDARD_STORE;
2101 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2103 Handle<Object> value) {
2104 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2105 // might deprecate the current map again, if value does not fit.
2106 if (MigrateDeprecated(object)) {
2107 Handle<Object> result;
2108 ASSIGN_RETURN_ON_EXCEPTION(
2109 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2110 value, language_mode()),
2115 // Check for non-string values that can be converted into an
2116 // internalized string directly or is representable as a smi.
2117 key = TryConvertKey(key, isolate());
2119 Handle<Object> store_handle;
2120 Handle<Code> stub = megamorphic_stub();
2122 if (key->IsInternalizedString() || key->IsSymbol()) {
2123 ASSIGN_RETURN_ON_EXCEPTION(
2124 isolate(), store_handle,
2125 StoreIC::Store(object, Handle<Name>::cast(key), value,
2126 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2128 if (!is_target_set()) {
2129 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2130 "unhandled internalized string key");
2131 TRACE_IC("StoreIC", key);
2134 return store_handle;
2138 FLAG_use_ic && !object->IsStringWrapper() &&
2139 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2140 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2141 if (use_ic && !object->IsSmi()) {
2142 // Don't use ICs for maps of the objects in Array's prototype chain. We
2143 // expect to be able to trap element sets to objects with those maps in
2144 // the runtime to enable optimization of element hole access.
2145 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2146 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2147 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2153 DCHECK(!object->IsAccessCheckNeeded());
2155 if (object->IsJSObject()) {
2156 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2157 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null();
2158 if (receiver->elements()->map() ==
2159 isolate()->heap()->sloppy_arguments_elements_map()) {
2160 if (is_sloppy(language_mode())) {
2161 stub = sloppy_arguments_stub();
2163 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2165 } else if (key_is_smi_like &&
2166 !(target().is_identical_to(sloppy_arguments_stub()))) {
2167 // We should go generic if receiver isn't a dictionary, but our
2168 // prototype chain does have dictionary elements. This ensures that
2169 // other non-dictionary receivers in the polymorphic case benefit
2170 // from fast path keyed stores.
2171 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
2172 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
2173 stub = StoreElementStub(receiver, store_mode);
2175 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype");
2178 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2181 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2185 if (store_handle.is_null()) {
2186 ASSIGN_RETURN_ON_EXCEPTION(
2187 isolate(), store_handle,
2188 Runtime::SetObjectProperty(isolate(), object, key, value,
2193 DCHECK(!is_target_set());
2194 Code* megamorphic = *megamorphic_stub();
2195 if (*stub == megamorphic) {
2196 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2198 if (*stub == *slow_stub()) {
2199 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
2201 DCHECK(!stub.is_null());
2202 if (!AddressIsDeoptimizedCode()) {
2205 TRACE_IC("StoreIC", key);
2207 return store_handle;
2211 bool CallIC::DoCustomHandler(Handle<Object> function,
2212 const CallICState& callic_state) {
2213 DCHECK(FLAG_use_ic && function->IsJSFunction());
2215 // Are we the array function?
2216 Handle<JSFunction> array_function =
2217 Handle<JSFunction>(isolate()->native_context()->array_function());
2218 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
2220 CallICNexus* nexus = casted_nexus<CallICNexus>();
2221 nexus->ConfigureMonomorphicArray();
2223 // Vector-based ICs have a different calling convention in optimized code
2224 // than full code so the correct stub has to be chosen.
2225 if (AddressIsOptimizedCode()) {
2226 CallIC_ArrayStub stub(isolate(), callic_state);
2227 set_target(*stub.GetCode());
2229 CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
2230 set_target(*stub.GetCode());
2233 Handle<String> name;
2234 if (array_function->shared()->name()->IsString()) {
2235 name = Handle<String>(String::cast(array_function->shared()->name()),
2238 TRACE_IC("CallIC", name);
2239 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2247 void CallIC::PatchMegamorphic(Handle<Object> function) {
2248 CallICState callic_state(target()->extra_ic_state());
2250 // We are going generic.
2251 CallICNexus* nexus = casted_nexus<CallICNexus>();
2252 nexus->ConfigureGeneric();
2254 // Vector-based ICs have a different calling convention in optimized code
2255 // than full code so the correct stub has to be chosen.
2256 if (AddressIsOptimizedCode()) {
2257 CallICStub stub(isolate(), callic_state);
2258 set_target(*stub.GetCode());
2260 CallICTrampolineStub stub(isolate(), callic_state);
2261 set_target(*stub.GetCode());
2264 Handle<Object> name = isolate()->factory()->empty_string();
2265 if (function->IsJSFunction()) {
2266 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2267 name = handle(js_function->shared()->name(), isolate());
2270 TRACE_IC("CallIC", name);
2271 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2276 void CallIC::HandleMiss(Handle<Object> function) {
2277 CallICState callic_state(target()->extra_ic_state());
2278 Handle<Object> name = isolate()->factory()->empty_string();
2279 CallICNexus* nexus = casted_nexus<CallICNexus>();
2280 Object* feedback = nexus->GetFeedback();
2282 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2283 DCHECK(!feedback->IsSmi());
2285 if (feedback->IsWeakCell() || !function->IsJSFunction()) {
2286 // We are going generic.
2287 nexus->ConfigureGeneric();
2289 // The feedback is either uninitialized or an allocation site.
2290 // It might be an allocation site because if we re-compile the full code
2291 // to add deoptimization support, we call with the default call-ic, and
2292 // merely need to patch the target to match the feedback.
2293 // TODO(mvstanton): the better approach is to dispense with patching
2294 // altogether, which is in progress.
2295 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) ||
2296 feedback->IsAllocationSite());
2298 // Do we want to install a custom handler?
2299 if (FLAG_use_ic && DoCustomHandler(function, callic_state)) {
2303 nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
2306 if (function->IsJSFunction()) {
2307 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2308 name = handle(js_function->shared()->name(), isolate());
2311 IC::State new_state = nexus->StateFromFeedback();
2312 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
2313 TRACE_IC("CallIC", name);
2320 // ----------------------------------------------------------------------------
2321 // Static IC stub generators.
2324 // Used from ic-<arch>.cc.
2325 RUNTIME_FUNCTION(CallIC_Miss) {
2326 TimerEventScope<TimerEventIcMiss> timer(isolate);
2327 HandleScope scope(isolate);
2328 DCHECK(args.length() == 3);
2329 Handle<Object> function = args.at<Object>(0);
2330 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2331 Handle<Smi> slot = args.at<Smi>(2);
2332 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2333 CallICNexus nexus(vector, vector_slot);
2334 CallIC ic(isolate, &nexus);
2335 ic.HandleMiss(function);
2340 RUNTIME_FUNCTION(CallIC_Customization_Miss) {
2341 TimerEventScope<TimerEventIcMiss> timer(isolate);
2342 HandleScope scope(isolate);
2343 DCHECK(args.length() == 3);
2344 Handle<Object> function = args.at<Object>(0);
2345 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2346 Handle<Smi> slot = args.at<Smi>(2);
2347 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2348 CallICNexus nexus(vector, vector_slot);
2349 // A miss on a custom call ic always results in going megamorphic.
2350 CallIC ic(isolate, &nexus);
2351 ic.PatchMegamorphic(function);
2356 // Used from ic-<arch>.cc.
2357 RUNTIME_FUNCTION(LoadIC_Miss) {
2358 TimerEventScope<TimerEventIcMiss> timer(isolate);
2359 HandleScope scope(isolate);
2360 Handle<Object> receiver = args.at<Object>(0);
2361 Handle<Name> key = args.at<Name>(1);
2362 Handle<Object> result;
2364 if (FLAG_vector_ics) {
2365 DCHECK(args.length() == 4);
2366 Handle<Smi> slot = args.at<Smi>(2);
2367 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2368 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2369 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2370 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2371 // set up outside the IC, handle that here.
2372 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2373 LoadICNexus nexus(vector, vector_slot);
2374 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2375 ic.UpdateState(receiver, key);
2376 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2377 ic.Load(receiver, key));
2379 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2380 KeyedLoadICNexus nexus(vector, vector_slot);
2381 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2382 ic.UpdateState(receiver, key);
2383 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2384 ic.Load(receiver, key));
2387 DCHECK(args.length() == 2);
2388 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2389 ic.UpdateState(receiver, key);
2390 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2396 // Used from ic-<arch>.cc
2397 RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
2398 TimerEventScope<TimerEventIcMiss> timer(isolate);
2399 HandleScope scope(isolate);
2400 Handle<Object> receiver = args.at<Object>(0);
2401 Handle<Object> key = args.at<Object>(1);
2402 Handle<Object> result;
2404 if (FLAG_vector_ics) {
2405 DCHECK(args.length() == 4);
2406 Handle<Smi> slot = args.at<Smi>(2);
2407 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2408 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2409 KeyedLoadICNexus nexus(vector, vector_slot);
2410 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2411 ic.UpdateState(receiver, key);
2412 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2414 DCHECK(args.length() == 2);
2415 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2416 ic.UpdateState(receiver, key);
2417 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2424 RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
2425 TimerEventScope<TimerEventIcMiss> timer(isolate);
2426 HandleScope scope(isolate);
2427 Handle<Object> receiver = args.at<Object>(0);
2428 Handle<Object> key = args.at<Object>(1);
2429 Handle<Object> result;
2431 if (FLAG_vector_ics) {
2432 DCHECK(args.length() == 4);
2433 Handle<Smi> slot = args.at<Smi>(2);
2434 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2435 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2436 KeyedLoadICNexus nexus(vector, vector_slot);
2437 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2438 ic.UpdateState(receiver, key);
2439 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2441 DCHECK(args.length() == 2);
2442 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2443 ic.UpdateState(receiver, key);
2444 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2451 // Used from ic-<arch>.cc.
2452 RUNTIME_FUNCTION(StoreIC_Miss) {
2453 TimerEventScope<TimerEventIcMiss> timer(isolate);
2454 HandleScope scope(isolate);
2455 DCHECK(args.length() == 3);
2456 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2457 Handle<Object> receiver = args.at<Object>(0);
2458 Handle<Name> key = args.at<Name>(1);
2459 ic.UpdateState(receiver, key);
2460 Handle<Object> result;
2461 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2462 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2467 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
2468 TimerEventScope<TimerEventIcMiss> timer(isolate);
2469 HandleScope scope(isolate);
2470 DCHECK(args.length() == 3 || args.length() == 4);
2471 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2472 Handle<Object> receiver = args.at<Object>(0);
2473 Handle<Name> key = args.at<Name>(1);
2474 ic.UpdateState(receiver, key);
2475 Handle<Object> result;
2476 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2477 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2482 // Used from ic-<arch>.cc.
2483 RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
2484 TimerEventScope<TimerEventIcMiss> timer(isolate);
2485 HandleScope scope(isolate);
2486 DCHECK(args.length() == 3);
2487 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2488 Handle<Object> receiver = args.at<Object>(0);
2489 Handle<Object> key = args.at<Object>(1);
2490 ic.UpdateState(receiver, key);
2491 Handle<Object> result;
2492 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2493 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2498 RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) {
2499 TimerEventScope<TimerEventIcMiss> timer(isolate);
2500 HandleScope scope(isolate);
2501 DCHECK(args.length() == 3);
2502 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2503 Handle<Object> receiver = args.at<Object>(0);
2504 Handle<Object> key = args.at<Object>(1);
2505 ic.UpdateState(receiver, key);
2506 Handle<Object> result;
2507 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2508 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2513 RUNTIME_FUNCTION(StoreIC_Slow) {
2514 HandleScope scope(isolate);
2515 DCHECK(args.length() == 3);
2516 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2517 Handle<Object> object = args.at<Object>(0);
2518 Handle<Object> key = args.at<Object>(1);
2519 Handle<Object> value = args.at<Object>(2);
2520 LanguageMode language_mode = ic.language_mode();
2521 Handle<Object> result;
2522 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2524 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2529 RUNTIME_FUNCTION(KeyedStoreIC_Slow) {
2530 HandleScope scope(isolate);
2531 DCHECK(args.length() == 3);
2532 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2533 Handle<Object> object = args.at<Object>(0);
2534 Handle<Object> key = args.at<Object>(1);
2535 Handle<Object> value = args.at<Object>(2);
2536 LanguageMode language_mode = ic.language_mode();
2537 Handle<Object> result;
2538 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2540 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2545 RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) {
2546 TimerEventScope<TimerEventIcMiss> timer(isolate);
2547 HandleScope scope(isolate);
2548 DCHECK(args.length() == 4);
2549 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2550 Handle<Object> value = args.at<Object>(0);
2551 Handle<Map> map = args.at<Map>(1);
2552 Handle<Object> key = args.at<Object>(2);
2553 Handle<Object> object = args.at<Object>(3);
2554 LanguageMode language_mode = ic.language_mode();
2555 if (object->IsJSObject()) {
2556 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2557 map->elements_kind());
2559 Handle<Object> result;
2560 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2562 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2567 MaybeHandle<Object> BinaryOpIC::Transition(
2568 Handle<AllocationSite> allocation_site, Handle<Object> left,
2569 Handle<Object> right) {
2570 BinaryOpICState state(isolate(), target()->extra_ic_state());
2572 // Compute the actual result using the builtin for the binary operation.
2573 Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
2574 TokenToJSBuiltin(state.op()));
2575 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
2576 Handle<Object> result;
2577 ASSIGN_RETURN_ON_EXCEPTION(
2578 isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
2581 // Do not try to update the target if the code was marked for lazy
2582 // deoptimization. (Since we do not relocate addresses in these
2583 // code objects, an attempt to access the target could fail.)
2584 if (AddressIsDeoptimizedCode()) {
2588 // Execution::Call can execute arbitrary JavaScript, hence potentially
2589 // update the state of this very IC, so we must update the stored state.
2592 // Compute the new state.
2593 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2594 state.Update(left, right, result);
2596 // Check if we have a string operation here.
2597 Handle<Code> target;
2598 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2599 // Setup the allocation site on-demand.
2600 if (allocation_site.is_null()) {
2601 allocation_site = isolate()->factory()->NewAllocationSite();
2604 // Install the stub with an allocation site.
2605 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2606 target = stub.GetCodeCopyFromTemplate(allocation_site);
2608 // Sanity check the trampoline stub.
2609 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2611 // Install the generic stub.
2612 BinaryOpICStub stub(isolate(), state);
2613 target = stub.GetCode();
2615 // Sanity check the generic stub.
2616 DCHECK_NULL(target->FindFirstAllocationSite());
2618 set_target(*target);
2620 if (FLAG_trace_ic) {
2621 OFStream os(stdout);
2622 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2623 << static_cast<void*>(*target) << " <- ";
2624 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2625 if (!allocation_site.is_null()) {
2626 os << " using allocation site " << static_cast<void*>(*allocation_site);
2628 os << "]" << std::endl;
2631 // Patch the inlined smi code as necessary.
2632 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2633 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2634 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2635 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2642 RUNTIME_FUNCTION(BinaryOpIC_Miss) {
2643 TimerEventScope<TimerEventIcMiss> timer(isolate);
2644 HandleScope scope(isolate);
2645 DCHECK_EQ(2, args.length());
2646 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2647 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2648 BinaryOpIC ic(isolate);
2649 Handle<Object> result;
2650 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2652 ic.Transition(Handle<AllocationSite>::null(), left, right));
2657 RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) {
2658 TimerEventScope<TimerEventIcMiss> timer(isolate);
2659 HandleScope scope(isolate);
2660 DCHECK_EQ(3, args.length());
2661 Handle<AllocationSite> allocation_site =
2662 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2663 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2664 Handle<Object> right =
2665 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2666 BinaryOpIC ic(isolate);
2667 Handle<Object> result;
2668 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2669 isolate, result, ic.Transition(allocation_site, left, right));
2674 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2675 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2676 CompareICState::UNINITIALIZED,
2677 CompareICState::UNINITIALIZED);
2679 CHECK(stub.FindCodeInCache(&code));
2684 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2685 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2686 CompareICState::UNINITIALIZED,
2687 CompareICState::UNINITIALIZED);
2688 return stub.GetCode();
2692 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2693 HandleScope scope(isolate());
2694 CompareICStub old_stub(target()->stub_key(), isolate());
2695 CompareICState::State new_left =
2696 CompareICState::NewInputState(old_stub.left(), x);
2697 CompareICState::State new_right =
2698 CompareICState::NewInputState(old_stub.right(), y);
2699 CompareICState::State state = CompareICState::TargetState(
2700 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2701 HasInlinedSmiCode(address()), x, y);
2702 CompareICStub stub(isolate(), op_, new_left, new_right, state);
2703 if (state == CompareICState::KNOWN_OBJECT) {
2705 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2707 Handle<Code> new_target = stub.GetCode();
2708 set_target(*new_target);
2710 if (FLAG_trace_ic) {
2711 PrintF("[CompareIC in ");
2712 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2713 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2714 CompareICState::GetStateName(old_stub.left()),
2715 CompareICState::GetStateName(old_stub.right()),
2716 CompareICState::GetStateName(old_stub.state()),
2717 CompareICState::GetStateName(new_left),
2718 CompareICState::GetStateName(new_right),
2719 CompareICState::GetStateName(state), Token::Name(op_),
2720 static_cast<void*>(*stub.GetCode()));
2723 // Activate inlined smi code.
2724 if (old_stub.state() == CompareICState::UNINITIALIZED) {
2725 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2732 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2733 RUNTIME_FUNCTION(CompareIC_Miss) {
2734 TimerEventScope<TimerEventIcMiss> timer(isolate);
2735 HandleScope scope(isolate);
2736 DCHECK(args.length() == 3);
2737 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2738 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2742 void CompareNilIC::Clear(Address address, Code* target,
2743 ConstantPoolArray* constant_pool) {
2744 if (IsCleared(target)) return;
2745 ExtraICState state = target->extra_ic_state();
2747 CompareNilICStub stub(target->GetIsolate(), state,
2748 HydrogenCodeStub::UNINITIALIZED);
2752 CHECK(stub.FindCodeInCache(&code));
2754 SetTargetAtAddress(address, code, constant_pool);
2758 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2759 Handle<Object> object) {
2760 if (object->IsNull() || object->IsUndefined()) {
2761 return handle(Smi::FromInt(true), isolate);
2763 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate);
2767 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2768 ExtraICState extra_ic_state = target()->extra_ic_state();
2770 CompareNilICStub stub(isolate(), extra_ic_state);
2772 // Extract the current supported types from the patched IC and calculate what
2773 // types must be supported as a result of the miss.
2774 bool already_monomorphic = stub.IsMonomorphic();
2776 stub.UpdateStatus(object);
2778 NilValue nil = stub.nil_value();
2780 // Find or create the specialized stub to support the new set of types.
2782 if (stub.IsMonomorphic()) {
2783 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2785 : HeapObject::cast(*object)->map());
2786 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2788 code = stub.GetCode();
2791 return DoCompareNilSlow(isolate(), nil, object);
2795 RUNTIME_FUNCTION(CompareNilIC_Miss) {
2796 TimerEventScope<TimerEventIcMiss> timer(isolate);
2797 HandleScope scope(isolate);
2798 Handle<Object> object = args.at<Object>(0);
2799 CompareNilIC ic(isolate);
2800 return *ic.CompareNil(object);
2804 RUNTIME_FUNCTION(Unreachable) {
2807 return isolate->heap()->undefined_value();
2811 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2816 return Builtins::ADD;
2819 return Builtins::SUB;
2822 return Builtins::MUL;
2825 return Builtins::DIV;
2828 return Builtins::MOD;
2831 return Builtins::BIT_OR;
2833 case Token::BIT_AND:
2834 return Builtins::BIT_AND;
2836 case Token::BIT_XOR:
2837 return Builtins::BIT_XOR;
2840 return Builtins::SAR;
2843 return Builtins::SHR;
2846 return Builtins::SHL;
2852 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2853 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2854 bool to_boolean_value = stub.UpdateStatus(object);
2855 Handle<Code> code = stub.GetCode();
2857 return handle(Smi::FromInt(to_boolean_value ? 1 : 0), isolate());
2861 RUNTIME_FUNCTION(ToBooleanIC_Miss) {
2862 TimerEventScope<TimerEventIcMiss> timer(isolate);
2863 DCHECK(args.length() == 1);
2864 HandleScope scope(isolate);
2865 Handle<Object> object = args.at<Object>(0);
2866 ToBooleanIC ic(isolate);
2867 return *ic.ToBoolean(object);
2871 RUNTIME_FUNCTION(StoreCallbackProperty) {
2872 Handle<JSObject> receiver = args.at<JSObject>(0);
2873 Handle<JSObject> holder = args.at<JSObject>(1);
2874 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
2875 Handle<Name> name = args.at<Name>(3);
2876 Handle<Object> value = args.at<Object>(4);
2877 HandleScope scope(isolate);
2879 Handle<ExecutableAccessorInfo> callback(
2880 callback_or_cell->IsWeakCell()
2881 ? ExecutableAccessorInfo::cast(
2882 WeakCell::cast(*callback_or_cell)->value())
2883 : ExecutableAccessorInfo::cast(*callback_or_cell));
2885 DCHECK(callback->IsCompatibleReceiver(*receiver));
2887 Address setter_address = v8::ToCData<Address>(callback->setter());
2888 v8::AccessorNameSetterCallback fun =
2889 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2890 DCHECK(fun != NULL);
2892 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2893 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2895 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2896 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2902 * Attempts to load a property with an interceptor (which must be present),
2903 * but doesn't search the prototype chain.
2905 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2906 * provide any value for the given name.
2908 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
2909 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2911 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2912 Handle<JSObject> receiver =
2913 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2914 Handle<JSObject> holder =
2915 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2916 HandleScope scope(isolate);
2917 auto res = JSObject::GetPropertyWithInterceptor(holder, receiver, name);
2918 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2919 Handle<Object> result;
2920 if (res.ToHandle(&result)) return *result;
2921 return isolate->heap()->no_interceptor_result_sentinel();
2925 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
2926 // If the load is non-contextual, just return the undefined result.
2927 // Note that both keyed and non-keyed loads may end up here.
2928 HandleScope scope(isolate);
2929 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
2930 if (ic.contextual_mode() != CONTEXTUAL) {
2931 return isolate->heap()->undefined_value();
2934 // Throw a reference error.
2935 Handle<Name> name_handle(name);
2936 THROW_NEW_ERROR_RETURN_FAILURE(
2937 isolate, NewReferenceError("not_defined", HandleVector(&name_handle, 1)));
2942 * Loads a property with an interceptor performing post interceptor
2943 * lookup if interceptor failed.
2945 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
2946 HandleScope scope(isolate);
2947 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2949 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2950 Handle<JSObject> receiver =
2951 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2952 Handle<JSObject> holder =
2953 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2955 Handle<Object> result;
2956 LookupIterator it(receiver, name, holder);
2957 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2958 JSObject::GetProperty(&it));
2960 if (it.IsFound()) return *result;
2962 return ThrowReferenceError(isolate, Name::cast(args[0]));
2966 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
2967 HandleScope scope(isolate);
2968 DCHECK(args.length() == 3);
2969 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2970 Handle<JSObject> receiver = args.at<JSObject>(0);
2971 Handle<Name> name = args.at<Name>(1);
2972 Handle<Object> value = args.at<Object>(2);
2974 PrototypeIterator iter(isolate, receiver,
2975 PrototypeIterator::START_AT_RECEIVER);
2977 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
2978 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2979 if (current->IsJSObject() &&
2980 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2987 Handle<Object> result;
2988 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2990 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
2995 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
2996 HandleScope scope(isolate);
2997 Handle<JSObject> receiver = args.at<JSObject>(0);
2998 DCHECK(args.smi_at(1) >= 0);
2999 uint32_t index = args.smi_at(1);
3000 Handle<Object> result;
3001 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3003 JSObject::GetElementWithInterceptor(receiver, receiver, index, true));
3008 RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
3009 TimerEventScope<TimerEventIcMiss> timer(isolate);
3010 HandleScope scope(isolate);
3011 Handle<Object> receiver = args.at<Object>(0);
3012 Handle<Name> key = args.at<Name>(1);
3013 Handle<Object> result;
3015 if (FLAG_vector_ics) {
3016 DCHECK(args.length() == 4);
3017 Handle<Smi> slot = args.at<Smi>(2);
3018 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
3019 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
3020 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
3021 // LoadIC miss handler if the handler misses. Since the vector Nexus is
3022 // set up outside the IC, handle that here.
3023 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
3024 LoadICNexus nexus(vector, vector_slot);
3025 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
3026 ic.UpdateState(receiver, key);
3027 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3028 ic.Load(receiver, key));
3030 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
3031 KeyedLoadICNexus nexus(vector, vector_slot);
3032 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
3033 ic.UpdateState(receiver, key);
3034 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3035 ic.Load(receiver, key));
3038 DCHECK(args.length() == 2);
3039 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
3040 ic.UpdateState(receiver, key);
3041 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
3048 static const Address IC_utilities[] = {
3049 #define ADDR(name) FUNCTION_ADDR(name),
3050 IC_UTIL_LIST(ADDR) NULL
3055 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; }
3057 } // namespace v8::internal