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) {
92 if (AddressIsDeoptimizedCode()) return;
94 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
95 TraceIC(type, name, state(), new_state);
100 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
103 Code* new_target = raw_target();
104 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
106 // TODO(jkummerow): Add support for "apply". The logic is roughly:
107 // marker = [fp_ + kMarkerOffset];
108 // if marker is smi and marker.value == INTERNAL and
109 // the frame's code == builtin(Builtins::kFunctionApply):
110 // then print "apply from" and advance one frame
112 Object* maybe_function =
113 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
114 if (maybe_function->IsJSFunction()) {
115 JSFunction* function = JSFunction::cast(maybe_function);
116 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
120 ExtraICState extra_state = new_target->extra_ic_state();
121 const char* modifier = "";
122 if (new_target->kind() == Code::KEYED_STORE_IC) {
123 modifier = GetTransitionMarkModifier(
124 KeyedStoreIC::GetKeyedAccessStoreMode(extra_state));
126 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
127 TransitionMarkFromState(new_state), modifier);
132 name->ShortPrint(stdout);
139 #define TRACE_IC(type, name) TraceIC(type, name)
142 IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
143 bool for_queries_only)
147 target_maps_set_(false),
149 // To improve the performance of the (much used) IC code, we unfold a few
150 // levels of the stack frame iteration code. This yields a ~35% speedup when
151 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
152 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
153 Address* constant_pool = NULL;
154 if (FLAG_enable_embedded_constant_pool) {
155 constant_pool = reinterpret_cast<Address*>(
156 entry + ExitFrameConstants::kConstantPoolOffset);
158 Address* pc_address =
159 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
160 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
161 // If there's another JavaScript frame on the stack or a
162 // StubFailureTrampoline, we need to look one frame further down the stack to
163 // find the frame pointer and the return address stack slot.
164 if (depth == EXTRA_CALL_FRAME) {
165 if (FLAG_enable_embedded_constant_pool) {
166 constant_pool = reinterpret_cast<Address*>(
167 fp + StandardFrameConstants::kConstantPoolOffset);
169 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
170 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
171 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
174 StackFrameIterator it(isolate);
175 for (int i = 0; i < depth + 1; i++) it.Advance();
176 StackFrame* frame = it.frame();
177 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
180 if (FLAG_enable_embedded_constant_pool) {
181 constant_pool_address_ = constant_pool;
183 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
184 target_ = handle(raw_target(), isolate);
185 kind_ = target_->kind();
186 state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
187 : target_->ic_state();
189 extra_ic_state_ = target_->extra_ic_state();
193 SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
194 // Compute the JavaScript frame for the frame pointer of this IC
195 // structure. We need this to be able to find the function
196 // corresponding to the frame.
197 StackFrameIterator it(isolate());
198 while (it.frame()->fp() != this->fp()) it.Advance();
199 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
200 // Find the function on the stack and both the active code for the
201 // function and the original code.
202 JSFunction* function = frame->function();
203 return function->shared();
207 Code* IC::GetCode() const {
208 HandleScope scope(isolate());
209 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
210 Code* code = shared->code();
215 Code* IC::GetOriginalCode() const {
216 HandleScope scope(isolate());
217 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
218 DCHECK(Debug::HasDebugInfo(shared));
219 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
220 DCHECK(original_code->IsCode());
221 return original_code;
225 bool IC::AddressIsOptimizedCode() const {
227 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
228 return host->kind() == Code::OPTIMIZED_FUNCTION;
232 static void LookupForRead(LookupIterator* it) {
233 for (; it->IsFound(); it->Next()) {
234 switch (it->state()) {
235 case LookupIterator::NOT_FOUND:
236 case LookupIterator::TRANSITION:
238 case LookupIterator::JSPROXY:
240 case LookupIterator::INTERCEPTOR: {
241 // If there is a getter, return; otherwise loop to perform the lookup.
242 Handle<JSObject> holder = it->GetHolder<JSObject>();
243 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
248 case LookupIterator::ACCESS_CHECK:
249 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
250 // access checks for global proxies.
251 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
255 case LookupIterator::ACCESSOR:
256 case LookupIterator::INTEGER_INDEXED_EXOTIC:
257 case LookupIterator::DATA:
264 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
265 Handle<String> name) {
266 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
268 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
270 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
273 // The current map wasn't handled yet. There's no reason to stay monomorphic,
274 // *unless* we're moving from a deprecated map to its replacement, or
275 // to a more general elements kind.
276 // TODO(verwaest): Check if the current map is actually what the old map
277 // would transition to.
278 if (maybe_handler_.is_null()) {
279 if (!receiver_map()->IsJSObjectMap()) return false;
280 Map* first_map = FirstTargetMap();
281 if (first_map == NULL) return false;
282 Handle<Map> old_map(first_map);
283 if (old_map->is_deprecated()) return true;
284 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
285 receiver_map()->elements_kind())) {
291 CacheHolderFlag flag;
292 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
294 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
295 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
296 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
298 if (state() == MONOMORPHIC) {
299 int index = ic_holder_map->IndexInCodeCache(*name, *target());
301 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
305 if (receiver->IsGlobalObject()) {
306 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
307 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
308 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
309 if (!it.IsFound()) return false;
310 return it.property_details().cell_type() == PropertyCellType::kConstant;
317 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
318 if (target()->is_keyed_stub()) {
319 // Determine whether the failure is due to a name failure.
320 if (!name->IsName()) return false;
322 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
323 if (*name != stub_name) return false;
330 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
331 update_receiver_map(receiver);
332 if (!name->IsString()) return;
333 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
334 if (receiver->IsUndefined() || receiver->IsNull()) return;
336 // Remove the target from the code cache if it became invalid
337 // because of changes in the prototype chain to avoid hitting it
339 if (TryRemoveInvalidPrototypeDependentStub(receiver,
340 Handle<String>::cast(name))) {
341 MarkPrototypeFailure(name);
345 // The builtins object is special. It only changes when JavaScript
346 // builtins are loaded lazily. It is important to keep inline
347 // caches for the builtins object monomorphic. Therefore, if we get
348 // an inline cache miss for the builtins object after lazily loading
349 // JavaScript builtins, we return uninitialized as the state to
350 // force the inline cache back to monomorphic state.
351 if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
355 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
356 Handle<Object> object, Handle<Object> key) {
357 HandleScope scope(isolate());
358 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
362 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
363 HandleScope scope(isolate());
365 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
369 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
370 int* polymorphic_delta,
371 int* generic_delta) {
375 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
376 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
377 *polymorphic_delta = 1;
378 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
384 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
385 *polymorphic_delta = -1;
386 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
392 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
394 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
395 *polymorphic_delta = 1;
398 case PROTOTYPE_FAILURE:
406 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
407 State old_state, State new_state,
408 bool target_remains_ic_stub) {
410 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
411 if (host->kind() != Code::FUNCTION) return;
413 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
414 // Not all Code objects have TypeFeedbackInfo.
415 host->type_feedback_info()->IsTypeFeedbackInfo()) {
416 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
417 int generic_delta = 0; // "Generic" here includes megamorphic.
418 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
420 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
421 info->change_ic_with_type_info_count(polymorphic_delta);
422 info->change_ic_generic_count(generic_delta);
424 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
425 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
426 info->change_own_type_change_checksum();
428 host->set_profiler_ticks(0);
429 isolate->runtime_profiler()->NotifyICChanged();
430 // TODO(2029): When an optimized function is patched, it would
431 // be nice to propagate the corresponding type information to its
432 // unoptimized version for the benefit of later inlining.
437 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
438 TypeFeedbackVector* vector, State old_state,
440 if (host->kind() != Code::FUNCTION) return;
442 if (FLAG_type_info_threshold > 0) {
443 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
444 int generic_delta = 0; // "Generic" here includes megamorphic.
445 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
447 vector->change_ic_with_type_info_count(polymorphic_delta);
448 vector->change_ic_generic_count(generic_delta);
450 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
451 info->change_own_type_change_checksum();
452 host->set_profiler_ticks(0);
453 isolate->runtime_profiler()->NotifyICChanged();
454 // TODO(2029): When an optimized function is patched, it would
455 // be nice to propagate the corresponding type information to its
456 // unoptimized version for the benefit of later inlining.
460 void IC::PostPatching(Address address, Code* target, Code* old_target) {
461 // Type vector based ICs update these statistics at a different time because
462 // they don't always patch on state change.
463 if (ICUseVector(target->kind())) return;
465 Isolate* isolate = target->GetHeap()->isolate();
466 State old_state = UNINITIALIZED;
467 State new_state = UNINITIALIZED;
468 bool target_remains_ic_stub = false;
469 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
470 old_state = old_target->ic_state();
471 new_state = target->ic_state();
472 target_remains_ic_stub = true;
475 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
476 target_remains_ic_stub);
480 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
481 Code* target = GetTargetAtAddress(address, constant_pool);
483 // Don't clear debug break inline cache as it will remove the break point.
484 if (target->is_debug_stub()) return;
486 switch (target->kind()) {
488 case Code::KEYED_LOAD_IC:
491 return StoreIC::Clear(isolate, address, target, constant_pool);
492 case Code::KEYED_STORE_IC:
493 return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
494 case Code::COMPARE_IC:
495 return CompareIC::Clear(isolate, address, target, constant_pool);
496 case Code::COMPARE_NIL_IC:
497 return CompareNilIC::Clear(address, target, constant_pool);
498 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
499 case Code::BINARY_OP_IC:
500 case Code::TO_BOOLEAN_IC:
501 // Clearing these is tricky and does not
502 // make any performance difference.
510 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
511 if (IsCleared(nexus)) return;
512 // Make sure to also clear the map used in inline fast cases. If we
513 // do not clear these maps, cached code can keep objects alive
514 // through the embedded maps.
515 State state = nexus->StateFromFeedback();
516 nexus->ConfigurePremonomorphic();
517 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
521 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
522 // Determine our state.
523 Object* feedback = nexus->vector()->Get(nexus->slot());
524 State state = nexus->StateFromFeedback();
526 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
527 nexus->ConfigureUninitialized();
528 // The change in state must be processed.
529 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
534 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
535 if (IsCleared(nexus)) return;
536 State state = nexus->StateFromFeedback();
537 nexus->ConfigurePremonomorphic();
538 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
542 void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
543 Address constant_pool) {
544 if (IsCleared(target)) return;
545 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
546 target->extra_ic_state());
547 SetTargetAtAddress(address, code, constant_pool);
551 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
552 Address constant_pool) {
553 if (IsCleared(target)) return;
554 Handle<Code> code = pre_monomorphic_stub(
555 isolate, StoreICState::GetLanguageMode(target->extra_ic_state()));
556 SetTargetAtAddress(address, *code, constant_pool);
560 void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
561 Address constant_pool) {
562 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
563 CompareICStub stub(target->stub_key(), isolate);
564 // Only clear CompareICs that can retain objects.
565 if (stub.state() != CompareICState::KNOWN_OBJECT) return;
566 SetTargetAtAddress(address,
567 GetRawUninitialized(isolate, stub.op(), stub.strength()),
569 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
574 Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate) {
575 if (FLAG_compiled_keyed_generic_loads) {
576 return KeyedLoadGenericStub(isolate).GetCode();
578 return isolate->builtins()->KeyedLoadIC_Megamorphic();
583 static bool MigrateDeprecated(Handle<Object> object) {
584 if (!object->IsJSObject()) return false;
585 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
586 if (!receiver->map()->is_deprecated()) return false;
587 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
592 void IC::ConfigureVectorState(IC::State new_state) {
594 if (kind() == Code::LOAD_IC) {
595 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
596 if (new_state == PREMONOMORPHIC) {
597 nexus->ConfigurePremonomorphic();
598 } else if (new_state == MEGAMORPHIC) {
599 nexus->ConfigureMegamorphic();
603 } else if (kind() == Code::KEYED_LOAD_IC) {
604 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
605 if (new_state == PREMONOMORPHIC) {
606 nexus->ConfigurePremonomorphic();
607 } else if (new_state == MEGAMORPHIC) {
608 nexus->ConfigureMegamorphic();
617 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
622 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
623 Handle<Code> handler) {
625 if (kind() == Code::LOAD_IC) {
626 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
627 nexus->ConfigureMonomorphic(map, handler);
629 DCHECK(kind() == Code::KEYED_LOAD_IC);
630 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
631 nexus->ConfigureMonomorphic(name, map, handler);
635 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
640 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
641 CodeHandleList* handlers) {
643 if (kind() == Code::LOAD_IC) {
644 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
645 nexus->ConfigurePolymorphic(maps, handlers);
647 DCHECK(kind() == Code::KEYED_LOAD_IC);
648 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
649 nexus->ConfigurePolymorphic(name, maps, handlers);
653 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
658 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
659 // If the object is undefined or null it's illegal to try to get any
660 // of its properties; throw a TypeError in that case.
661 if (object->IsUndefined() || object->IsNull()) {
662 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
665 // Check if the name is trivially convertible to an index and get
666 // the element or char if so.
668 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
669 // Rewrite to the generic keyed load stub.
672 ConfigureVectorState(MEGAMORPHIC);
674 set_target(*megamorphic_stub());
676 TRACE_IC("LoadIC", name);
677 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
679 Handle<Object> result;
680 ASSIGN_RETURN_ON_EXCEPTION(
682 Runtime::GetElementOrCharAt(isolate(), object, index), Object);
686 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
688 if (object->IsGlobalObject() && name->IsString()) {
689 // Look up in script context table.
690 Handle<String> str_name = Handle<String>::cast(name);
691 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
692 Handle<ScriptContextTable> script_contexts(
693 global->native_context()->script_context_table());
695 ScriptContextTable::LookupResult lookup_result;
696 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
697 Handle<Object> result =
698 FixedArray::get(ScriptContextTable::GetContext(
699 script_contexts, lookup_result.context_index),
700 lookup_result.slot_index);
701 if (*result == *isolate()->factory()->the_hole_value()) {
702 // Do not install stubs and stay pre-monomorphic for
703 // uninitialized accesses.
704 return ReferenceError(name);
707 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
708 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
709 PatchCache(name, stub.GetCode());
715 // Named lookup in the object.
716 LookupIterator it(object, name);
719 if (it.IsFound() || !IsUndeclaredGlobal(object)) {
720 // Update inline cache and stub cache.
721 if (use_ic) UpdateCaches(&it);
724 Handle<Object> result;
725 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
729 } else if (!IsUndeclaredGlobal(object)) {
730 LOG(isolate(), SuspectReadEvent(*name, *object));
734 return ReferenceError(name);
738 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
739 Handle<Map> new_receiver_map) {
740 DCHECK(!new_receiver_map.is_null());
741 for (int current = 0; current < receiver_maps->length(); ++current) {
742 if (!receiver_maps->at(current).is_null() &&
743 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
747 receiver_maps->Add(new_receiver_map);
752 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
753 if (!code->is_handler()) return false;
754 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
755 Handle<Map> map = receiver_map();
757 CodeHandleList handlers;
760 int number_of_maps = maps.length();
761 int deprecated_maps = 0;
762 int handler_to_overwrite = -1;
764 for (int i = 0; i < number_of_maps; i++) {
765 Handle<Map> current_map = maps.at(i);
766 if (current_map->is_deprecated()) {
767 // Filter out deprecated maps to ensure their instances get migrated.
769 } else if (map.is_identical_to(current_map)) {
770 // If the receiver type is already in the polymorphic IC, this indicates
771 // there was a prototoype chain failure. In that case, just overwrite the
773 handler_to_overwrite = i;
774 } else if (handler_to_overwrite == -1 &&
775 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
776 handler_to_overwrite = i;
780 int number_of_valid_maps =
781 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
783 if (number_of_valid_maps >= 4) return false;
784 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
788 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
790 if (!target()->FindHandlers(&handlers, maps.length())) return false;
793 number_of_valid_maps++;
794 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
796 if (number_of_valid_maps == 1) {
798 ConfigureVectorState(name, receiver_map(), code);
800 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, map, code,
804 if (handler_to_overwrite >= 0) {
805 handlers.Set(handler_to_overwrite, code);
806 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
807 maps.Set(handler_to_overwrite, map);
815 ConfigureVectorState(name, &maps, &handlers);
817 ic = PropertyICCompiler::ComputePolymorphic(kind(), &maps, &handlers,
818 number_of_valid_maps, name,
823 if (!UseVector()) set_target(*ic);
828 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
829 DCHECK(handler->is_handler());
831 ConfigureVectorState(name, receiver_map(), handler);
833 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
834 kind(), name, receiver_map(), handler, extra_ic_state());
840 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
842 CodeHandleList handlers;
844 if (!target()->FindHandlers(&handlers, maps.length())) return;
845 for (int i = 0; i < maps.length(); i++) {
846 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
851 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
852 if (source_map == NULL) return true;
853 if (target_map == NULL) return false;
854 ElementsKind target_elements_kind = target_map->elements_kind();
855 bool more_general_transition = IsMoreGeneralElementsKindTransition(
856 source_map->elements_kind(), target_elements_kind);
857 Map* transitioned_map =
858 more_general_transition
859 ? source_map->LookupElementsTransitionMap(target_elements_kind)
862 return transitioned_map == target_map;
866 void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
870 UpdateMonomorphicIC(code, name);
872 case PROTOTYPE_FAILURE:
875 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
876 if (UpdatePolymorphicIC(name, code)) break;
877 // For keyed stubs, we can't know whether old handlers were for the
879 CopyICToMegamorphicCache(name);
882 ConfigureVectorState(MEGAMORPHIC);
884 set_target(*megamorphic_stub());
888 UpdateMegamorphicCache(*receiver_map(), *name, *code);
889 // Indicate that we've handled this case.
906 Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
907 ExtraICState extra_state) {
908 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
912 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
913 Isolate* isolate, ExtraICState extra_state, State initialization_state) {
914 return LoadICStub(isolate, LoadICState(extra_state)).GetCode();
918 Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
919 return KeyedLoadICTrampolineStub(isolate).GetCode();
923 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
924 Isolate* isolate, State initialization_state) {
925 if (initialization_state != MEGAMORPHIC) {
926 return KeyedLoadICStub(isolate).GetCode();
928 switch (initialization_state) {
930 return isolate->builtins()->KeyedLoadIC_Initialize();
932 return isolate->builtins()->KeyedLoadIC_Megamorphic();
936 return Handle<Code>();
940 Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
941 LanguageMode language_mode,
942 State initialization_state) {
943 switch (initialization_state) {
945 return is_strict(language_mode)
946 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
947 : isolate->builtins()->KeyedStoreIC_Initialize();
949 return is_strict(language_mode)
950 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
951 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
953 return is_strict(language_mode)
954 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
955 : isolate->builtins()->KeyedStoreIC_Megamorphic();
959 return Handle<Code>();
963 Handle<Code> LoadIC::megamorphic_stub() {
964 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
965 return KeyedLoadIC::ChooseMegamorphicStub(isolate());
969 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
970 LoadFieldStub stub(isolate(), index);
971 return stub.GetCode();
975 void LoadIC::UpdateCaches(LookupIterator* lookup) {
976 if (state() == UNINITIALIZED) {
977 // This is the first time we execute this inline cache. Set the target to
978 // the pre monomorphic stub to delay setting the monomorphic state.
979 ConfigureVectorState(PREMONOMORPHIC);
980 TRACE_IC("LoadIC", lookup->name());
985 if (lookup->state() == LookupIterator::JSPROXY ||
986 lookup->state() == LookupIterator::ACCESS_CHECK) {
988 } else if (!lookup->IsFound()) {
989 if (kind() == Code::LOAD_IC) {
990 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
992 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
993 if (code.is_null()) code = slow_stub();
998 code = ComputeHandler(lookup);
1001 PatchCache(lookup->name(), code);
1002 TRACE_IC("LoadIC", lookup->name());
1006 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1007 isolate()->stub_cache()->Set(name, map, code);
1011 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1012 bool receiver_is_holder =
1013 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1014 CacheHolderFlag flag;
1015 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
1016 receiver_map(), receiver_is_holder, isolate(), &flag);
1018 Handle<Code> code = PropertyHandlerCompiler::Find(
1019 lookup->name(), stub_holder_map, kind(), flag,
1020 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1021 // Use the cached value if it exists, and if it is different from the
1022 // handler that just missed.
1023 if (!code.is_null()) {
1024 if (!maybe_handler_.is_null() &&
1025 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1028 if (maybe_handler_.is_null()) {
1029 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1030 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1031 // cache (which just missed) is different from the cached handler.
1032 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1033 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1034 Code* megamorphic_cached_code =
1035 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1036 if (megamorphic_cached_code != *code) return code;
1043 code = CompileHandler(lookup, value, flag);
1044 DCHECK(code->is_handler());
1046 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1047 // code compiled for this map, otherwise it's already cached in the global
1049 // cache. We are also guarding against installing code with flags that don't
1050 // match the desired CacheHolderFlag computed above, which would lead to
1051 // invalid lookups later.
1052 if (code->type() != Code::NORMAL &&
1053 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1054 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1061 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1062 Handle<Object> unused,
1063 CacheHolderFlag cache_holder) {
1064 Handle<Object> receiver = lookup->GetReceiver();
1065 if (receiver->IsString() &&
1066 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1067 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1068 return SimpleFieldLoad(index);
1071 if (receiver->IsStringWrapper() &&
1072 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1073 StringLengthStub string_length_stub(isolate());
1074 return string_length_stub.GetCode();
1077 // Use specialized code for getting prototype of functions.
1078 if (receiver->IsJSFunction() &&
1079 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1080 Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
1081 !Handle<JSFunction>::cast(receiver)
1083 ->has_non_instance_prototype()) {
1085 FunctionPrototypeStub function_prototype_stub(isolate());
1086 return function_prototype_stub.GetCode();
1089 Handle<Map> map = receiver_map();
1090 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1091 bool receiver_is_holder = receiver.is_identical_to(holder);
1092 switch (lookup->state()) {
1093 case LookupIterator::INTERCEPTOR: {
1094 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1095 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1096 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1097 // the original iterator will be used to fetch the value.
1098 LookupIterator it = *lookup;
1101 return compiler.CompileLoadInterceptor(&it);
1104 case LookupIterator::ACCESSOR: {
1105 // Use simple field loads for some well-known callback properties.
1106 // The method will only return true for absolute truths based on the
1109 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1111 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1112 return SimpleFieldLoad(index);
1114 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
1116 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1117 ArrayBufferViewLoadFieldStub stub(isolate(), index);
1118 return stub.GetCode();
1121 Handle<Object> accessors = lookup->GetAccessors();
1122 if (accessors->IsExecutableAccessorInfo()) {
1123 Handle<ExecutableAccessorInfo> info =
1124 Handle<ExecutableAccessorInfo>::cast(accessors);
1125 if (v8::ToCData<Address>(info->getter()) == 0) break;
1126 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1130 if (!holder->HasFastProperties()) break;
1131 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1132 return compiler.CompileLoadCallback(lookup->name(), info);
1134 if (accessors->IsAccessorPair()) {
1135 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1137 if (!getter->IsJSFunction()) break;
1138 if (!holder->HasFastProperties()) break;
1139 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1140 if (!receiver->IsJSObject() && !function->IsBuiltin() &&
1141 is_sloppy(function->shared()->language_mode())) {
1142 // Calling sloppy non-builtins with a value as the receiver
1146 CallOptimization call_optimization(function);
1147 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1148 if (call_optimization.is_simple_api_call() &&
1149 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1150 return compiler.CompileLoadCallback(lookup->name(), call_optimization,
1151 lookup->GetAccessorIndex());
1153 int expected_arguments =
1154 function->shared()->internal_formal_parameter_count();
1155 return compiler.CompileLoadViaGetter(
1156 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1161 case LookupIterator::DATA: {
1162 if (lookup->is_dictionary_holder()) {
1163 if (kind() != Code::LOAD_IC) break;
1164 if (holder->IsGlobalObject()) {
1165 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1167 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1168 Handle<Code> code = compiler.CompileLoadGlobal(
1169 cell, lookup->name(), lookup->IsConfigurable());
1170 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1171 CacheHolderFlag flag;
1172 Handle<Map> stub_holder_map =
1173 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
1174 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1177 // There is only one shared stub for loading normalized
1178 // properties. It does not traverse the prototype chain, so the
1179 // property must be found in the object for the stub to be
1181 if (!receiver_is_holder) break;
1182 return isolate()->builtins()->LoadIC_Normal();
1185 // -------------- Fields --------------
1186 if (lookup->property_details().type() == DATA) {
1187 FieldIndex field = lookup->GetFieldIndex();
1188 if (receiver_is_holder) {
1189 return SimpleFieldLoad(field);
1191 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1192 return compiler.CompileLoadField(lookup->name(), field);
1195 // -------------- Constant properties --------------
1196 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1197 if (receiver_is_holder) {
1198 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1199 return stub.GetCode();
1201 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1202 return compiler.CompileLoadConstant(lookup->name(),
1203 lookup->GetConstantIndex());
1206 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1208 case LookupIterator::ACCESS_CHECK:
1209 case LookupIterator::JSPROXY:
1210 case LookupIterator::NOT_FOUND:
1211 case LookupIterator::TRANSITION:
1219 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1220 // This helper implements a few common fast cases for converting
1221 // non-smi keys of keyed loads/stores to a smi or a string.
1222 if (key->IsHeapNumber()) {
1223 double value = Handle<HeapNumber>::cast(key)->value();
1224 if (std::isnan(value)) {
1225 key = isolate->factory()->nan_string();
1227 int int_value = FastD2I(value);
1228 if (value == int_value && Smi::IsValid(int_value)) {
1229 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1232 } else if (key->IsUndefined()) {
1233 key = isolate->factory()->undefined_string();
1239 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1240 Handle<Code> null_handle;
1241 Handle<Map> receiver_map(receiver->map(), isolate());
1242 MapHandleList target_receiver_maps;
1243 TargetMaps(&target_receiver_maps);
1246 if (target_receiver_maps.length() == 0) {
1247 Handle<Code> handler =
1248 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1249 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1253 // The first time a receiver is seen that is a transitioned version of the
1254 // previous monomorphic receiver type, assume the new ElementsKind is the
1255 // monomorphic type. This benefits global arrays that only transition
1256 // once, and all call sites accessing them are faster if they remain
1257 // monomorphic. If this optimistic assumption is not true, the IC will
1258 // miss again and it will become polymorphic and support both the
1259 // untransitioned and transitioned maps.
1260 if (state() == MONOMORPHIC && !receiver->IsString() &&
1261 IsMoreGeneralElementsKindTransition(
1262 target_receiver_maps.at(0)->elements_kind(),
1263 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1264 Handle<Code> handler =
1265 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1266 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1270 DCHECK(state() != GENERIC);
1272 // Determine the list of receiver maps that this call site has seen,
1273 // adding the map that was just encountered.
1274 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1275 // If the miss wasn't due to an unseen map, a polymorphic stub
1276 // won't help, use the generic stub.
1277 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
1278 return megamorphic_stub();
1281 // If the maximum number of receiver maps has been exceeded, use the generic
1282 // version of the IC.
1283 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1284 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
1285 return megamorphic_stub();
1288 CodeHandleList handlers(target_receiver_maps.length());
1289 ElementHandlerCompiler compiler(isolate());
1290 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1291 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
1296 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1297 Handle<Object> key) {
1298 if (MigrateDeprecated(object)) {
1299 Handle<Object> result;
1300 ASSIGN_RETURN_ON_EXCEPTION(
1301 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1306 Handle<Object> load_handle;
1307 Handle<Code> stub = megamorphic_stub();
1309 // Check for non-string values that can be converted into an
1310 // internalized string directly or is representable as a smi.
1311 key = TryConvertKey(key, isolate());
1313 if (key->IsInternalizedString() || key->IsSymbol()) {
1314 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1315 LoadIC::Load(object, Handle<Name>::cast(key)),
1317 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1318 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1319 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1320 if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
1321 stub = LoadElementStub(receiver);
1327 if (!is_target_set()) {
1328 Code* generic = *megamorphic_stub();
1329 if (*stub == generic) {
1330 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1334 TRACE_IC("LoadIC", key);
1337 if (!is_vector_set() || stub.is_null()) {
1338 Code* generic = *megamorphic_stub();
1339 if (!stub.is_null() && *stub == generic) {
1340 ConfigureVectorState(MEGAMORPHIC);
1341 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1344 TRACE_IC("LoadIC", key);
1348 if (!load_handle.is_null()) return load_handle;
1349 Handle<Object> result;
1350 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1351 Runtime::GetObjectProperty(isolate(), object, key),
1357 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1358 JSReceiver::StoreFromKeyed store_mode) {
1359 // Disable ICs for non-JSObjects for now.
1360 Handle<Object> receiver = it->GetReceiver();
1361 if (!receiver->IsJSObject()) return false;
1362 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1364 for (; it->IsFound(); it->Next()) {
1365 switch (it->state()) {
1366 case LookupIterator::NOT_FOUND:
1367 case LookupIterator::TRANSITION:
1369 case LookupIterator::JSPROXY:
1371 case LookupIterator::INTERCEPTOR: {
1372 Handle<JSObject> holder = it->GetHolder<JSObject>();
1373 InterceptorInfo* info = holder->GetNamedInterceptor();
1374 if (it->HolderIsReceiverOrHiddenPrototype()) {
1375 if (!info->setter()->IsUndefined()) return true;
1376 } else if (!info->getter()->IsUndefined() ||
1377 !info->query()->IsUndefined()) {
1382 case LookupIterator::ACCESS_CHECK:
1383 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1385 case LookupIterator::ACCESSOR:
1386 return !it->IsReadOnly();
1387 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1389 case LookupIterator::DATA: {
1390 if (it->IsReadOnly()) return false;
1391 Handle<JSObject> holder = it->GetHolder<JSObject>();
1392 if (receiver.is_identical_to(holder)) {
1393 it->PrepareForDataProperty(value);
1394 // The previous receiver map might just have been deprecated,
1396 update_receiver_map(receiver);
1400 // Receiver != holder.
1401 PrototypeIterator iter(it->isolate(), receiver);
1402 if (receiver->IsJSGlobalProxy()) {
1403 return it->GetHolder<Object>().is_identical_to(
1404 PrototypeIterator::GetCurrent(iter));
1407 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1408 return it->IsCacheableTransition();
1413 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1414 return it->IsCacheableTransition();
1418 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1419 Handle<Object> value,
1420 JSReceiver::StoreFromKeyed store_mode) {
1421 if (object->IsGlobalObject() && name->IsString()) {
1422 // Look up in script context table.
1423 Handle<String> str_name = Handle<String>::cast(name);
1424 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
1425 Handle<ScriptContextTable> script_contexts(
1426 global->native_context()->script_context_table());
1428 ScriptContextTable::LookupResult lookup_result;
1429 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1430 Handle<Context> script_context = ScriptContextTable::GetContext(
1431 script_contexts, lookup_result.context_index);
1432 if (lookup_result.mode == CONST) {
1433 return TypeError(MessageTemplate::kConstAssign, object, name);
1436 Handle<Object> previous_value =
1437 FixedArray::get(script_context, lookup_result.slot_index);
1439 if (*previous_value == *isolate()->factory()->the_hole_value()) {
1440 // Do not install stubs and stay pre-monomorphic for
1441 // uninitialized accesses.
1442 return ReferenceError(name);
1446 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1447 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1448 PatchCache(name, stub.GetCode());
1451 script_context->set(lookup_result.slot_index, *value);
1456 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1457 // might deprecate the current map again, if value does not fit.
1458 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1459 Handle<Object> result;
1460 ASSIGN_RETURN_ON_EXCEPTION(
1462 Object::SetProperty(object, name, value, language_mode()), Object);
1466 // If the object is undefined or null it's illegal to try to set any
1467 // properties on it; throw a TypeError in that case.
1468 if (object->IsUndefined() || object->IsNull()) {
1469 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1472 // Check if the given name is an array index.
1474 if (name->AsArrayIndex(&index)) {
1475 // Ignore other stores where the receiver is not a JSObject.
1476 // TODO(1475): Must check prototype chains of object wrappers.
1477 if (!object->IsJSObject()) return value;
1478 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1480 Handle<Object> result;
1481 ASSIGN_RETURN_ON_EXCEPTION(
1483 JSObject::SetElement(receiver, index, value, NONE, language_mode()),
1488 // Observed objects are always modified through the runtime.
1489 if (object->IsHeapObject() &&
1490 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1491 Handle<Object> result;
1492 ASSIGN_RETURN_ON_EXCEPTION(
1494 Object::SetProperty(object, name, value, language_mode(), store_mode),
1499 LookupIterator it(object, name);
1500 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1502 // Set the property.
1503 Handle<Object> result;
1504 ASSIGN_RETURN_ON_EXCEPTION(
1506 Object::SetProperty(&it, value, language_mode(), store_mode), Object);
1511 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
1512 CallICState::CallType call_type) {
1513 CallICTrampolineStub stub(isolate, CallICState(argc, call_type));
1514 Handle<Code> code = stub.GetCode();
1519 Handle<Code> CallIC::initialize_stub_in_optimized_code(
1520 Isolate* isolate, int argc, CallICState::CallType call_type) {
1521 CallICStub stub(isolate, CallICState(argc, call_type));
1522 Handle<Code> code = stub.GetCode();
1527 Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1528 LanguageMode language_mode,
1529 State initialization_state) {
1530 DCHECK(initialization_state == UNINITIALIZED ||
1531 initialization_state == PREMONOMORPHIC ||
1532 initialization_state == MEGAMORPHIC);
1533 ExtraICState extra_state = ComputeExtraICState(language_mode);
1534 Handle<Code> ic = PropertyICCompiler::ComputeStore(
1535 isolate, initialization_state, extra_state);
1540 Handle<Code> StoreIC::megamorphic_stub() {
1541 if (kind() == Code::STORE_IC) {
1542 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1545 DCHECK(kind() == Code::KEYED_STORE_IC);
1546 if (is_strict(language_mode())) {
1547 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
1549 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
1555 Handle<Code> StoreIC::slow_stub() const {
1556 if (kind() == Code::STORE_IC) {
1557 return isolate()->builtins()->StoreIC_Slow();
1559 DCHECK(kind() == Code::KEYED_STORE_IC);
1560 return isolate()->builtins()->KeyedStoreIC_Slow();
1565 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1566 LanguageMode language_mode) {
1567 ExtraICState state = ComputeExtraICState(language_mode);
1568 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1572 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1573 JSReceiver::StoreFromKeyed store_mode) {
1574 if (state() == UNINITIALIZED) {
1575 // This is the first time we execute this inline cache. Set the target to
1576 // the pre monomorphic stub to delay setting the monomorphic state.
1577 set_target(*pre_monomorphic_stub());
1578 TRACE_IC("StoreIC", lookup->name());
1582 bool use_ic = LookupForWrite(lookup, value, store_mode);
1584 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1586 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1588 PatchCache(lookup->name(), code);
1589 TRACE_IC("StoreIC", lookup->name());
1593 static Handle<Code> PropertyCellStoreHandler(
1594 Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
1595 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1596 auto constant_type = Nothing<PropertyCellConstantType>();
1597 if (type == PropertyCellType::kConstantType) {
1598 constant_type = Just(cell->GetConstantType());
1600 StoreGlobalStub stub(isolate, type, constant_type,
1601 receiver->IsJSGlobalProxy());
1602 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1603 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1604 HeapObject::UpdateMapCodeCache(receiver, name, code);
1609 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1610 Handle<Object> value,
1611 CacheHolderFlag cache_holder) {
1612 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1614 // This is currently guaranteed by checks in StoreIC::Store.
1615 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1616 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1617 DCHECK(!receiver->IsAccessCheckNeeded() ||
1618 isolate()->IsInternallyUsedPropertyName(lookup->name()));
1620 switch (lookup->state()) {
1621 case LookupIterator::TRANSITION: {
1622 auto store_target = lookup->GetStoreTarget();
1623 if (store_target->IsGlobalObject()) {
1624 // TODO(dcarney): this currently just deopts. Use the transition cell.
1625 auto cell = isolate()->factory()->NewPropertyCell();
1626 cell->set_value(*value);
1627 auto code = PropertyCellStoreHandler(
1628 isolate(), store_target, Handle<GlobalObject>::cast(store_target),
1629 lookup->name(), cell, PropertyCellType::kConstant);
1630 cell->set_value(isolate()->heap()->the_hole_value());
1633 Handle<Map> transition = lookup->transition_map();
1634 // Currently not handled by CompileStoreTransition.
1635 if (!holder->HasFastProperties()) {
1636 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1640 DCHECK(lookup->IsCacheableTransition());
1641 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1642 return compiler.CompileStoreTransition(transition, lookup->name());
1645 case LookupIterator::INTERCEPTOR: {
1646 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1647 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1648 return compiler.CompileStoreInterceptor(lookup->name());
1651 case LookupIterator::ACCESSOR: {
1652 if (!holder->HasFastProperties()) {
1653 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1656 Handle<Object> accessors = lookup->GetAccessors();
1657 if (accessors->IsExecutableAccessorInfo()) {
1658 Handle<ExecutableAccessorInfo> info =
1659 Handle<ExecutableAccessorInfo>::cast(accessors);
1660 if (v8::ToCData<Address>(info->setter()) == 0) {
1661 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1664 if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1665 !lookup->HolderIsReceiverOrHiddenPrototype()) {
1666 TRACE_GENERIC_IC(isolate(), "StoreIC",
1667 "special data property in prototype chain");
1670 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1672 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1675 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1676 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1677 } else if (accessors->IsAccessorPair()) {
1678 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1680 if (!setter->IsJSFunction()) {
1681 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1684 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1685 CallOptimization call_optimization(function);
1686 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1687 if (call_optimization.is_simple_api_call() &&
1688 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1689 return compiler.CompileStoreCallback(receiver, lookup->name(),
1691 lookup->GetAccessorIndex());
1693 int expected_arguments =
1694 function->shared()->internal_formal_parameter_count();
1695 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
1696 lookup->GetAccessorIndex(),
1697 expected_arguments);
1702 case LookupIterator::DATA: {
1703 if (lookup->is_dictionary_holder()) {
1704 if (holder->IsGlobalObject()) {
1705 DCHECK(holder.is_identical_to(receiver) ||
1706 receiver->map()->prototype() == *holder);
1707 auto cell = lookup->GetPropertyCell();
1708 auto updated_type = PropertyCell::UpdatedType(
1709 cell, value, lookup->property_details());
1710 auto code = PropertyCellStoreHandler(
1711 isolate(), receiver, Handle<GlobalObject>::cast(holder),
1712 lookup->name(), cell, updated_type);
1715 DCHECK(holder.is_identical_to(receiver));
1716 return isolate()->builtins()->StoreIC_Normal();
1719 // -------------- Fields --------------
1720 if (lookup->property_details().type() == DATA) {
1721 bool use_stub = true;
1722 if (lookup->representation().IsHeapObject()) {
1723 // Only use a generic stub if no types need to be tracked.
1724 Handle<HeapType> field_type = lookup->GetFieldType();
1725 HeapType::Iterator<Map> it = field_type->Classes();
1726 use_stub = it.Done();
1729 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1730 lookup->representation());
1731 return stub.GetCode();
1733 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1734 return compiler.CompileStoreField(lookup);
1737 // -------------- Constant properties --------------
1738 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1739 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1743 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1744 case LookupIterator::ACCESS_CHECK:
1745 case LookupIterator::JSPROXY:
1746 case LookupIterator::NOT_FOUND:
1753 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1754 KeyedAccessStoreMode store_mode) {
1755 // Don't handle megamorphic property accesses for INTERCEPTORS or
1756 // ACCESSOR_CONSTANT
1757 // via megamorphic stubs, since they don't have a map in their relocation info
1758 // and so the stubs can't be harvested for the object needed for a map check.
1759 if (target()->type() != Code::NORMAL) {
1760 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
1761 return megamorphic_stub();
1764 Handle<Map> receiver_map(receiver->map(), isolate());
1765 MapHandleList target_receiver_maps;
1766 TargetMaps(&target_receiver_maps);
1767 if (target_receiver_maps.length() == 0) {
1768 Handle<Map> monomorphic_map =
1769 ComputeTransitionedMap(receiver_map, store_mode);
1770 store_mode = GetNonTransitioningStoreMode(store_mode);
1771 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1772 monomorphic_map, language_mode(), store_mode);
1775 // There are several special cases where an IC that is MONOMORPHIC can still
1776 // transition to a different GetNonTransitioningStoreMode IC that handles a
1777 // superset of the original IC. Handle those here if the receiver map hasn't
1778 // changed or it has transitioned to a more general kind.
1779 KeyedAccessStoreMode old_store_mode =
1780 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
1781 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1782 if (state() == MONOMORPHIC) {
1783 Handle<Map> transitioned_receiver_map = receiver_map;
1784 if (IsTransitionStoreMode(store_mode)) {
1785 transitioned_receiver_map =
1786 ComputeTransitionedMap(receiver_map, store_mode);
1788 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1789 IsTransitionStoreMode(store_mode)) ||
1790 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1791 *transitioned_receiver_map)) {
1792 // If the "old" and "new" maps are in the same elements map family, or
1793 // if they at least come from the same origin for a transitioning store,
1794 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1795 store_mode = GetNonTransitioningStoreMode(store_mode);
1796 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1797 transitioned_receiver_map, language_mode(), store_mode);
1798 } else if (*previous_receiver_map == receiver->map() &&
1799 old_store_mode == STANDARD_STORE &&
1800 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1801 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1802 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1803 // A "normal" IC that handles stores can switch to a version that can
1804 // grow at the end of the array, handle OOB accesses or copy COW arrays
1805 // and still stay MONOMORPHIC.
1806 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1807 receiver_map, language_mode(), store_mode);
1811 DCHECK(state() != GENERIC);
1814 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1816 if (IsTransitionStoreMode(store_mode)) {
1817 Handle<Map> transitioned_receiver_map =
1818 ComputeTransitionedMap(receiver_map, store_mode);
1819 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1820 transitioned_receiver_map);
1824 // If the miss wasn't due to an unseen map, a polymorphic stub
1825 // won't help, use the megamorphic stub which can handle everything.
1826 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
1827 return megamorphic_stub();
1830 // If the maximum number of receiver maps has been exceeded, use the
1831 // megamorphic version of the IC.
1832 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1833 return megamorphic_stub();
1836 // Make sure all polymorphic handlers have the same store mode, otherwise the
1837 // megamorphic stub must be used.
1838 store_mode = GetNonTransitioningStoreMode(store_mode);
1839 if (old_store_mode != STANDARD_STORE) {
1840 if (store_mode == STANDARD_STORE) {
1841 store_mode = old_store_mode;
1842 } else if (store_mode != old_store_mode) {
1843 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
1844 return megamorphic_stub();
1848 // If the store mode isn't the standard mode, make sure that all polymorphic
1849 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1850 // use the megamorphic stub.
1851 if (store_mode != STANDARD_STORE) {
1852 int external_arrays = 0;
1853 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1854 if (target_receiver_maps[i]->has_external_array_elements() ||
1855 target_receiver_maps[i]->has_fixed_typed_array_elements()) {
1859 if (external_arrays != 0 &&
1860 external_arrays != target_receiver_maps.length()) {
1861 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1862 "unsupported combination of external and normal arrays");
1863 return megamorphic_stub();
1867 return PropertyICCompiler::ComputeKeyedStorePolymorphic(
1868 &target_receiver_maps, store_mode, language_mode());
1872 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1873 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1874 switch (store_mode) {
1875 case STORE_TRANSITION_SMI_TO_OBJECT:
1876 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1877 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1878 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1879 return Map::TransitionElementsTo(map, FAST_ELEMENTS);
1880 case STORE_TRANSITION_SMI_TO_DOUBLE:
1881 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1882 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS);
1883 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1884 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1885 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1886 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1887 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS);
1888 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1889 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1890 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
1891 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1892 DCHECK(map->has_external_array_elements());
1894 case STORE_NO_TRANSITION_HANDLE_COW:
1895 case STANDARD_STORE:
1896 case STORE_AND_GROW_NO_TRANSITION:
1900 return MaybeHandle<Map>().ToHandleChecked();
1904 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, int index) {
1905 if (receiver->IsJSArray()) {
1906 return JSArray::cast(*receiver)->length()->IsSmi() &&
1907 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1909 return index >= receiver->elements()->length();
1913 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1915 Handle<Object> value) {
1916 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked();
1917 int index = smi_key->value();
1918 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1919 // Don't consider this a growing store if the store would send the receiver to
1921 bool allow_growth = receiver->IsJSArray() && oob_access &&
1922 !receiver->WouldConvertToSlowElements(key);
1924 // Handle growing array in stub if necessary.
1925 if (receiver->HasFastSmiElements()) {
1926 if (value->IsHeapNumber()) {
1927 if (receiver->HasFastHoleyElements()) {
1928 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1930 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1933 if (value->IsHeapObject()) {
1934 if (receiver->HasFastHoleyElements()) {
1935 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1937 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1940 } else if (receiver->HasFastDoubleElements()) {
1941 if (!value->IsSmi() && !value->IsHeapNumber()) {
1942 if (receiver->HasFastHoleyElements()) {
1943 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1945 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1949 return STORE_AND_GROW_NO_TRANSITION;
1951 // Handle only in-bounds elements accesses.
1952 if (receiver->HasFastSmiElements()) {
1953 if (value->IsHeapNumber()) {
1954 if (receiver->HasFastHoleyElements()) {
1955 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1957 return STORE_TRANSITION_SMI_TO_DOUBLE;
1959 } else if (value->IsHeapObject()) {
1960 if (receiver->HasFastHoleyElements()) {
1961 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1963 return STORE_TRANSITION_SMI_TO_OBJECT;
1966 } else if (receiver->HasFastDoubleElements()) {
1967 if (!value->IsSmi() && !value->IsHeapNumber()) {
1968 if (receiver->HasFastHoleyElements()) {
1969 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1971 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1975 if (!FLAG_trace_external_array_abuse &&
1976 receiver->map()->has_external_array_elements() && oob_access) {
1977 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1979 Heap* heap = receiver->GetHeap();
1980 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1981 return STORE_NO_TRANSITION_HANDLE_COW;
1983 return STANDARD_STORE;
1989 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
1991 Handle<Object> value) {
1992 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1993 // might deprecate the current map again, if value does not fit.
1994 if (MigrateDeprecated(object)) {
1995 Handle<Object> result;
1996 ASSIGN_RETURN_ON_EXCEPTION(
1997 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
1998 value, language_mode()),
2003 // Check for non-string values that can be converted into an
2004 // internalized string directly or is representable as a smi.
2005 key = TryConvertKey(key, isolate());
2007 Handle<Object> store_handle;
2008 Handle<Code> stub = megamorphic_stub();
2010 if (key->IsInternalizedString() || key->IsSymbol()) {
2011 ASSIGN_RETURN_ON_EXCEPTION(
2012 isolate(), store_handle,
2013 StoreIC::Store(object, Handle<Name>::cast(key), value,
2014 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2016 if (!is_target_set()) {
2017 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2018 "unhandled internalized string key");
2019 TRACE_IC("StoreIC", key);
2022 return store_handle;
2026 FLAG_use_ic && !object->IsStringWrapper() &&
2027 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2028 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2029 if (use_ic && !object->IsSmi()) {
2030 // Don't use ICs for maps of the objects in Array's prototype chain. We
2031 // expect to be able to trap element sets to objects with those maps in
2032 // the runtime to enable optimization of element hole access.
2033 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2034 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2035 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2041 DCHECK(!object->IsAccessCheckNeeded());
2043 if (object->IsJSObject()) {
2044 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2045 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null();
2046 if (receiver->elements()->map() ==
2047 isolate()->heap()->sloppy_arguments_elements_map() &&
2048 !is_sloppy(language_mode())) {
2049 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2050 } else if (key_is_smi_like) {
2051 // We should go generic if receiver isn't a dictionary, but our
2052 // prototype chain does have dictionary elements. This ensures that
2053 // other non-dictionary receivers in the polymorphic case benefit
2054 // from fast path keyed stores.
2055 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
2056 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
2057 stub = StoreElementStub(receiver, store_mode);
2059 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype");
2062 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2065 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2069 if (store_handle.is_null()) {
2070 ASSIGN_RETURN_ON_EXCEPTION(
2071 isolate(), store_handle,
2072 Runtime::SetObjectProperty(isolate(), object, key, value,
2077 DCHECK(!is_target_set());
2078 Code* megamorphic = *megamorphic_stub();
2079 if (*stub == megamorphic) {
2080 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2082 if (*stub == *slow_stub()) {
2083 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
2085 DCHECK(!stub.is_null());
2086 if (!AddressIsDeoptimizedCode()) {
2089 TRACE_IC("StoreIC", key);
2091 return store_handle;
2095 bool CallIC::DoCustomHandler(Handle<Object> function,
2096 const CallICState& callic_state) {
2097 DCHECK(FLAG_use_ic && function->IsJSFunction());
2099 // Are we the array function?
2100 Handle<JSFunction> array_function =
2101 Handle<JSFunction>(isolate()->native_context()->array_function());
2102 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
2104 CallICNexus* nexus = casted_nexus<CallICNexus>();
2105 nexus->ConfigureMonomorphicArray();
2107 // Vector-based ICs have a different calling convention in optimized code
2108 // than full code so the correct stub has to be chosen.
2109 if (AddressIsOptimizedCode()) {
2110 CallIC_ArrayStub stub(isolate(), callic_state);
2111 set_target(*stub.GetCode());
2113 CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
2114 set_target(*stub.GetCode());
2117 Handle<String> name;
2118 if (array_function->shared()->name()->IsString()) {
2119 name = Handle<String>(String::cast(array_function->shared()->name()),
2122 TRACE_IC("CallIC", name);
2123 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2131 void CallIC::PatchMegamorphic(Handle<Object> function) {
2132 CallICState callic_state(target()->extra_ic_state());
2134 // We are going generic.
2135 CallICNexus* nexus = casted_nexus<CallICNexus>();
2136 nexus->ConfigureGeneric();
2138 // Vector-based ICs have a different calling convention in optimized code
2139 // than full code so the correct stub has to be chosen.
2140 if (AddressIsOptimizedCode()) {
2141 CallICStub stub(isolate(), callic_state);
2142 set_target(*stub.GetCode());
2144 CallICTrampolineStub stub(isolate(), callic_state);
2145 set_target(*stub.GetCode());
2148 Handle<Object> name = isolate()->factory()->empty_string();
2149 if (function->IsJSFunction()) {
2150 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2151 name = handle(js_function->shared()->name(), isolate());
2154 TRACE_IC("CallIC", name);
2155 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2160 void CallIC::HandleMiss(Handle<Object> function) {
2161 CallICState callic_state(target()->extra_ic_state());
2162 Handle<Object> name = isolate()->factory()->empty_string();
2163 CallICNexus* nexus = casted_nexus<CallICNexus>();
2164 Object* feedback = nexus->GetFeedback();
2166 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2167 DCHECK(!feedback->IsSmi());
2169 if (feedback->IsWeakCell() || !function->IsJSFunction()) {
2170 // We are going generic.
2171 nexus->ConfigureGeneric();
2173 // The feedback is either uninitialized or an allocation site.
2174 // It might be an allocation site because if we re-compile the full code
2175 // to add deoptimization support, we call with the default call-ic, and
2176 // merely need to patch the target to match the feedback.
2177 // TODO(mvstanton): the better approach is to dispense with patching
2178 // altogether, which is in progress.
2179 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) ||
2180 feedback->IsAllocationSite());
2182 // Do we want to install a custom handler?
2183 if (FLAG_use_ic && DoCustomHandler(function, callic_state)) {
2187 nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
2190 if (function->IsJSFunction()) {
2191 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2192 name = handle(js_function->shared()->name(), isolate());
2195 IC::State new_state = nexus->StateFromFeedback();
2196 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
2197 TRACE_IC("CallIC", name);
2204 // ----------------------------------------------------------------------------
2205 // Static IC stub generators.
2208 // Used from ic-<arch>.cc.
2209 RUNTIME_FUNCTION(CallIC_Miss) {
2210 TimerEventScope<TimerEventIcMiss> timer(isolate);
2211 HandleScope scope(isolate);
2212 DCHECK(args.length() == 3);
2213 Handle<Object> function = args.at<Object>(0);
2214 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2215 Handle<Smi> slot = args.at<Smi>(2);
2216 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2217 CallICNexus nexus(vector, vector_slot);
2218 CallIC ic(isolate, &nexus);
2219 ic.HandleMiss(function);
2224 RUNTIME_FUNCTION(CallIC_Customization_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 // A miss on a custom call ic always results in going megamorphic.
2234 CallIC ic(isolate, &nexus);
2235 ic.PatchMegamorphic(function);
2240 // Used from ic-<arch>.cc.
2241 RUNTIME_FUNCTION(LoadIC_Miss) {
2242 TimerEventScope<TimerEventIcMiss> timer(isolate);
2243 HandleScope scope(isolate);
2244 Handle<Object> receiver = args.at<Object>(0);
2245 Handle<Name> key = args.at<Name>(1);
2246 Handle<Object> result;
2248 DCHECK(args.length() == 4);
2249 Handle<Smi> slot = args.at<Smi>(2);
2250 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2251 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2252 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2253 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2254 // set up outside the IC, handle that here.
2255 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2256 LoadICNexus nexus(vector, vector_slot);
2257 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2258 ic.UpdateState(receiver, key);
2259 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2261 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2262 KeyedLoadICNexus nexus(vector, vector_slot);
2263 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2264 ic.UpdateState(receiver, key);
2265 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2271 // Used from ic-<arch>.cc
2272 RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
2273 TimerEventScope<TimerEventIcMiss> timer(isolate);
2274 HandleScope scope(isolate);
2275 Handle<Object> receiver = args.at<Object>(0);
2276 Handle<Object> key = args.at<Object>(1);
2277 Handle<Object> result;
2279 DCHECK(args.length() == 4);
2280 Handle<Smi> slot = args.at<Smi>(2);
2281 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2282 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2283 KeyedLoadICNexus nexus(vector, vector_slot);
2284 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2285 ic.UpdateState(receiver, key);
2286 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2291 RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
2292 TimerEventScope<TimerEventIcMiss> timer(isolate);
2293 HandleScope scope(isolate);
2294 Handle<Object> receiver = args.at<Object>(0);
2295 Handle<Object> key = args.at<Object>(1);
2296 Handle<Object> result;
2298 DCHECK(args.length() == 4);
2299 Handle<Smi> slot = args.at<Smi>(2);
2300 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2301 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2302 KeyedLoadICNexus nexus(vector, vector_slot);
2303 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2304 ic.UpdateState(receiver, key);
2305 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2311 // Used from ic-<arch>.cc.
2312 RUNTIME_FUNCTION(StoreIC_Miss) {
2313 TimerEventScope<TimerEventIcMiss> timer(isolate);
2314 HandleScope scope(isolate);
2315 DCHECK(args.length() == 3);
2316 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2317 Handle<Object> receiver = args.at<Object>(0);
2318 Handle<Name> key = args.at<Name>(1);
2319 ic.UpdateState(receiver, key);
2320 Handle<Object> result;
2321 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2322 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2327 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
2328 TimerEventScope<TimerEventIcMiss> timer(isolate);
2329 HandleScope scope(isolate);
2330 DCHECK(args.length() == 3 || args.length() == 4);
2331 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2332 Handle<Object> receiver = args.at<Object>(0);
2333 Handle<Name> key = args.at<Name>(1);
2334 ic.UpdateState(receiver, key);
2335 Handle<Object> result;
2336 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2337 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2342 // Used from ic-<arch>.cc.
2343 RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
2344 TimerEventScope<TimerEventIcMiss> timer(isolate);
2345 HandleScope scope(isolate);
2346 DCHECK(args.length() == 3);
2347 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2348 Handle<Object> receiver = args.at<Object>(0);
2349 Handle<Object> key = args.at<Object>(1);
2350 ic.UpdateState(receiver, key);
2351 Handle<Object> result;
2352 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2353 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2358 RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) {
2359 TimerEventScope<TimerEventIcMiss> timer(isolate);
2360 HandleScope scope(isolate);
2361 DCHECK(args.length() == 3);
2362 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2363 Handle<Object> receiver = args.at<Object>(0);
2364 Handle<Object> key = args.at<Object>(1);
2365 ic.UpdateState(receiver, key);
2366 Handle<Object> result;
2367 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2368 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2373 RUNTIME_FUNCTION(StoreIC_Slow) {
2374 HandleScope scope(isolate);
2375 DCHECK(args.length() == 3);
2376 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2377 Handle<Object> object = args.at<Object>(0);
2378 Handle<Object> key = args.at<Object>(1);
2379 Handle<Object> value = args.at<Object>(2);
2380 LanguageMode language_mode = ic.language_mode();
2381 Handle<Object> result;
2382 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2384 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2389 RUNTIME_FUNCTION(KeyedStoreIC_Slow) {
2390 HandleScope scope(isolate);
2391 DCHECK(args.length() == 3);
2392 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2393 Handle<Object> object = args.at<Object>(0);
2394 Handle<Object> key = args.at<Object>(1);
2395 Handle<Object> value = args.at<Object>(2);
2396 LanguageMode language_mode = ic.language_mode();
2397 Handle<Object> result;
2398 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2400 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2405 RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) {
2406 TimerEventScope<TimerEventIcMiss> timer(isolate);
2407 HandleScope scope(isolate);
2408 DCHECK(args.length() == 4);
2409 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2410 Handle<Object> value = args.at<Object>(0);
2411 Handle<Map> map = args.at<Map>(1);
2412 Handle<Object> key = args.at<Object>(2);
2413 Handle<Object> object = args.at<Object>(3);
2414 LanguageMode language_mode = ic.language_mode();
2415 if (object->IsJSObject()) {
2416 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2417 map->elements_kind());
2419 Handle<Object> result;
2420 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2422 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2427 MaybeHandle<Object> BinaryOpIC::Transition(
2428 Handle<AllocationSite> allocation_site, Handle<Object> left,
2429 Handle<Object> right) {
2430 BinaryOpICState state(isolate(), target()->extra_ic_state());
2432 // Compute the actual result using the builtin for the binary operation.
2433 Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
2434 TokenToJSBuiltin(state.op(), state.strength()));
2435 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
2436 Handle<Object> result;
2437 ASSIGN_RETURN_ON_EXCEPTION(
2438 isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
2441 // Do not try to update the target if the code was marked for lazy
2442 // deoptimization. (Since we do not relocate addresses in these
2443 // code objects, an attempt to access the target could fail.)
2444 if (AddressIsDeoptimizedCode()) {
2448 // Execution::Call can execute arbitrary JavaScript, hence potentially
2449 // update the state of this very IC, so we must update the stored state.
2452 // Compute the new state.
2453 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2454 state.Update(left, right, result);
2456 // Check if we have a string operation here.
2457 Handle<Code> target;
2458 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2459 // Setup the allocation site on-demand.
2460 if (allocation_site.is_null()) {
2461 allocation_site = isolate()->factory()->NewAllocationSite();
2464 // Install the stub with an allocation site.
2465 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2466 target = stub.GetCodeCopyFromTemplate(allocation_site);
2468 // Sanity check the trampoline stub.
2469 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2471 // Install the generic stub.
2472 BinaryOpICStub stub(isolate(), state);
2473 target = stub.GetCode();
2475 // Sanity check the generic stub.
2476 DCHECK_NULL(target->FindFirstAllocationSite());
2478 set_target(*target);
2480 if (FLAG_trace_ic) {
2481 OFStream os(stdout);
2482 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2483 << static_cast<void*>(*target) << " <- ";
2484 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2485 if (!allocation_site.is_null()) {
2486 os << " using allocation site " << static_cast<void*>(*allocation_site);
2488 os << "]" << std::endl;
2491 // Patch the inlined smi code as necessary.
2492 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2493 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2494 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2495 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2502 RUNTIME_FUNCTION(BinaryOpIC_Miss) {
2503 TimerEventScope<TimerEventIcMiss> timer(isolate);
2504 HandleScope scope(isolate);
2505 DCHECK_EQ(2, args.length());
2506 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2507 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2508 BinaryOpIC ic(isolate);
2509 Handle<Object> result;
2510 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2512 ic.Transition(Handle<AllocationSite>::null(), left, right));
2517 RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) {
2518 TimerEventScope<TimerEventIcMiss> timer(isolate);
2519 HandleScope scope(isolate);
2520 DCHECK_EQ(3, args.length());
2521 Handle<AllocationSite> allocation_site =
2522 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2523 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2524 Handle<Object> right =
2525 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2526 BinaryOpIC ic(isolate);
2527 Handle<Object> result;
2528 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2529 isolate, result, ic.Transition(allocation_site, left, right));
2534 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op,
2535 Strength strength) {
2536 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
2537 CompareICState::UNINITIALIZED,
2538 CompareICState::UNINITIALIZED);
2540 CHECK(stub.FindCodeInCache(&code));
2545 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op,
2546 Strength strength) {
2547 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
2548 CompareICState::UNINITIALIZED,
2549 CompareICState::UNINITIALIZED);
2550 return stub.GetCode();
2554 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2555 HandleScope scope(isolate());
2556 CompareICStub old_stub(target()->stub_key(), isolate());
2557 CompareICState::State new_left =
2558 CompareICState::NewInputState(old_stub.left(), x);
2559 CompareICState::State new_right =
2560 CompareICState::NewInputState(old_stub.right(), y);
2561 CompareICState::State state = CompareICState::TargetState(
2562 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2563 HasInlinedSmiCode(address()), x, y);
2564 CompareICStub stub(isolate(), op_, old_stub.strength(), new_left, new_right,
2566 if (state == CompareICState::KNOWN_OBJECT) {
2568 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2570 Handle<Code> new_target = stub.GetCode();
2571 set_target(*new_target);
2573 if (FLAG_trace_ic) {
2574 PrintF("[CompareIC in ");
2575 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2576 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2577 CompareICState::GetStateName(old_stub.left()),
2578 CompareICState::GetStateName(old_stub.right()),
2579 CompareICState::GetStateName(old_stub.state()),
2580 CompareICState::GetStateName(new_left),
2581 CompareICState::GetStateName(new_right),
2582 CompareICState::GetStateName(state), Token::Name(op_),
2583 static_cast<void*>(*stub.GetCode()));
2586 // Activate inlined smi code.
2587 if (old_stub.state() == CompareICState::UNINITIALIZED) {
2588 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2595 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2596 RUNTIME_FUNCTION(CompareIC_Miss) {
2597 TimerEventScope<TimerEventIcMiss> timer(isolate);
2598 HandleScope scope(isolate);
2599 DCHECK(args.length() == 3);
2600 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2601 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2605 void CompareNilIC::Clear(Address address, Code* target, Address constant_pool) {
2606 if (IsCleared(target)) return;
2607 ExtraICState state = target->extra_ic_state();
2609 CompareNilICStub stub(target->GetIsolate(), state,
2610 HydrogenCodeStub::UNINITIALIZED);
2614 CHECK(stub.FindCodeInCache(&code));
2616 SetTargetAtAddress(address, code, constant_pool);
2620 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2621 Handle<Object> object) {
2622 if (object->IsNull() || object->IsUndefined()) {
2623 return handle(Smi::FromInt(true), isolate);
2625 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate);
2629 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2630 ExtraICState extra_ic_state = target()->extra_ic_state();
2632 CompareNilICStub stub(isolate(), extra_ic_state);
2634 // Extract the current supported types from the patched IC and calculate what
2635 // types must be supported as a result of the miss.
2636 bool already_monomorphic = stub.IsMonomorphic();
2638 stub.UpdateStatus(object);
2640 NilValue nil = stub.nil_value();
2642 // Find or create the specialized stub to support the new set of types.
2644 if (stub.IsMonomorphic()) {
2645 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2647 : HeapObject::cast(*object)->map());
2648 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2650 code = stub.GetCode();
2653 return DoCompareNilSlow(isolate(), nil, object);
2657 RUNTIME_FUNCTION(CompareNilIC_Miss) {
2658 TimerEventScope<TimerEventIcMiss> timer(isolate);
2659 HandleScope scope(isolate);
2660 Handle<Object> object = args.at<Object>(0);
2661 CompareNilIC ic(isolate);
2662 return *ic.CompareNil(object);
2666 RUNTIME_FUNCTION(Unreachable) {
2669 return isolate->heap()->undefined_value();
2673 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op,
2674 Strength strength) {
2675 if (is_strong(strength)) {
2677 default: UNREACHABLE();
2678 case Token::ADD: return Builtins::ADD_STRONG;
2679 case Token::SUB: return Builtins::SUB_STRONG;
2680 case Token::MUL: return Builtins::MUL_STRONG;
2681 case Token::DIV: return Builtins::DIV_STRONG;
2682 case Token::MOD: return Builtins::MOD_STRONG;
2683 case Token::BIT_OR: return Builtins::BIT_OR_STRONG;
2684 case Token::BIT_AND: return Builtins::BIT_AND_STRONG;
2685 case Token::BIT_XOR: return Builtins::BIT_XOR_STRONG;
2686 case Token::SAR: return Builtins::SAR_STRONG;
2687 case Token::SHR: return Builtins::SHR_STRONG;
2688 case Token::SHL: return Builtins::SHL_STRONG;
2692 default: UNREACHABLE();
2693 case Token::ADD: return Builtins::ADD;
2694 case Token::SUB: return Builtins::SUB;
2695 case Token::MUL: return Builtins::MUL;
2696 case Token::DIV: return Builtins::DIV;
2697 case Token::MOD: return Builtins::MOD;
2698 case Token::BIT_OR: return Builtins::BIT_OR;
2699 case Token::BIT_AND: return Builtins::BIT_AND;
2700 case Token::BIT_XOR: return Builtins::BIT_XOR;
2701 case Token::SAR: return Builtins::SAR;
2702 case Token::SHR: return Builtins::SHR;
2703 case Token::SHL: return Builtins::SHL;
2709 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2710 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2711 bool to_boolean_value = stub.UpdateStatus(object);
2712 Handle<Code> code = stub.GetCode();
2714 return handle(Smi::FromInt(to_boolean_value ? 1 : 0), isolate());
2718 RUNTIME_FUNCTION(ToBooleanIC_Miss) {
2719 TimerEventScope<TimerEventIcMiss> timer(isolate);
2720 DCHECK(args.length() == 1);
2721 HandleScope scope(isolate);
2722 Handle<Object> object = args.at<Object>(0);
2723 ToBooleanIC ic(isolate);
2724 return *ic.ToBoolean(object);
2728 RUNTIME_FUNCTION(StoreCallbackProperty) {
2729 Handle<JSObject> receiver = args.at<JSObject>(0);
2730 Handle<JSObject> holder = args.at<JSObject>(1);
2731 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
2732 Handle<Name> name = args.at<Name>(3);
2733 Handle<Object> value = args.at<Object>(4);
2734 HandleScope scope(isolate);
2736 Handle<ExecutableAccessorInfo> callback(
2737 callback_or_cell->IsWeakCell()
2738 ? ExecutableAccessorInfo::cast(
2739 WeakCell::cast(*callback_or_cell)->value())
2740 : ExecutableAccessorInfo::cast(*callback_or_cell));
2742 DCHECK(callback->IsCompatibleReceiver(*receiver));
2744 Address setter_address = v8::ToCData<Address>(callback->setter());
2745 v8::AccessorNameSetterCallback fun =
2746 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2747 DCHECK(fun != NULL);
2749 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2750 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2752 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2753 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2759 * Attempts to load a property with an interceptor (which must be present),
2760 * but doesn't search the prototype chain.
2762 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2763 * provide any value for the given name.
2765 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
2766 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2768 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2769 Handle<JSObject> receiver =
2770 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2771 Handle<JSObject> holder =
2772 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2773 HandleScope scope(isolate);
2774 LookupIterator it(receiver, name, holder, LookupIterator::OWN);
2775 auto res = JSObject::GetPropertyWithInterceptor(&it);
2776 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2777 Handle<Object> result;
2778 if (res.ToHandle(&result)) return *result;
2779 return isolate->heap()->no_interceptor_result_sentinel();
2783 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
2784 // If the load is non-contextual, just return the undefined result.
2785 // Note that both keyed and non-keyed loads may end up here.
2786 HandleScope scope(isolate);
2787 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
2788 if (ic.contextual_mode() != CONTEXTUAL) {
2789 return isolate->heap()->undefined_value();
2792 // Throw a reference error.
2793 Handle<Name> name_handle(name);
2794 THROW_NEW_ERROR_RETURN_FAILURE(
2795 isolate, NewReferenceError(MessageTemplate::kNotDefined, name_handle));
2800 * Loads a property with an interceptor performing post interceptor
2801 * lookup if interceptor failed.
2803 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
2804 HandleScope scope(isolate);
2805 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2807 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2808 Handle<JSObject> receiver =
2809 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2810 Handle<JSObject> holder =
2811 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2813 Handle<Object> result;
2814 LookupIterator it(receiver, name, holder);
2815 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2816 JSObject::GetProperty(&it));
2818 if (it.IsFound()) return *result;
2820 return ThrowReferenceError(isolate, Name::cast(args[0]));
2824 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
2825 HandleScope scope(isolate);
2826 DCHECK(args.length() == 3);
2827 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2828 Handle<JSObject> receiver = args.at<JSObject>(0);
2829 Handle<Name> name = args.at<Name>(1);
2830 Handle<Object> value = args.at<Object>(2);
2832 PrototypeIterator iter(isolate, receiver,
2833 PrototypeIterator::START_AT_RECEIVER);
2835 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
2836 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2837 if (current->IsJSObject() &&
2838 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2845 Handle<Object> result;
2846 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2848 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
2853 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
2854 // TODO(verwaest): This should probably get the holder and receiver as input.
2855 HandleScope scope(isolate);
2856 Handle<JSObject> receiver = args.at<JSObject>(0);
2857 DCHECK(args.smi_at(1) >= 0);
2858 uint32_t index = args.smi_at(1);
2859 Handle<Object> result;
2860 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2861 isolate, result, Object::GetElement(isolate, receiver, index));
2866 RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
2867 TimerEventScope<TimerEventIcMiss> timer(isolate);
2868 HandleScope scope(isolate);
2869 Handle<Object> receiver = args.at<Object>(0);
2870 Handle<Name> key = args.at<Name>(1);
2871 Handle<Object> result;
2873 DCHECK(args.length() == 4);
2874 Handle<Smi> slot = args.at<Smi>(2);
2875 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2876 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2877 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2878 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2879 // set up outside the IC, handle that here.
2880 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2881 LoadICNexus nexus(vector, vector_slot);
2882 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2883 ic.UpdateState(receiver, key);
2884 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2886 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2887 KeyedLoadICNexus nexus(vector, vector_slot);
2888 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2889 ic.UpdateState(receiver, key);
2890 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2897 static const Address IC_utilities[] = {
2898 #define ADDR(name) FUNCTION_ADDR(name),
2899 IC_UTIL_LIST(ADDR) NULL
2904 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; }
2905 } // namespace internal