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 static void LookupForRead(LookupIterator* it) {
234 for (; it->IsFound(); it->Next()) {
235 switch (it->state()) {
236 case LookupIterator::NOT_FOUND:
237 case LookupIterator::TRANSITION:
239 case LookupIterator::JSPROXY:
241 case LookupIterator::INTERCEPTOR: {
242 // If there is a getter, return; otherwise loop to perform the lookup.
243 Handle<JSObject> holder = it->GetHolder<JSObject>();
244 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
249 case LookupIterator::ACCESS_CHECK:
250 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
251 // access checks for global proxies.
252 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() &&
253 it->HasAccess(v8::ACCESS_GET)) {
257 case LookupIterator::ACCESSOR:
258 case LookupIterator::DATA:
265 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
266 Handle<String> name) {
267 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
269 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
271 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
274 // The current map wasn't handled yet. There's no reason to stay monomorphic,
275 // *unless* we're moving from a deprecated map to its replacement, or
276 // to a more general elements kind.
277 // TODO(verwaest): Check if the current map is actually what the old map
278 // would transition to.
279 if (maybe_handler_.is_null()) {
280 if (!receiver_map()->IsJSObjectMap()) return false;
281 Map* first_map = FirstTargetMap();
282 if (first_map == NULL) return false;
283 Handle<Map> old_map(first_map);
284 if (old_map->is_deprecated()) return true;
285 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
286 receiver_map()->elements_kind())) {
292 CacheHolderFlag flag;
293 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
295 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
296 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
297 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
299 if (state() == MONOMORPHIC) {
300 int index = ic_holder_map->IndexInCodeCache(*name, *target());
302 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
306 if (receiver->IsGlobalObject()) {
307 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
308 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
309 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
310 if (!it.IsFound()) return false;
311 Handle<PropertyCell> cell = it.GetPropertyCell();
312 return cell->type()->IsConstant();
319 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
320 if (target()->is_keyed_stub()) {
321 // Determine whether the failure is due to a name failure.
322 if (!name->IsName()) return false;
324 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
325 if (*name != stub_name) return false;
332 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
333 update_receiver_map(receiver);
334 if (!name->IsString()) return;
335 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
336 if (receiver->IsUndefined() || receiver->IsNull()) return;
338 // Remove the target from the code cache if it became invalid
339 // because of changes in the prototype chain to avoid hitting it
341 if (TryRemoveInvalidPrototypeDependentStub(receiver,
342 Handle<String>::cast(name))) {
343 MarkPrototypeFailure(name);
347 // The builtins object is special. It only changes when JavaScript
348 // builtins are loaded lazily. It is important to keep inline
349 // caches for the builtins object monomorphic. Therefore, if we get
350 // an inline cache miss for the builtins object after lazily loading
351 // JavaScript builtins, we return uninitialized as the state to
352 // force the inline cache back to monomorphic state.
353 if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
357 MaybeHandle<Object> IC::TypeError(const char* type, Handle<Object> object,
358 Handle<Object> key) {
359 HandleScope scope(isolate());
360 Handle<Object> args[2] = {key, object};
361 THROW_NEW_ERROR(isolate(), NewTypeError(type, HandleVector(args, 2)), Object);
365 MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) {
366 HandleScope scope(isolate());
367 THROW_NEW_ERROR(isolate(), NewReferenceError(type, HandleVector(&name, 1)),
372 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
373 int* polymorphic_delta,
374 int* generic_delta) {
378 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
379 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
380 *polymorphic_delta = 1;
381 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
387 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
388 *polymorphic_delta = -1;
389 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
395 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
397 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
398 *polymorphic_delta = 1;
401 case PROTOTYPE_FAILURE:
409 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
410 State old_state, State new_state,
411 bool target_remains_ic_stub) {
413 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
414 if (host->kind() != Code::FUNCTION) return;
416 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
417 // Not all Code objects have TypeFeedbackInfo.
418 host->type_feedback_info()->IsTypeFeedbackInfo()) {
419 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
420 int generic_delta = 0; // "Generic" here includes megamorphic.
421 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
423 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
424 info->change_ic_with_type_info_count(polymorphic_delta);
425 info->change_ic_generic_count(generic_delta);
427 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
428 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
429 info->change_own_type_change_checksum();
431 host->set_profiler_ticks(0);
432 isolate->runtime_profiler()->NotifyICChanged();
433 // TODO(2029): When an optimized function is patched, it would
434 // be nice to propagate the corresponding type information to its
435 // unoptimized version for the benefit of later inlining.
440 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
441 TypeFeedbackVector* vector, State old_state,
443 if (host->kind() != Code::FUNCTION) return;
445 if (FLAG_type_info_threshold > 0) {
446 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
447 int generic_delta = 0; // "Generic" here includes megamorphic.
448 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
450 vector->change_ic_with_type_info_count(polymorphic_delta);
451 vector->change_ic_generic_count(generic_delta);
453 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
454 info->change_own_type_change_checksum();
455 host->set_profiler_ticks(0);
456 isolate->runtime_profiler()->NotifyICChanged();
457 // TODO(2029): When an optimized function is patched, it would
458 // be nice to propagate the corresponding type information to its
459 // unoptimized version for the benefit of later inlining.
463 void IC::PostPatching(Address address, Code* target, Code* old_target) {
464 // Type vector based ICs update these statistics at a different time because
465 // they don't always patch on state change.
466 if (ICUseVector(target->kind())) return;
468 Isolate* isolate = target->GetHeap()->isolate();
469 State old_state = UNINITIALIZED;
470 State new_state = UNINITIALIZED;
471 bool target_remains_ic_stub = false;
472 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
473 old_state = old_target->ic_state();
474 new_state = target->ic_state();
475 target_remains_ic_stub = true;
478 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
479 target_remains_ic_stub);
483 void IC::Clear(Isolate* isolate, Address address,
484 ConstantPoolArray* constant_pool) {
485 Code* target = GetTargetAtAddress(address, constant_pool);
487 // Don't clear debug break inline cache as it will remove the break point.
488 if (target->is_debug_stub()) return;
490 switch (target->kind()) {
492 if (FLAG_vector_ics) return;
493 return LoadIC::Clear(isolate, address, target, constant_pool);
494 case Code::KEYED_LOAD_IC:
495 if (FLAG_vector_ics) return;
496 return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
498 return StoreIC::Clear(isolate, address, target, constant_pool);
499 case Code::KEYED_STORE_IC:
500 return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
501 case Code::COMPARE_IC:
502 return CompareIC::Clear(isolate, address, target, constant_pool);
503 case Code::COMPARE_NIL_IC:
504 return CompareNilIC::Clear(address, target, constant_pool);
505 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
506 case Code::BINARY_OP_IC:
507 case Code::TO_BOOLEAN_IC:
508 // Clearing these is tricky and does not
509 // make any performance difference.
517 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
518 ConstantPoolArray* constant_pool) {
519 DCHECK(!FLAG_vector_ics);
520 if (IsCleared(target)) return;
522 // Make sure to also clear the map used in inline fast cases. If we
523 // do not clear these maps, cached code can keep objects alive
524 // through the embedded maps.
525 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
529 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
530 if (IsCleared(nexus)) return;
531 // Make sure to also clear the map used in inline fast cases. If we
532 // do not clear these maps, cached code can keep objects alive
533 // through the embedded maps.
534 State state = nexus->StateFromFeedback();
535 nexus->ConfigurePremonomorphic();
536 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
540 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
541 // Determine our state.
542 Object* feedback = nexus->vector()->Get(nexus->slot());
543 State state = nexus->StateFromFeedback();
545 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
546 nexus->ConfigureUninitialized();
547 // The change in state must be processed.
548 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
553 void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
554 ConstantPoolArray* constant_pool) {
555 DCHECK(!FLAG_vector_ics);
556 if (IsCleared(target)) return;
557 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC,
558 target->extra_ic_state());
559 SetTargetAtAddress(address, code, constant_pool);
563 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
564 if (IsCleared(nexus)) return;
565 State state = nexus->StateFromFeedback();
566 nexus->ConfigurePremonomorphic();
567 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
571 void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
572 ConstantPoolArray* constant_pool) {
573 if (IsCleared(target)) return;
574 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
575 target->extra_ic_state());
576 SetTargetAtAddress(address, code, constant_pool);
580 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
581 ConstantPoolArray* constant_pool) {
582 if (IsCleared(target)) return;
584 address, *pre_monomorphic_stub(
585 isolate, StoreIC::GetLanguageMode(target->extra_ic_state())),
590 void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
591 ConstantPoolArray* constant_pool) {
592 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
593 CompareICStub stub(target->stub_key(), isolate);
594 // Only clear CompareICs that can retain objects.
595 if (stub.state() != CompareICState::KNOWN_OBJECT) return;
596 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
598 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
603 Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate) {
604 if (FLAG_compiled_keyed_generic_loads) {
605 return KeyedLoadGenericStub(isolate).GetCode();
607 return isolate->builtins()->KeyedLoadIC_Megamorphic();
612 static bool MigrateDeprecated(Handle<Object> object) {
613 if (!object->IsJSObject()) return false;
614 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
615 if (!receiver->map()->is_deprecated()) return false;
616 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
621 void IC::ConfigureVectorState(IC::State new_state) {
623 if (kind() == Code::LOAD_IC) {
624 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
625 if (new_state == PREMONOMORPHIC) {
626 nexus->ConfigurePremonomorphic();
627 } else if (new_state == MEGAMORPHIC) {
628 nexus->ConfigureMegamorphic();
632 } else if (kind() == Code::KEYED_LOAD_IC) {
633 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
634 if (new_state == PREMONOMORPHIC) {
635 nexus->ConfigurePremonomorphic();
636 } else if (new_state == MEGAMORPHIC) {
637 nexus->ConfigureMegamorphic();
646 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
651 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
652 Handle<Code> handler) {
654 if (kind() == Code::LOAD_IC) {
655 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
656 nexus->ConfigureMonomorphic(map, handler);
658 DCHECK(kind() == Code::KEYED_LOAD_IC);
659 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
660 nexus->ConfigureMonomorphic(name, map, handler);
664 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
669 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
670 CodeHandleList* handlers) {
672 if (kind() == Code::LOAD_IC) {
673 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
674 nexus->ConfigurePolymorphic(maps, handlers);
676 DCHECK(kind() == Code::KEYED_LOAD_IC);
677 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
678 nexus->ConfigurePolymorphic(name, maps, handlers);
682 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
687 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
688 // If the object is undefined or null it's illegal to try to get any
689 // of its properties; throw a TypeError in that case.
690 if (object->IsUndefined() || object->IsNull()) {
691 return TypeError("non_object_property_load", object, name);
694 // Check if the name is trivially convertible to an index and get
695 // the element or char if so.
697 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
698 // Rewrite to the generic keyed load stub.
701 ConfigureVectorState(MEGAMORPHIC);
703 set_target(*megamorphic_stub());
705 TRACE_IC("LoadIC", name);
706 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
708 Handle<Object> result;
709 ASSIGN_RETURN_ON_EXCEPTION(
711 Runtime::GetElementOrCharAt(isolate(), object, index), Object);
715 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
717 if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
718 // Look up in script context table.
719 Handle<String> str_name = Handle<String>::cast(name);
720 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
721 Handle<ScriptContextTable> script_contexts(
722 global->native_context()->script_context_table());
724 ScriptContextTable::LookupResult lookup_result;
725 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
726 Handle<Object> result =
727 FixedArray::get(ScriptContextTable::GetContext(
728 script_contexts, lookup_result.context_index),
729 lookup_result.slot_index);
730 if (*result == *isolate()->factory()->the_hole_value()) {
731 // Do not install stubs and stay pre-monomorphic for
732 // uninitialized accesses.
733 return ReferenceError("not_defined", name);
736 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
737 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
738 PatchCache(name, stub.GetCode());
744 // Named lookup in the object.
745 LookupIterator it(object, name);
748 if (it.IsFound() || !IsUndeclaredGlobal(object)) {
749 // Update inline cache and stub cache.
750 if (use_ic) UpdateCaches(&it);
753 Handle<Object> result;
754 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
758 } else if (!IsUndeclaredGlobal(object)) {
759 LOG(isolate(), SuspectReadEvent(*name, *object));
763 return ReferenceError("not_defined", name);
767 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
768 Handle<Map> new_receiver_map) {
769 DCHECK(!new_receiver_map.is_null());
770 for (int current = 0; current < receiver_maps->length(); ++current) {
771 if (!receiver_maps->at(current).is_null() &&
772 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
776 receiver_maps->Add(new_receiver_map);
781 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
782 if (!code->is_handler()) return false;
783 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
784 Handle<Map> map = receiver_map();
786 CodeHandleList handlers;
789 int number_of_maps = maps.length();
790 int deprecated_maps = 0;
791 int handler_to_overwrite = -1;
793 for (int i = 0; i < number_of_maps; i++) {
794 Handle<Map> current_map = maps.at(i);
795 if (current_map->is_deprecated()) {
796 // Filter out deprecated maps to ensure their instances get migrated.
798 } else if (map.is_identical_to(current_map)) {
799 // If the receiver type is already in the polymorphic IC, this indicates
800 // there was a prototoype chain failure. In that case, just overwrite the
802 handler_to_overwrite = i;
803 } else if (handler_to_overwrite == -1 &&
804 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
805 handler_to_overwrite = i;
809 int number_of_valid_maps =
810 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
812 if (number_of_valid_maps >= 4) return false;
813 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
817 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
819 if (!target()->FindHandlers(&handlers, maps.length())) return false;
822 number_of_valid_maps++;
823 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
825 if (number_of_valid_maps == 1) {
827 ConfigureVectorState(name, receiver_map(), code);
829 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, map, code,
833 if (handler_to_overwrite >= 0) {
834 handlers.Set(handler_to_overwrite, code);
835 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
836 maps.Set(handler_to_overwrite, map);
844 ConfigureVectorState(name, &maps, &handlers);
846 ic = PropertyICCompiler::ComputePolymorphic(kind(), &maps, &handlers,
847 number_of_valid_maps, name,
852 if (!UseVector()) set_target(*ic);
857 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
858 DCHECK(handler->is_handler());
860 ConfigureVectorState(name, receiver_map(), handler);
862 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
863 kind(), name, receiver_map(), handler, extra_ic_state());
869 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
871 CodeHandleList handlers;
873 if (!target()->FindHandlers(&handlers, maps.length())) return;
874 for (int i = 0; i < maps.length(); i++) {
875 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
880 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
881 if (source_map == NULL) return true;
882 if (target_map == NULL) return false;
883 ElementsKind target_elements_kind = target_map->elements_kind();
884 bool more_general_transition = IsMoreGeneralElementsKindTransition(
885 source_map->elements_kind(), target_elements_kind);
886 Map* transitioned_map =
887 more_general_transition
888 ? source_map->LookupElementsTransitionMap(target_elements_kind)
891 return transitioned_map == target_map;
895 void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
899 UpdateMonomorphicIC(code, name);
901 case PROTOTYPE_FAILURE:
904 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
905 if (UpdatePolymorphicIC(name, code)) break;
906 // For keyed stubs, we can't know whether old handlers were for the
908 CopyICToMegamorphicCache(name);
911 ConfigureVectorState(MEGAMORPHIC);
913 set_target(*megamorphic_stub());
917 UpdateMegamorphicCache(*receiver_map(), *name, *code);
918 // Indicate that we've handled this case.
935 Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
936 ExtraICState extra_state) {
937 if (FLAG_vector_ics) {
938 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
941 return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state);
945 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
946 Isolate* isolate, ExtraICState extra_state) {
947 if (FLAG_vector_ics) {
948 return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
950 return initialize_stub(isolate, extra_state);
954 Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
955 if (FLAG_vector_ics) {
956 return KeyedLoadICTrampolineStub(isolate).GetCode();
959 return isolate->builtins()->KeyedLoadIC_Initialize();
963 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
964 if (FLAG_vector_ics) {
965 return VectorKeyedLoadStub(isolate).GetCode();
967 return initialize_stub(isolate);
971 Handle<Code> LoadIC::megamorphic_stub() {
972 if (kind() == Code::LOAD_IC) {
973 MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state()));
974 return stub.GetCode();
976 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
977 return KeyedLoadIC::ChooseMegamorphicStub(isolate());
982 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
983 ExtraICState extra_state) {
984 DCHECK(!FLAG_vector_ics);
985 return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
989 Handle<Code> KeyedLoadIC::pre_monomorphic_stub(Isolate* isolate) {
990 return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
994 Handle<Code> LoadIC::pre_monomorphic_stub() const {
995 if (kind() == Code::LOAD_IC) {
996 return LoadIC::pre_monomorphic_stub(isolate(), extra_ic_state());
998 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
999 return KeyedLoadIC::pre_monomorphic_stub(isolate());
1004 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
1005 LoadFieldStub stub(isolate(), index);
1006 return stub.GetCode();
1010 void LoadIC::UpdateCaches(LookupIterator* lookup) {
1011 if (state() == UNINITIALIZED) {
1012 // This is the first time we execute this inline cache. Set the target to
1013 // the pre monomorphic stub to delay setting the monomorphic state.
1015 ConfigureVectorState(PREMONOMORPHIC);
1017 set_target(*pre_monomorphic_stub());
1019 TRACE_IC("LoadIC", lookup->name());
1024 if (lookup->state() == LookupIterator::JSPROXY ||
1025 lookup->state() == LookupIterator::ACCESS_CHECK) {
1027 } else if (!lookup->IsFound()) {
1028 if (kind() == Code::LOAD_IC) {
1029 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
1031 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1032 if (code.is_null()) code = slow_stub();
1037 code = ComputeHandler(lookup);
1040 PatchCache(lookup->name(), code);
1041 TRACE_IC("LoadIC", lookup->name());
1045 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1046 isolate()->stub_cache()->Set(name, map, code);
1050 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1051 bool receiver_is_holder =
1052 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1053 CacheHolderFlag flag;
1054 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
1055 receiver_map(), receiver_is_holder, isolate(), &flag);
1057 Handle<Code> code = PropertyHandlerCompiler::Find(
1058 lookup->name(), stub_holder_map, kind(), flag,
1059 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1060 // Use the cached value if it exists, and if it is different from the
1061 // handler that just missed.
1062 if (!code.is_null()) {
1063 if (!maybe_handler_.is_null() &&
1064 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1067 if (maybe_handler_.is_null()) {
1068 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1069 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1070 // cache (which just missed) is different from the cached handler.
1071 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1072 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1073 Code* megamorphic_cached_code =
1074 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1075 if (megamorphic_cached_code != *code) return code;
1082 code = CompileHandler(lookup, value, flag);
1083 DCHECK(code->is_handler());
1085 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1086 // code compiled for this map, otherwise it's already cached in the global
1088 // cache. We are also guarding against installing code with flags that don't
1089 // match the desired CacheHolderFlag computed above, which would lead to
1090 // invalid lookups later.
1091 if (code->type() != Code::NORMAL &&
1092 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1093 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1100 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1101 Handle<Object> unused,
1102 CacheHolderFlag cache_holder) {
1103 Handle<Object> receiver = lookup->GetReceiver();
1104 if (receiver->IsString() &&
1105 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1106 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1107 return SimpleFieldLoad(index);
1110 if (receiver->IsStringWrapper() &&
1111 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1112 StringLengthStub string_length_stub(isolate());
1113 return string_length_stub.GetCode();
1116 // Use specialized code for getting prototype of functions.
1117 if (receiver->IsJSFunction() &&
1118 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1119 Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
1120 !Handle<JSFunction>::cast(receiver)
1122 ->has_non_instance_prototype()) {
1124 FunctionPrototypeStub function_prototype_stub(isolate());
1125 return function_prototype_stub.GetCode();
1128 Handle<Map> map = receiver_map();
1129 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1130 bool receiver_is_holder = receiver.is_identical_to(holder);
1131 switch (lookup->state()) {
1132 case LookupIterator::INTERCEPTOR: {
1133 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1134 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1135 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1136 // the original iterator will be used to fetch the value.
1137 LookupIterator it = *lookup;
1140 return compiler.CompileLoadInterceptor(&it);
1143 case LookupIterator::ACCESSOR: {
1144 // Use simple field loads for some well-known callback properties.
1145 if (receiver_is_holder) {
1146 DCHECK(receiver->IsJSObject());
1147 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
1149 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1152 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map());
1153 return SimpleFieldLoad(index);
1157 Handle<Object> accessors = lookup->GetAccessors();
1158 if (accessors->IsExecutableAccessorInfo()) {
1159 Handle<ExecutableAccessorInfo> info =
1160 Handle<ExecutableAccessorInfo>::cast(accessors);
1161 if (v8::ToCData<Address>(info->getter()) == 0) break;
1162 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1166 if (!holder->HasFastProperties()) break;
1167 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1168 return compiler.CompileLoadCallback(lookup->name(), info);
1170 if (accessors->IsAccessorPair()) {
1171 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1173 if (!getter->IsJSFunction()) break;
1174 if (!holder->HasFastProperties()) break;
1175 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1176 if (!receiver->IsJSObject() && !function->IsBuiltin() &&
1177 is_sloppy(function->shared()->language_mode())) {
1178 // Calling sloppy non-builtins with a value as the receiver
1182 CallOptimization call_optimization(function);
1183 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1184 if (call_optimization.is_simple_api_call() &&
1185 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1186 return compiler.CompileLoadCallback(lookup->name(), call_optimization,
1187 lookup->GetAccessorIndex());
1189 int expected_arguments =
1190 function->shared()->internal_formal_parameter_count();
1191 return compiler.CompileLoadViaGetter(
1192 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1197 case LookupIterator::DATA: {
1198 if (lookup->is_dictionary_holder()) {
1199 if (kind() != Code::LOAD_IC) break;
1200 if (holder->IsGlobalObject()) {
1201 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1203 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1204 Handle<Code> code = compiler.CompileLoadGlobal(
1205 cell, lookup->name(), lookup->IsConfigurable());
1206 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1207 CacheHolderFlag flag;
1208 Handle<Map> stub_holder_map =
1209 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
1210 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1213 // There is only one shared stub for loading normalized
1214 // properties. It does not traverse the prototype chain, so the
1215 // property must be found in the object for the stub to be
1217 if (!receiver_is_holder) break;
1218 return isolate()->builtins()->LoadIC_Normal();
1221 // -------------- Fields --------------
1222 if (lookup->property_details().type() == DATA) {
1223 FieldIndex field = lookup->GetFieldIndex();
1224 if (receiver_is_holder) {
1225 return SimpleFieldLoad(field);
1227 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1228 return compiler.CompileLoadField(lookup->name(), field);
1231 // -------------- Constant properties --------------
1232 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1233 if (receiver_is_holder) {
1234 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1235 return stub.GetCode();
1237 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1238 return compiler.CompileLoadConstant(lookup->name(),
1239 lookup->GetConstantIndex());
1242 case LookupIterator::ACCESS_CHECK:
1243 case LookupIterator::JSPROXY:
1244 case LookupIterator::NOT_FOUND:
1245 case LookupIterator::TRANSITION:
1253 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1254 // This helper implements a few common fast cases for converting
1255 // non-smi keys of keyed loads/stores to a smi or a string.
1256 if (key->IsHeapNumber()) {
1257 double value = Handle<HeapNumber>::cast(key)->value();
1258 if (std::isnan(value)) {
1259 key = isolate->factory()->nan_string();
1261 int int_value = FastD2I(value);
1262 if (value == int_value && Smi::IsValid(int_value)) {
1263 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1266 } else if (key->IsUndefined()) {
1267 key = isolate->factory()->undefined_string();
1273 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1274 Handle<Code> null_handle;
1275 Handle<Map> receiver_map(receiver->map(), isolate());
1276 MapHandleList target_receiver_maps;
1277 TargetMaps(&target_receiver_maps);
1280 if (target_receiver_maps.length() == 0) {
1281 if (FLAG_vector_ics) {
1282 Handle<Code> handler =
1283 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1284 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1287 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1290 // The first time a receiver is seen that is a transitioned version of the
1291 // previous monomorphic receiver type, assume the new ElementsKind is the
1292 // monomorphic type. This benefits global arrays that only transition
1293 // once, and all call sites accessing them are faster if they remain
1294 // monomorphic. If this optimistic assumption is not true, the IC will
1295 // miss again and it will become polymorphic and support both the
1296 // untransitioned and transitioned maps.
1297 if (state() == MONOMORPHIC && !receiver->IsString() &&
1298 IsMoreGeneralElementsKindTransition(
1299 target_receiver_maps.at(0)->elements_kind(),
1300 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1301 if (FLAG_vector_ics) {
1302 Handle<Code> handler =
1303 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1304 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1307 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1310 DCHECK(state() != GENERIC);
1312 // Determine the list of receiver maps that this call site has seen,
1313 // adding the map that was just encountered.
1314 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1315 // If the miss wasn't due to an unseen map, a polymorphic stub
1316 // won't help, use the generic stub.
1317 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
1318 return megamorphic_stub();
1321 // If the maximum number of receiver maps has been exceeded, use the generic
1322 // version of the IC.
1323 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1324 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
1325 return megamorphic_stub();
1328 if (FLAG_vector_ics) {
1329 CodeHandleList handlers(target_receiver_maps.length());
1330 ElementHandlerCompiler compiler(isolate());
1331 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1332 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps,
1337 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps);
1341 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1342 Handle<Object> key) {
1343 if (MigrateDeprecated(object)) {
1344 Handle<Object> result;
1345 ASSIGN_RETURN_ON_EXCEPTION(
1346 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1351 Handle<Object> load_handle;
1352 Handle<Code> stub = megamorphic_stub();
1354 // Check for non-string values that can be converted into an
1355 // internalized string directly or is representable as a smi.
1356 key = TryConvertKey(key, isolate());
1358 if (key->IsInternalizedString() || key->IsSymbol()) {
1359 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1360 LoadIC::Load(object, Handle<Name>::cast(key)),
1362 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1363 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1364 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1365 if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
1366 stub = LoadElementStub(receiver);
1372 if (!is_target_set()) {
1373 Code* generic = *megamorphic_stub();
1374 if (*stub == generic) {
1375 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1379 TRACE_IC("LoadIC", key);
1382 if (!is_vector_set() || stub.is_null()) {
1383 Code* generic = *megamorphic_stub();
1384 if (!stub.is_null() && *stub == generic) {
1385 ConfigureVectorState(MEGAMORPHIC);
1386 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1389 TRACE_IC("LoadIC", key);
1393 if (!load_handle.is_null()) return load_handle;
1394 Handle<Object> result;
1395 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1396 Runtime::GetObjectProperty(isolate(), object, key),
1402 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1403 JSReceiver::StoreFromKeyed store_mode) {
1404 // Disable ICs for non-JSObjects for now.
1405 Handle<Object> receiver = it->GetReceiver();
1406 if (!receiver->IsJSObject()) return false;
1407 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1409 for (; it->IsFound(); it->Next()) {
1410 switch (it->state()) {
1411 case LookupIterator::NOT_FOUND:
1412 case LookupIterator::TRANSITION:
1414 case LookupIterator::JSPROXY:
1416 case LookupIterator::INTERCEPTOR: {
1417 Handle<JSObject> holder = it->GetHolder<JSObject>();
1418 InterceptorInfo* info = holder->GetNamedInterceptor();
1419 if (it->HolderIsReceiverOrHiddenPrototype()) {
1420 if (!info->setter()->IsUndefined()) return true;
1421 } else if (!info->getter()->IsUndefined() ||
1422 !info->query()->IsUndefined()) {
1427 case LookupIterator::ACCESS_CHECK:
1428 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1430 case LookupIterator::ACCESSOR:
1431 return !it->IsReadOnly();
1432 case LookupIterator::DATA: {
1433 if (it->IsReadOnly()) return false;
1434 Handle<JSObject> holder = it->GetHolder<JSObject>();
1435 if (receiver.is_identical_to(holder)) {
1436 it->PrepareForDataProperty(value);
1437 // The previous receiver map might just have been deprecated,
1439 update_receiver_map(receiver);
1443 // Receiver != holder.
1444 PrototypeIterator iter(it->isolate(), receiver);
1445 if (receiver->IsJSGlobalProxy()) {
1446 return it->GetHolder<Object>().is_identical_to(
1447 PrototypeIterator::GetCurrent(iter));
1450 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1451 return it->IsCacheableTransition();
1456 if (it->IsSpecialNumericIndex()) return false;
1457 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1458 return it->IsCacheableTransition();
1462 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1463 Handle<Object> value,
1464 JSReceiver::StoreFromKeyed store_mode) {
1465 if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
1466 // Look up in script context table.
1467 Handle<String> str_name = Handle<String>::cast(name);
1468 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
1469 Handle<ScriptContextTable> script_contexts(
1470 global->native_context()->script_context_table());
1472 ScriptContextTable::LookupResult lookup_result;
1473 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1474 Handle<Context> script_context = ScriptContextTable::GetContext(
1475 script_contexts, lookup_result.context_index);
1476 if (lookup_result.mode == CONST) {
1477 return TypeError("harmony_const_assign", object, name);
1481 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1482 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1483 PatchCache(name, stub.GetCode());
1486 script_context->set(lookup_result.slot_index, *value);
1491 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1492 // might deprecate the current map again, if value does not fit.
1493 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1494 Handle<Object> result;
1495 ASSIGN_RETURN_ON_EXCEPTION(
1497 Object::SetProperty(object, name, value, language_mode()), Object);
1501 // If the object is undefined or null it's illegal to try to set any
1502 // properties on it; throw a TypeError in that case.
1503 if (object->IsUndefined() || object->IsNull()) {
1504 return TypeError("non_object_property_store", object, name);
1507 // Check if the given name is an array index.
1509 if (name->AsArrayIndex(&index)) {
1510 // Ignore other stores where the receiver is not a JSObject.
1511 // TODO(1475): Must check prototype chains of object wrappers.
1512 if (!object->IsJSObject()) return value;
1513 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1515 Handle<Object> result;
1516 ASSIGN_RETURN_ON_EXCEPTION(
1518 JSObject::SetElement(receiver, index, value, NONE, language_mode()),
1523 // Observed objects are always modified through the runtime.
1524 if (object->IsHeapObject() &&
1525 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1526 Handle<Object> result;
1527 ASSIGN_RETURN_ON_EXCEPTION(
1529 Object::SetProperty(object, name, value, language_mode(), store_mode),
1534 LookupIterator it(object, name);
1535 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1537 // Set the property.
1538 Handle<Object> result;
1539 ASSIGN_RETURN_ON_EXCEPTION(
1541 Object::SetProperty(&it, value, language_mode(), store_mode), Object);
1546 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
1547 CallICState::CallType call_type) {
1548 CallICTrampolineStub stub(isolate, CallICState(argc, call_type));
1549 Handle<Code> code = stub.GetCode();
1554 Handle<Code> CallIC::initialize_stub_in_optimized_code(
1555 Isolate* isolate, int argc, CallICState::CallType call_type) {
1556 CallICStub stub(isolate, CallICState(argc, call_type));
1557 Handle<Code> code = stub.GetCode();
1562 Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1563 LanguageMode language_mode) {
1564 ExtraICState extra_state = ComputeExtraICState(language_mode);
1566 PropertyICCompiler::ComputeStore(isolate, UNINITIALIZED, extra_state);
1571 Handle<Code> StoreIC::megamorphic_stub() {
1572 if (kind() == Code::STORE_IC) {
1573 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1576 DCHECK(kind() == Code::KEYED_STORE_IC);
1577 if (is_strict(language_mode())) {
1578 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
1580 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
1586 Handle<Code> StoreIC::slow_stub() const {
1587 if (kind() == Code::STORE_IC) {
1588 return isolate()->builtins()->StoreIC_Slow();
1590 DCHECK(kind() == Code::KEYED_STORE_IC);
1591 return isolate()->builtins()->KeyedStoreIC_Slow();
1596 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1597 LanguageMode language_mode) {
1598 ExtraICState state = ComputeExtraICState(language_mode);
1599 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1603 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1604 JSReceiver::StoreFromKeyed store_mode) {
1605 if (state() == UNINITIALIZED) {
1606 // This is the first time we execute this inline cache. Set the target to
1607 // the pre monomorphic stub to delay setting the monomorphic state.
1608 set_target(*pre_monomorphic_stub());
1609 TRACE_IC("StoreIC", lookup->name());
1613 bool use_ic = LookupForWrite(lookup, value, store_mode);
1615 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1617 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1619 PatchCache(lookup->name(), code);
1620 TRACE_IC("StoreIC", lookup->name());
1624 static Handle<Code> PropertyCellStoreHandler(
1625 Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
1626 Handle<Name> name, Handle<PropertyCell> cell, Handle<Object> value) {
1627 auto union_type = PropertyCell::UpdatedType(cell, value);
1628 StoreGlobalStub stub(isolate, union_type->IsConstant(),
1629 receiver->IsJSGlobalProxy());
1630 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1631 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1632 HeapObject::UpdateMapCodeCache(receiver, name, code);
1637 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1638 Handle<Object> value,
1639 CacheHolderFlag cache_holder) {
1640 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1642 // This is currently guaranteed by checks in StoreIC::Store.
1643 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1644 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1645 DCHECK(!receiver->IsAccessCheckNeeded());
1647 switch (lookup->state()) {
1648 case LookupIterator::TRANSITION: {
1649 auto store_target = lookup->GetStoreTarget();
1650 if (store_target->IsGlobalObject()) {
1651 auto cell = lookup->GetTransitionPropertyCell();
1652 return PropertyCellStoreHandler(
1653 isolate(), store_target, Handle<GlobalObject>::cast(store_target),
1654 lookup->name(), cell, value);
1656 Handle<Map> transition = lookup->transition_map();
1657 // Currently not handled by CompileStoreTransition.
1658 if (!holder->HasFastProperties()) {
1659 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1663 DCHECK(lookup->IsCacheableTransition());
1664 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1665 return compiler.CompileStoreTransition(transition, lookup->name());
1668 case LookupIterator::INTERCEPTOR: {
1669 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1670 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1671 return compiler.CompileStoreInterceptor(lookup->name());
1674 case LookupIterator::ACCESSOR: {
1675 if (!holder->HasFastProperties()) {
1676 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1679 Handle<Object> accessors = lookup->GetAccessors();
1680 if (accessors->IsExecutableAccessorInfo()) {
1681 Handle<ExecutableAccessorInfo> info =
1682 Handle<ExecutableAccessorInfo>::cast(accessors);
1683 if (v8::ToCData<Address>(info->setter()) == 0) {
1684 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1687 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1689 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1692 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1693 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1694 } else if (accessors->IsAccessorPair()) {
1695 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1697 if (!setter->IsJSFunction()) {
1698 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1701 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1702 CallOptimization call_optimization(function);
1703 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1704 if (call_optimization.is_simple_api_call() &&
1705 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1706 return compiler.CompileStoreCallback(receiver, lookup->name(),
1708 lookup->GetAccessorIndex());
1710 int expected_arguments =
1711 function->shared()->internal_formal_parameter_count();
1712 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
1713 lookup->GetAccessorIndex(),
1714 expected_arguments);
1719 case LookupIterator::DATA: {
1720 if (lookup->is_dictionary_holder()) {
1721 if (holder->IsGlobalObject()) {
1722 DCHECK(holder.is_identical_to(receiver) ||
1723 receiver->map()->prototype() == *holder);
1724 auto cell = lookup->GetPropertyCell();
1725 return PropertyCellStoreHandler(isolate(), receiver,
1726 Handle<GlobalObject>::cast(holder),
1727 lookup->name(), cell, value);
1729 DCHECK(holder.is_identical_to(receiver));
1730 return isolate()->builtins()->StoreIC_Normal();
1733 // -------------- Fields --------------
1734 if (lookup->property_details().type() == DATA) {
1735 bool use_stub = true;
1736 if (lookup->representation().IsHeapObject()) {
1737 // Only use a generic stub if no types need to be tracked.
1738 Handle<HeapType> field_type = lookup->GetFieldType();
1739 HeapType::Iterator<Map> it = field_type->Classes();
1740 use_stub = it.Done();
1743 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1744 lookup->representation());
1745 return stub.GetCode();
1747 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1748 return compiler.CompileStoreField(lookup);
1751 // -------------- Constant properties --------------
1752 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1753 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1757 case LookupIterator::ACCESS_CHECK:
1758 case LookupIterator::JSPROXY:
1759 case LookupIterator::NOT_FOUND:
1766 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1767 KeyedAccessStoreMode store_mode) {
1768 // Don't handle megamorphic property accesses for INTERCEPTORS or
1769 // ACCESSOR_CONSTANT
1770 // via megamorphic stubs, since they don't have a map in their relocation info
1771 // and so the stubs can't be harvested for the object needed for a map check.
1772 if (target()->type() != Code::NORMAL) {
1773 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
1774 return megamorphic_stub();
1777 Handle<Map> receiver_map(receiver->map(), isolate());
1778 MapHandleList target_receiver_maps;
1779 TargetMaps(&target_receiver_maps);
1780 if (target_receiver_maps.length() == 0) {
1781 Handle<Map> monomorphic_map =
1782 ComputeTransitionedMap(receiver_map, store_mode);
1783 store_mode = GetNonTransitioningStoreMode(store_mode);
1784 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1785 monomorphic_map, language_mode(), store_mode);
1788 // There are several special cases where an IC that is MONOMORPHIC can still
1789 // transition to a different GetNonTransitioningStoreMode IC that handles a
1790 // superset of the original IC. Handle those here if the receiver map hasn't
1791 // changed or it has transitioned to a more general kind.
1792 KeyedAccessStoreMode old_store_mode =
1793 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
1794 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1795 if (state() == MONOMORPHIC) {
1796 Handle<Map> transitioned_receiver_map = receiver_map;
1797 if (IsTransitionStoreMode(store_mode)) {
1798 transitioned_receiver_map =
1799 ComputeTransitionedMap(receiver_map, store_mode);
1801 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1802 IsTransitionStoreMode(store_mode)) ||
1803 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1804 *transitioned_receiver_map)) {
1805 // If the "old" and "new" maps are in the same elements map family, or
1806 // if they at least come from the same origin for a transitioning store,
1807 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1808 store_mode = GetNonTransitioningStoreMode(store_mode);
1809 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1810 transitioned_receiver_map, language_mode(), store_mode);
1811 } else if (*previous_receiver_map == receiver->map() &&
1812 old_store_mode == STANDARD_STORE &&
1813 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1814 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1815 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1816 // A "normal" IC that handles stores can switch to a version that can
1817 // grow at the end of the array, handle OOB accesses or copy COW arrays
1818 // and still stay MONOMORPHIC.
1819 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1820 receiver_map, language_mode(), store_mode);
1824 DCHECK(state() != GENERIC);
1827 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1829 if (IsTransitionStoreMode(store_mode)) {
1830 Handle<Map> transitioned_receiver_map =
1831 ComputeTransitionedMap(receiver_map, store_mode);
1832 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1833 transitioned_receiver_map);
1837 // If the miss wasn't due to an unseen map, a polymorphic stub
1838 // won't help, use the megamorphic stub which can handle everything.
1839 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
1840 return megamorphic_stub();
1843 // If the maximum number of receiver maps has been exceeded, use the
1844 // megamorphic version of the IC.
1845 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1846 return megamorphic_stub();
1849 // Make sure all polymorphic handlers have the same store mode, otherwise the
1850 // megamorphic stub must be used.
1851 store_mode = GetNonTransitioningStoreMode(store_mode);
1852 if (old_store_mode != STANDARD_STORE) {
1853 if (store_mode == STANDARD_STORE) {
1854 store_mode = old_store_mode;
1855 } else if (store_mode != old_store_mode) {
1856 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
1857 return megamorphic_stub();
1861 // If the store mode isn't the standard mode, make sure that all polymorphic
1862 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1863 // use the megamorphic stub.
1864 if (store_mode != STANDARD_STORE) {
1865 int external_arrays = 0;
1866 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1867 if (target_receiver_maps[i]->has_external_array_elements() ||
1868 target_receiver_maps[i]->has_fixed_typed_array_elements()) {
1872 if (external_arrays != 0 &&
1873 external_arrays != target_receiver_maps.length()) {
1874 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1875 "unsupported combination of external and normal arrays");
1876 return megamorphic_stub();
1880 return PropertyICCompiler::ComputeKeyedStorePolymorphic(
1881 &target_receiver_maps, store_mode, language_mode());
1885 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1886 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1887 switch (store_mode) {
1888 case STORE_TRANSITION_SMI_TO_OBJECT:
1889 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1890 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1891 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1892 return Map::TransitionElementsTo(map, FAST_ELEMENTS);
1893 case STORE_TRANSITION_SMI_TO_DOUBLE:
1894 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1895 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS);
1896 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1897 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1898 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1899 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1900 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS);
1901 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1902 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1903 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
1904 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1905 DCHECK(map->has_external_array_elements());
1907 case STORE_NO_TRANSITION_HANDLE_COW:
1908 case STANDARD_STORE:
1909 case STORE_AND_GROW_NO_TRANSITION:
1913 return MaybeHandle<Map>().ToHandleChecked();
1917 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, int index) {
1918 if (receiver->IsJSArray()) {
1919 return JSArray::cast(*receiver)->length()->IsSmi() &&
1920 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1922 return index >= receiver->elements()->length();
1926 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1928 Handle<Object> value) {
1929 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked();
1930 int index = smi_key->value();
1931 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1932 // Don't consider this a growing store if the store would send the receiver to
1934 bool allow_growth = receiver->IsJSArray() && oob_access &&
1935 !receiver->WouldConvertToSlowElements(key);
1937 // Handle growing array in stub if necessary.
1938 if (receiver->HasFastSmiElements()) {
1939 if (value->IsHeapNumber()) {
1940 if (receiver->HasFastHoleyElements()) {
1941 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1943 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1946 if (value->IsHeapObject()) {
1947 if (receiver->HasFastHoleyElements()) {
1948 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1950 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1953 } else if (receiver->HasFastDoubleElements()) {
1954 if (!value->IsSmi() && !value->IsHeapNumber()) {
1955 if (receiver->HasFastHoleyElements()) {
1956 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1958 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1962 return STORE_AND_GROW_NO_TRANSITION;
1964 // Handle only in-bounds elements accesses.
1965 if (receiver->HasFastSmiElements()) {
1966 if (value->IsHeapNumber()) {
1967 if (receiver->HasFastHoleyElements()) {
1968 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1970 return STORE_TRANSITION_SMI_TO_DOUBLE;
1972 } else if (value->IsHeapObject()) {
1973 if (receiver->HasFastHoleyElements()) {
1974 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1976 return STORE_TRANSITION_SMI_TO_OBJECT;
1979 } else if (receiver->HasFastDoubleElements()) {
1980 if (!value->IsSmi() && !value->IsHeapNumber()) {
1981 if (receiver->HasFastHoleyElements()) {
1982 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1984 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1988 if (!FLAG_trace_external_array_abuse &&
1989 receiver->map()->has_external_array_elements() && oob_access) {
1990 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1992 Heap* heap = receiver->GetHeap();
1993 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1994 return STORE_NO_TRANSITION_HANDLE_COW;
1996 return STANDARD_STORE;
2002 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2004 Handle<Object> value) {
2005 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2006 // might deprecate the current map again, if value does not fit.
2007 if (MigrateDeprecated(object)) {
2008 Handle<Object> result;
2009 ASSIGN_RETURN_ON_EXCEPTION(
2010 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2011 value, language_mode()),
2016 // Check for non-string values that can be converted into an
2017 // internalized string directly or is representable as a smi.
2018 key = TryConvertKey(key, isolate());
2020 Handle<Object> store_handle;
2021 Handle<Code> stub = megamorphic_stub();
2023 if (key->IsInternalizedString() || key->IsSymbol()) {
2024 ASSIGN_RETURN_ON_EXCEPTION(
2025 isolate(), store_handle,
2026 StoreIC::Store(object, Handle<Name>::cast(key), value,
2027 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2029 if (!is_target_set()) {
2030 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2031 "unhandled internalized string key");
2032 TRACE_IC("StoreIC", key);
2035 return store_handle;
2039 FLAG_use_ic && !object->IsStringWrapper() &&
2040 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2041 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2042 if (use_ic && !object->IsSmi()) {
2043 // Don't use ICs for maps of the objects in Array's prototype chain. We
2044 // expect to be able to trap element sets to objects with those maps in
2045 // the runtime to enable optimization of element hole access.
2046 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2047 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2048 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2054 DCHECK(!object->IsAccessCheckNeeded());
2056 if (object->IsJSObject()) {
2057 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2058 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null();
2059 if (receiver->elements()->map() ==
2060 isolate()->heap()->sloppy_arguments_elements_map()) {
2061 if (is_sloppy(language_mode())) {
2062 stub = sloppy_arguments_stub();
2064 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2066 } else if (key_is_smi_like &&
2067 !(target().is_identical_to(sloppy_arguments_stub()))) {
2068 // We should go generic if receiver isn't a dictionary, but our
2069 // prototype chain does have dictionary elements. This ensures that
2070 // other non-dictionary receivers in the polymorphic case benefit
2071 // from fast path keyed stores.
2072 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
2073 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
2074 stub = StoreElementStub(receiver, store_mode);
2076 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype");
2079 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2082 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2086 if (store_handle.is_null()) {
2087 ASSIGN_RETURN_ON_EXCEPTION(
2088 isolate(), store_handle,
2089 Runtime::SetObjectProperty(isolate(), object, key, value,
2094 DCHECK(!is_target_set());
2095 Code* megamorphic = *megamorphic_stub();
2096 if (*stub == megamorphic) {
2097 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2099 if (*stub == *slow_stub()) {
2100 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
2102 DCHECK(!stub.is_null());
2104 TRACE_IC("StoreIC", key);
2106 return store_handle;
2110 bool CallIC::DoCustomHandler(Handle<Object> function,
2111 const CallICState& callic_state) {
2112 DCHECK(FLAG_use_ic && function->IsJSFunction());
2114 // Are we the array function?
2115 Handle<JSFunction> array_function =
2116 Handle<JSFunction>(isolate()->native_context()->array_function());
2117 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
2119 CallICNexus* nexus = casted_nexus<CallICNexus>();
2120 nexus->ConfigureMonomorphicArray();
2122 // Vector-based ICs have a different calling convention in optimized code
2123 // than full code so the correct stub has to be chosen.
2124 if (AddressIsOptimizedCode()) {
2125 CallIC_ArrayStub stub(isolate(), callic_state);
2126 set_target(*stub.GetCode());
2128 CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
2129 set_target(*stub.GetCode());
2132 Handle<String> name;
2133 if (array_function->shared()->name()->IsString()) {
2134 name = Handle<String>(String::cast(array_function->shared()->name()),
2137 TRACE_IC("CallIC", name);
2138 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2146 void CallIC::PatchMegamorphic(Handle<Object> function) {
2147 CallICState callic_state(target()->extra_ic_state());
2149 // We are going generic.
2150 CallICNexus* nexus = casted_nexus<CallICNexus>();
2151 nexus->ConfigureGeneric();
2153 // Vector-based ICs have a different calling convention in optimized code
2154 // than full code so the correct stub has to be chosen.
2155 if (AddressIsOptimizedCode()) {
2156 CallICStub stub(isolate(), callic_state);
2157 set_target(*stub.GetCode());
2159 CallICTrampolineStub stub(isolate(), callic_state);
2160 set_target(*stub.GetCode());
2163 Handle<Object> name = isolate()->factory()->empty_string();
2164 if (function->IsJSFunction()) {
2165 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2166 name = handle(js_function->shared()->name(), isolate());
2169 TRACE_IC("CallIC", name);
2170 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2175 void CallIC::HandleMiss(Handle<Object> function) {
2176 CallICState callic_state(target()->extra_ic_state());
2177 Handle<Object> name = isolate()->factory()->empty_string();
2178 CallICNexus* nexus = casted_nexus<CallICNexus>();
2179 Object* feedback = nexus->GetFeedback();
2181 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2182 DCHECK(!feedback->IsSmi());
2184 if (feedback->IsWeakCell() || !function->IsJSFunction()) {
2185 // We are going generic.
2186 nexus->ConfigureGeneric();
2188 // The feedback is either uninitialized or an allocation site.
2189 // It might be an allocation site because if we re-compile the full code
2190 // to add deoptimization support, we call with the default call-ic, and
2191 // merely need to patch the target to match the feedback.
2192 // TODO(mvstanton): the better approach is to dispense with patching
2193 // altogether, which is in progress.
2194 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) ||
2195 feedback->IsAllocationSite());
2197 // Do we want to install a custom handler?
2198 if (FLAG_use_ic && DoCustomHandler(function, callic_state)) {
2202 nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
2205 if (function->IsJSFunction()) {
2206 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2207 name = handle(js_function->shared()->name(), isolate());
2210 IC::State new_state = nexus->StateFromFeedback();
2211 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
2212 TRACE_IC("CallIC", name);
2219 // ----------------------------------------------------------------------------
2220 // Static IC stub generators.
2223 // Used from ic-<arch>.cc.
2224 RUNTIME_FUNCTION(CallIC_Miss) {
2225 TimerEventScope<TimerEventIcMiss> timer(isolate);
2226 HandleScope scope(isolate);
2227 DCHECK(args.length() == 3);
2228 Handle<Object> function = args.at<Object>(0);
2229 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2230 Handle<Smi> slot = args.at<Smi>(2);
2231 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2232 CallICNexus nexus(vector, vector_slot);
2233 CallIC ic(isolate, &nexus);
2234 ic.HandleMiss(function);
2239 RUNTIME_FUNCTION(CallIC_Customization_Miss) {
2240 TimerEventScope<TimerEventIcMiss> timer(isolate);
2241 HandleScope scope(isolate);
2242 DCHECK(args.length() == 3);
2243 Handle<Object> function = args.at<Object>(0);
2244 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2245 Handle<Smi> slot = args.at<Smi>(2);
2246 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2247 CallICNexus nexus(vector, vector_slot);
2248 // A miss on a custom call ic always results in going megamorphic.
2249 CallIC ic(isolate, &nexus);
2250 ic.PatchMegamorphic(function);
2255 // Used from ic-<arch>.cc.
2256 RUNTIME_FUNCTION(LoadIC_Miss) {
2257 TimerEventScope<TimerEventIcMiss> timer(isolate);
2258 HandleScope scope(isolate);
2259 Handle<Object> receiver = args.at<Object>(0);
2260 Handle<Name> key = args.at<Name>(1);
2261 Handle<Object> result;
2263 if (FLAG_vector_ics) {
2264 DCHECK(args.length() == 4);
2265 Handle<Smi> slot = args.at<Smi>(2);
2266 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2267 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2268 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2269 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2270 // set up outside the IC, handle that here.
2271 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2272 LoadICNexus nexus(vector, vector_slot);
2273 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2274 ic.UpdateState(receiver, key);
2275 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2276 ic.Load(receiver, key));
2278 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2279 KeyedLoadICNexus nexus(vector, vector_slot);
2280 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2281 ic.UpdateState(receiver, key);
2282 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2283 ic.Load(receiver, key));
2286 DCHECK(args.length() == 2);
2287 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2288 ic.UpdateState(receiver, key);
2289 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2295 // Used from ic-<arch>.cc
2296 RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
2297 TimerEventScope<TimerEventIcMiss> timer(isolate);
2298 HandleScope scope(isolate);
2299 Handle<Object> receiver = args.at<Object>(0);
2300 Handle<Object> key = args.at<Object>(1);
2301 Handle<Object> result;
2303 if (FLAG_vector_ics) {
2304 DCHECK(args.length() == 4);
2305 Handle<Smi> slot = args.at<Smi>(2);
2306 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2307 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2308 KeyedLoadICNexus nexus(vector, vector_slot);
2309 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2310 ic.UpdateState(receiver, key);
2311 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2313 DCHECK(args.length() == 2);
2314 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2315 ic.UpdateState(receiver, key);
2316 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2323 RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
2324 TimerEventScope<TimerEventIcMiss> timer(isolate);
2325 HandleScope scope(isolate);
2326 Handle<Object> receiver = args.at<Object>(0);
2327 Handle<Object> key = args.at<Object>(1);
2328 Handle<Object> result;
2330 if (FLAG_vector_ics) {
2331 DCHECK(args.length() == 4);
2332 Handle<Smi> slot = args.at<Smi>(2);
2333 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2334 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2335 KeyedLoadICNexus nexus(vector, vector_slot);
2336 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2337 ic.UpdateState(receiver, key);
2338 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2340 DCHECK(args.length() == 2);
2341 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2342 ic.UpdateState(receiver, key);
2343 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2350 // Used from ic-<arch>.cc.
2351 RUNTIME_FUNCTION(StoreIC_Miss) {
2352 TimerEventScope<TimerEventIcMiss> timer(isolate);
2353 HandleScope scope(isolate);
2354 DCHECK(args.length() == 3);
2355 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2356 Handle<Object> receiver = args.at<Object>(0);
2357 Handle<Name> key = args.at<Name>(1);
2358 ic.UpdateState(receiver, key);
2359 Handle<Object> result;
2360 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2361 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2366 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
2367 TimerEventScope<TimerEventIcMiss> timer(isolate);
2368 HandleScope scope(isolate);
2369 DCHECK(args.length() == 3 || args.length() == 4);
2370 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2371 Handle<Object> receiver = args.at<Object>(0);
2372 Handle<Name> key = args.at<Name>(1);
2373 ic.UpdateState(receiver, key);
2374 Handle<Object> result;
2375 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2376 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2381 // Used from ic-<arch>.cc.
2382 RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
2383 TimerEventScope<TimerEventIcMiss> timer(isolate);
2384 HandleScope scope(isolate);
2385 DCHECK(args.length() == 3);
2386 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2387 Handle<Object> receiver = args.at<Object>(0);
2388 Handle<Object> key = args.at<Object>(1);
2389 ic.UpdateState(receiver, key);
2390 Handle<Object> result;
2391 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2392 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2397 RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) {
2398 TimerEventScope<TimerEventIcMiss> timer(isolate);
2399 HandleScope scope(isolate);
2400 DCHECK(args.length() == 3);
2401 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2402 Handle<Object> receiver = args.at<Object>(0);
2403 Handle<Object> key = args.at<Object>(1);
2404 ic.UpdateState(receiver, key);
2405 Handle<Object> result;
2406 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2407 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2412 RUNTIME_FUNCTION(StoreIC_Slow) {
2413 HandleScope scope(isolate);
2414 DCHECK(args.length() == 3);
2415 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2416 Handle<Object> object = args.at<Object>(0);
2417 Handle<Object> key = args.at<Object>(1);
2418 Handle<Object> value = args.at<Object>(2);
2419 LanguageMode language_mode = ic.language_mode();
2420 Handle<Object> result;
2421 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2423 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2428 RUNTIME_FUNCTION(KeyedStoreIC_Slow) {
2429 HandleScope scope(isolate);
2430 DCHECK(args.length() == 3);
2431 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2432 Handle<Object> object = args.at<Object>(0);
2433 Handle<Object> key = args.at<Object>(1);
2434 Handle<Object> value = args.at<Object>(2);
2435 LanguageMode language_mode = ic.language_mode();
2436 Handle<Object> result;
2437 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2439 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2444 RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) {
2445 TimerEventScope<TimerEventIcMiss> timer(isolate);
2446 HandleScope scope(isolate);
2447 DCHECK(args.length() == 4);
2448 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2449 Handle<Object> value = args.at<Object>(0);
2450 Handle<Map> map = args.at<Map>(1);
2451 Handle<Object> key = args.at<Object>(2);
2452 Handle<Object> object = args.at<Object>(3);
2453 LanguageMode language_mode = ic.language_mode();
2454 if (object->IsJSObject()) {
2455 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2456 map->elements_kind());
2458 Handle<Object> result;
2459 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2461 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2466 MaybeHandle<Object> BinaryOpIC::Transition(
2467 Handle<AllocationSite> allocation_site, Handle<Object> left,
2468 Handle<Object> right) {
2469 BinaryOpICState state(isolate(), target()->extra_ic_state());
2471 // Compute the actual result using the builtin for the binary operation.
2472 Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
2473 TokenToJSBuiltin(state.op()));
2474 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
2475 Handle<Object> result;
2476 ASSIGN_RETURN_ON_EXCEPTION(
2477 isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
2480 // Execution::Call can execute arbitrary JavaScript, hence potentially
2481 // update the state of this very IC, so we must update the stored state.
2483 // Compute the new state.
2484 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2485 state.Update(left, right, result);
2487 // Check if we have a string operation here.
2488 Handle<Code> target;
2489 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2490 // Setup the allocation site on-demand.
2491 if (allocation_site.is_null()) {
2492 allocation_site = isolate()->factory()->NewAllocationSite();
2495 // Install the stub with an allocation site.
2496 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2497 target = stub.GetCodeCopyFromTemplate(allocation_site);
2499 // Sanity check the trampoline stub.
2500 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2502 // Install the generic stub.
2503 BinaryOpICStub stub(isolate(), state);
2504 target = stub.GetCode();
2506 // Sanity check the generic stub.
2507 DCHECK_NULL(target->FindFirstAllocationSite());
2509 set_target(*target);
2511 if (FLAG_trace_ic) {
2512 OFStream os(stdout);
2513 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2514 << static_cast<void*>(*target) << " <- ";
2515 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2516 if (!allocation_site.is_null()) {
2517 os << " using allocation site " << static_cast<void*>(*allocation_site);
2519 os << "]" << std::endl;
2522 // Patch the inlined smi code as necessary.
2523 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2524 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2525 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2526 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2533 RUNTIME_FUNCTION(BinaryOpIC_Miss) {
2534 TimerEventScope<TimerEventIcMiss> timer(isolate);
2535 HandleScope scope(isolate);
2536 DCHECK_EQ(2, args.length());
2537 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2538 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2539 BinaryOpIC ic(isolate);
2540 Handle<Object> result;
2541 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2543 ic.Transition(Handle<AllocationSite>::null(), left, right));
2548 RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) {
2549 TimerEventScope<TimerEventIcMiss> timer(isolate);
2550 HandleScope scope(isolate);
2551 DCHECK_EQ(3, args.length());
2552 Handle<AllocationSite> allocation_site =
2553 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2554 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2555 Handle<Object> right =
2556 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2557 BinaryOpIC ic(isolate);
2558 Handle<Object> result;
2559 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2560 isolate, result, ic.Transition(allocation_site, left, right));
2565 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2566 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2567 CompareICState::UNINITIALIZED,
2568 CompareICState::UNINITIALIZED);
2570 CHECK(stub.FindCodeInCache(&code));
2575 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2576 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2577 CompareICState::UNINITIALIZED,
2578 CompareICState::UNINITIALIZED);
2579 return stub.GetCode();
2583 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2584 HandleScope scope(isolate());
2585 CompareICStub old_stub(target()->stub_key(), isolate());
2586 CompareICState::State new_left =
2587 CompareICState::NewInputState(old_stub.left(), x);
2588 CompareICState::State new_right =
2589 CompareICState::NewInputState(old_stub.right(), y);
2590 CompareICState::State state = CompareICState::TargetState(
2591 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2592 HasInlinedSmiCode(address()), x, y);
2593 CompareICStub stub(isolate(), op_, new_left, new_right, state);
2594 if (state == CompareICState::KNOWN_OBJECT) {
2596 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2598 Handle<Code> new_target = stub.GetCode();
2599 set_target(*new_target);
2601 if (FLAG_trace_ic) {
2602 PrintF("[CompareIC in ");
2603 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2604 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2605 CompareICState::GetStateName(old_stub.left()),
2606 CompareICState::GetStateName(old_stub.right()),
2607 CompareICState::GetStateName(old_stub.state()),
2608 CompareICState::GetStateName(new_left),
2609 CompareICState::GetStateName(new_right),
2610 CompareICState::GetStateName(state), Token::Name(op_),
2611 static_cast<void*>(*stub.GetCode()));
2614 // Activate inlined smi code.
2615 if (old_stub.state() == CompareICState::UNINITIALIZED) {
2616 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2623 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2624 RUNTIME_FUNCTION(CompareIC_Miss) {
2625 TimerEventScope<TimerEventIcMiss> timer(isolate);
2626 HandleScope scope(isolate);
2627 DCHECK(args.length() == 3);
2628 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2629 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2633 void CompareNilIC::Clear(Address address, Code* target,
2634 ConstantPoolArray* constant_pool) {
2635 if (IsCleared(target)) return;
2636 ExtraICState state = target->extra_ic_state();
2638 CompareNilICStub stub(target->GetIsolate(), state,
2639 HydrogenCodeStub::UNINITIALIZED);
2643 CHECK(stub.FindCodeInCache(&code));
2645 SetTargetAtAddress(address, code, constant_pool);
2649 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2650 Handle<Object> object) {
2651 if (object->IsNull() || object->IsUndefined()) {
2652 return handle(Smi::FromInt(true), isolate);
2654 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate);
2658 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2659 ExtraICState extra_ic_state = target()->extra_ic_state();
2661 CompareNilICStub stub(isolate(), extra_ic_state);
2663 // Extract the current supported types from the patched IC and calculate what
2664 // types must be supported as a result of the miss.
2665 bool already_monomorphic = stub.IsMonomorphic();
2667 stub.UpdateStatus(object);
2669 NilValue nil = stub.nil_value();
2671 // Find or create the specialized stub to support the new set of types.
2673 if (stub.IsMonomorphic()) {
2674 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2676 : HeapObject::cast(*object)->map());
2677 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2679 code = stub.GetCode();
2682 return DoCompareNilSlow(isolate(), nil, object);
2686 RUNTIME_FUNCTION(CompareNilIC_Miss) {
2687 TimerEventScope<TimerEventIcMiss> timer(isolate);
2688 HandleScope scope(isolate);
2689 Handle<Object> object = args.at<Object>(0);
2690 CompareNilIC ic(isolate);
2691 return *ic.CompareNil(object);
2695 RUNTIME_FUNCTION(Unreachable) {
2698 return isolate->heap()->undefined_value();
2702 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2707 return Builtins::ADD;
2710 return Builtins::SUB;
2713 return Builtins::MUL;
2716 return Builtins::DIV;
2719 return Builtins::MOD;
2722 return Builtins::BIT_OR;
2724 case Token::BIT_AND:
2725 return Builtins::BIT_AND;
2727 case Token::BIT_XOR:
2728 return Builtins::BIT_XOR;
2731 return Builtins::SAR;
2734 return Builtins::SHR;
2737 return Builtins::SHL;
2743 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2744 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2745 bool to_boolean_value = stub.UpdateStatus(object);
2746 Handle<Code> code = stub.GetCode();
2748 return handle(Smi::FromInt(to_boolean_value ? 1 : 0), isolate());
2752 RUNTIME_FUNCTION(ToBooleanIC_Miss) {
2753 TimerEventScope<TimerEventIcMiss> timer(isolate);
2754 DCHECK(args.length() == 1);
2755 HandleScope scope(isolate);
2756 Handle<Object> object = args.at<Object>(0);
2757 ToBooleanIC ic(isolate);
2758 return *ic.ToBoolean(object);
2762 RUNTIME_FUNCTION(StoreCallbackProperty) {
2763 Handle<JSObject> receiver = args.at<JSObject>(0);
2764 Handle<JSObject> holder = args.at<JSObject>(1);
2765 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
2766 Handle<Name> name = args.at<Name>(3);
2767 Handle<Object> value = args.at<Object>(4);
2768 HandleScope scope(isolate);
2770 Handle<ExecutableAccessorInfo> callback(
2771 callback_or_cell->IsWeakCell()
2772 ? ExecutableAccessorInfo::cast(
2773 WeakCell::cast(*callback_or_cell)->value())
2774 : ExecutableAccessorInfo::cast(*callback_or_cell));
2776 DCHECK(callback->IsCompatibleReceiver(*receiver));
2778 Address setter_address = v8::ToCData<Address>(callback->setter());
2779 v8::AccessorNameSetterCallback fun =
2780 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2781 DCHECK(fun != NULL);
2783 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2784 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2786 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2787 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2793 * Attempts to load a property with an interceptor (which must be present),
2794 * but doesn't search the prototype chain.
2796 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2797 * provide any value for the given name.
2799 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
2800 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2802 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2803 Handle<JSObject> receiver =
2804 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2805 Handle<JSObject> holder =
2806 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2807 HandleScope scope(isolate);
2808 Handle<InterceptorInfo> interceptor_info(holder->GetNamedInterceptor());
2810 if (name->IsSymbol() && !interceptor_info->can_intercept_symbols())
2811 return isolate->heap()->no_interceptor_result_sentinel();
2813 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
2814 v8::GenericNamedPropertyGetterCallback getter =
2815 FUNCTION_CAST<v8::GenericNamedPropertyGetterCallback>(getter_address);
2816 DCHECK(getter != NULL);
2818 PropertyCallbackArguments callback_args(isolate, interceptor_info->data(),
2819 *receiver, *holder);
2821 // Use the interceptor getter.
2822 v8::Handle<v8::Value> r =
2823 callback_args.Call(getter, v8::Utils::ToLocal(name));
2824 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2826 Handle<Object> result = v8::Utils::OpenHandle(*r);
2827 result->VerifyApiCallResultType();
2828 return *v8::Utils::OpenHandle(*r);
2832 return isolate->heap()->no_interceptor_result_sentinel();
2836 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
2837 // If the load is non-contextual, just return the undefined result.
2838 // Note that both keyed and non-keyed loads may end up here.
2839 HandleScope scope(isolate);
2840 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
2841 if (ic.contextual_mode() != CONTEXTUAL) {
2842 return isolate->heap()->undefined_value();
2845 // Throw a reference error.
2846 Handle<Name> name_handle(name);
2847 THROW_NEW_ERROR_RETURN_FAILURE(
2848 isolate, NewReferenceError("not_defined", HandleVector(&name_handle, 1)));
2853 * Loads a property with an interceptor performing post interceptor
2854 * lookup if interceptor failed.
2856 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
2857 HandleScope scope(isolate);
2858 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2860 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2861 Handle<JSObject> receiver =
2862 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2863 Handle<JSObject> holder =
2864 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2866 Handle<Object> result;
2867 LookupIterator it(receiver, name, holder);
2868 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2869 JSObject::GetProperty(&it));
2871 if (it.IsFound()) return *result;
2873 return ThrowReferenceError(isolate, Name::cast(args[0]));
2877 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
2878 HandleScope scope(isolate);
2879 DCHECK(args.length() == 3);
2880 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2881 Handle<JSObject> receiver = args.at<JSObject>(0);
2882 Handle<Name> name = args.at<Name>(1);
2883 Handle<Object> value = args.at<Object>(2);
2885 PrototypeIterator iter(isolate, receiver,
2886 PrototypeIterator::START_AT_RECEIVER);
2888 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
2889 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2890 if (current->IsJSObject() &&
2891 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2898 Handle<Object> result;
2899 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2901 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
2906 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
2907 HandleScope scope(isolate);
2908 Handle<JSObject> receiver = args.at<JSObject>(0);
2909 DCHECK(args.smi_at(1) >= 0);
2910 uint32_t index = args.smi_at(1);
2911 Handle<Object> result;
2912 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2914 JSObject::GetElementWithInterceptor(receiver, receiver, index, true));
2919 RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
2920 TimerEventScope<TimerEventIcMiss> timer(isolate);
2921 HandleScope scope(isolate);
2922 Handle<Object> receiver = args.at<Object>(0);
2923 Handle<Name> key = args.at<Name>(1);
2924 Handle<Object> result;
2926 if (FLAG_vector_ics) {
2927 DCHECK(args.length() == 4);
2928 Handle<Smi> slot = args.at<Smi>(2);
2929 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2930 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2931 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2932 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2933 // set up outside the IC, handle that here.
2934 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2935 LoadICNexus nexus(vector, vector_slot);
2936 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2937 ic.UpdateState(receiver, key);
2938 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2939 ic.Load(receiver, key));
2941 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2942 KeyedLoadICNexus nexus(vector, vector_slot);
2943 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2944 ic.UpdateState(receiver, key);
2945 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2946 ic.Load(receiver, key));
2949 DCHECK(args.length() == 2);
2950 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2951 ic.UpdateState(receiver, key);
2952 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2959 static const Address IC_utilities[] = {
2960 #define ADDR(name) FUNCTION_ADDR(name),
2961 IC_UTIL_LIST(ADDR) NULL
2966 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; }
2968 } // namespace v8::internal