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/macro-assembler.h"
20 #include "src/prototype.h"
21 #include "src/runtime/runtime.h"
26 char IC::TransitionMarkFromState(IC::State state) {
34 case PROTOTYPE_FAILURE:
43 // We never see the debugger states here, because the state is
44 // computed from the original code - not the patched code. Let
45 // these cases fall through to the unreachable code below.
48 // Type-vector-based ICs resolve state to one of the above.
57 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
58 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
59 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
62 if (IsGrowStoreMode(mode)) return ".GROW";
69 #define TRACE_GENERIC_IC(isolate, type, reason) \
71 if (FLAG_trace_ic) { \
72 PrintF("[%s patching generic stub in ", type); \
73 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
74 PrintF(" (%s)]\n", reason); \
80 #define TRACE_GENERIC_IC(isolate, type, reason) \
82 if (FLAG_trace_ic) { \
83 PrintF("[%s patching generic stub in ", type); \
84 PrintF("(see below) (%s)]\n", reason); \
91 void IC::TraceIC(const char* type, Handle<Object> name) {
93 if (AddressIsDeoptimizedCode()) return;
95 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
96 TraceIC(type, name, state(), new_state);
101 void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
104 Code* new_target = raw_target();
105 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
107 // TODO(jkummerow): Add support for "apply". The logic is roughly:
108 // marker = [fp_ + kMarkerOffset];
109 // if marker is smi and marker.value == INTERNAL and
110 // the frame's code == builtin(Builtins::kFunctionApply):
111 // then print "apply from" and advance one frame
113 Object* maybe_function =
114 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
115 if (maybe_function->IsJSFunction()) {
116 JSFunction* function = JSFunction::cast(maybe_function);
117 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
121 ExtraICState extra_state = new_target->extra_ic_state();
122 const char* modifier = "";
123 if (new_target->kind() == Code::KEYED_STORE_IC) {
124 modifier = GetTransitionMarkModifier(
125 KeyedStoreIC::GetKeyedAccessStoreMode(extra_state));
127 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
128 TransitionMarkFromState(new_state), modifier);
133 name->ShortPrint(stdout);
140 #define TRACE_IC(type, name) TraceIC(type, name)
143 IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
144 bool for_queries_only)
148 target_maps_set_(false),
150 // To improve the performance of the (much used) IC code, we unfold a few
151 // levels of the stack frame iteration code. This yields a ~35% speedup when
152 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
153 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
154 Address* constant_pool = NULL;
155 if (FLAG_enable_embedded_constant_pool) {
156 constant_pool = reinterpret_cast<Address*>(
157 entry + ExitFrameConstants::kConstantPoolOffset);
159 Address* pc_address =
160 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
161 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
162 // If there's another JavaScript frame on the stack or a
163 // StubFailureTrampoline, we need to look one frame further down the stack to
164 // find the frame pointer and the return address stack slot.
165 if (depth == EXTRA_CALL_FRAME) {
166 if (FLAG_enable_embedded_constant_pool) {
167 constant_pool = reinterpret_cast<Address*>(
168 fp + StandardFrameConstants::kConstantPoolOffset);
170 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
171 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
172 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
175 StackFrameIterator it(isolate);
176 for (int i = 0; i < depth + 1; i++) it.Advance();
177 StackFrame* frame = it.frame();
178 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
181 if (FLAG_enable_embedded_constant_pool) {
182 constant_pool_address_ = constant_pool;
184 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
185 target_ = handle(raw_target(), isolate);
186 kind_ = target_->kind();
187 state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
188 : target_->ic_state();
190 extra_ic_state_ = target_->extra_ic_state();
194 SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
195 // Compute the JavaScript frame for the frame pointer of this IC
196 // structure. We need this to be able to find the function
197 // corresponding to the frame.
198 StackFrameIterator it(isolate());
199 while (it.frame()->fp() != this->fp()) it.Advance();
200 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
201 // Find the function on the stack and both the active code for the
202 // function and the original code.
203 JSFunction* function = frame->function();
204 return function->shared();
208 Code* IC::GetCode() const {
209 HandleScope scope(isolate());
210 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
211 Code* code = shared->code();
216 bool IC::AddressIsOptimizedCode() const {
218 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
219 return host->kind() == Code::OPTIMIZED_FUNCTION;
223 static void LookupForRead(LookupIterator* it) {
224 for (; it->IsFound(); it->Next()) {
225 switch (it->state()) {
226 case LookupIterator::NOT_FOUND:
227 case LookupIterator::TRANSITION:
229 case LookupIterator::JSPROXY:
231 case LookupIterator::INTERCEPTOR: {
232 // If there is a getter, return; otherwise loop to perform the lookup.
233 Handle<JSObject> holder = it->GetHolder<JSObject>();
234 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
239 case LookupIterator::ACCESS_CHECK:
240 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
241 // access checks for global proxies.
242 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
246 case LookupIterator::ACCESSOR:
247 case LookupIterator::INTEGER_INDEXED_EXOTIC:
248 case LookupIterator::DATA:
255 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
256 Handle<String> name) {
257 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
259 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
261 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
264 // The current map wasn't handled yet. There's no reason to stay monomorphic,
265 // *unless* we're moving from a deprecated map to its replacement, or
266 // to a more general elements kind.
267 // TODO(verwaest): Check if the current map is actually what the old map
268 // would transition to.
269 if (maybe_handler_.is_null()) {
270 if (!receiver_map()->IsJSObjectMap()) return false;
271 Map* first_map = FirstTargetMap();
272 if (first_map == NULL) return false;
273 Handle<Map> old_map(first_map);
274 if (old_map->is_deprecated()) return true;
275 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
276 receiver_map()->elements_kind())) {
282 CacheHolderFlag flag;
283 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
285 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
286 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
287 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
289 if (state() == MONOMORPHIC) {
290 int index = ic_holder_map->IndexInCodeCache(*name, *target());
292 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
296 if (receiver->IsGlobalObject()) {
297 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
298 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
299 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
300 if (!it.IsFound()) return false;
301 return it.property_details().cell_type() == PropertyCellType::kConstant;
308 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
309 if (target()->is_keyed_stub()) {
310 // Determine whether the failure is due to a name failure.
311 if (!name->IsName()) return false;
313 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
314 if (*name != stub_name) return false;
321 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
322 update_receiver_map(receiver);
323 if (!name->IsString()) return;
324 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
325 if (receiver->IsUndefined() || receiver->IsNull()) return;
327 // Remove the target from the code cache if it became invalid
328 // because of changes in the prototype chain to avoid hitting it
330 if (TryRemoveInvalidPrototypeDependentStub(receiver,
331 Handle<String>::cast(name))) {
332 MarkPrototypeFailure(name);
336 // The builtins object is special. It only changes when JavaScript
337 // builtins are loaded lazily. It is important to keep inline
338 // caches for the builtins object monomorphic. Therefore, if we get
339 // an inline cache miss for the builtins object after lazily loading
340 // JavaScript builtins, we return uninitialized as the state to
341 // force the inline cache back to monomorphic state.
342 if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
346 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
347 Handle<Object> object, Handle<Object> key) {
348 HandleScope scope(isolate());
349 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
353 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
354 HandleScope scope(isolate());
356 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
360 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
361 int* polymorphic_delta,
362 int* generic_delta) {
366 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
367 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
368 *polymorphic_delta = 1;
369 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
375 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
376 *polymorphic_delta = -1;
377 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
383 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
385 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
386 *polymorphic_delta = 1;
389 case PROTOTYPE_FAILURE:
397 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
398 State old_state, State new_state,
399 bool target_remains_ic_stub) {
401 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
402 if (host->kind() != Code::FUNCTION) return;
404 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
405 // Not all Code objects have TypeFeedbackInfo.
406 host->type_feedback_info()->IsTypeFeedbackInfo()) {
407 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
408 int generic_delta = 0; // "Generic" here includes megamorphic.
409 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
411 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
412 info->change_ic_with_type_info_count(polymorphic_delta);
413 info->change_ic_generic_count(generic_delta);
415 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
416 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
417 info->change_own_type_change_checksum();
419 host->set_profiler_ticks(0);
420 isolate->runtime_profiler()->NotifyICChanged();
421 // TODO(2029): When an optimized function is patched, it would
422 // be nice to propagate the corresponding type information to its
423 // unoptimized version for the benefit of later inlining.
428 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
429 TypeFeedbackVector* vector, State old_state,
431 if (host->kind() != Code::FUNCTION) return;
433 if (FLAG_type_info_threshold > 0) {
434 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
435 int generic_delta = 0; // "Generic" here includes megamorphic.
436 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
438 vector->change_ic_with_type_info_count(polymorphic_delta);
439 vector->change_ic_generic_count(generic_delta);
441 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
442 info->change_own_type_change_checksum();
443 host->set_profiler_ticks(0);
444 isolate->runtime_profiler()->NotifyICChanged();
445 // TODO(2029): When an optimized function is patched, it would
446 // be nice to propagate the corresponding type information to its
447 // unoptimized version for the benefit of later inlining.
451 void IC::PostPatching(Address address, Code* target, Code* old_target) {
452 // Type vector based ICs update these statistics at a different time because
453 // they don't always patch on state change.
454 if (ICUseVector(target->kind())) return;
456 Isolate* isolate = target->GetHeap()->isolate();
457 State old_state = UNINITIALIZED;
458 State new_state = UNINITIALIZED;
459 bool target_remains_ic_stub = false;
460 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
461 old_state = old_target->ic_state();
462 new_state = target->ic_state();
463 target_remains_ic_stub = true;
466 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
467 target_remains_ic_stub);
471 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
472 Code* target = GetTargetAtAddress(address, constant_pool);
474 // Don't clear debug break inline cache as it will remove the break point.
475 if (target->is_debug_stub()) return;
477 switch (target->kind()) {
479 case Code::KEYED_LOAD_IC:
482 if (FLAG_vector_stores) return;
483 return StoreIC::Clear(isolate, address, target, constant_pool);
484 case Code::KEYED_STORE_IC:
485 if (FLAG_vector_stores) return;
486 return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
487 case Code::COMPARE_IC:
488 return CompareIC::Clear(isolate, address, target, constant_pool);
489 case Code::COMPARE_NIL_IC:
490 return CompareNilIC::Clear(address, target, constant_pool);
491 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
492 case Code::BINARY_OP_IC:
493 case Code::TO_BOOLEAN_IC:
494 // Clearing these is tricky and does not
495 // make any performance difference.
503 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
504 if (IsCleared(nexus)) return;
505 // Make sure to also clear the map used in inline fast cases. If we
506 // do not clear these maps, cached code can keep objects alive
507 // through the embedded maps.
508 State state = nexus->StateFromFeedback();
509 nexus->ConfigurePremonomorphic();
510 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
514 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
515 // Determine our state.
516 Object* feedback = nexus->vector()->Get(nexus->slot());
517 State state = nexus->StateFromFeedback();
519 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
520 nexus->ConfigureUninitialized();
521 // The change in state must be processed.
522 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
527 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
528 if (IsCleared(nexus)) return;
529 State state = nexus->StateFromFeedback();
530 nexus->ConfigurePremonomorphic();
531 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
535 void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
536 Address constant_pool) {
537 if (IsCleared(target)) return;
538 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
539 target->extra_ic_state());
540 SetTargetAtAddress(address, code, constant_pool);
544 void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
545 if (IsCleared(nexus)) return;
546 State state = nexus->StateFromFeedback();
547 nexus->ConfigurePremonomorphic();
548 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
552 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
553 Address constant_pool) {
554 if (IsCleared(target)) return;
555 Handle<Code> code = pre_monomorphic_stub(
556 isolate, StoreICState::GetLanguageMode(target->extra_ic_state()));
557 SetTargetAtAddress(address, *code, constant_pool);
561 void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
562 KeyedStoreICNexus* nexus) {
563 if (IsCleared(nexus)) return;
564 State state = nexus->StateFromFeedback();
565 nexus->ConfigurePremonomorphic();
566 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
570 void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
571 Address constant_pool) {
572 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
573 CompareICStub stub(target->stub_key(), isolate);
574 // Only clear CompareICs that can retain objects.
575 if (stub.state() != CompareICState::KNOWN_OBJECT) return;
576 SetTargetAtAddress(address,
577 GetRawUninitialized(isolate, stub.op(), stub.strength()),
579 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
584 Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate,
585 ExtraICState extra_state) {
586 if (FLAG_compiled_keyed_generic_loads) {
587 return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode();
589 return is_strong(LoadICState::GetLanguageMode(extra_state))
590 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong()
591 : isolate->builtins()->KeyedLoadIC_Megamorphic();
596 static bool MigrateDeprecated(Handle<Object> object) {
597 if (!object->IsJSObject()) return false;
598 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
599 if (!receiver->map()->is_deprecated()) return false;
600 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
605 void IC::ConfigureVectorState(IC::State new_state) {
607 if (new_state == PREMONOMORPHIC) {
608 nexus()->ConfigurePremonomorphic();
609 } else if (new_state == MEGAMORPHIC) {
610 nexus()->ConfigureMegamorphic();
616 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
621 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
622 Handle<Code> handler) {
624 if (kind() == Code::LOAD_IC) {
625 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
626 nexus->ConfigureMonomorphic(map, handler);
627 } else if (kind() == Code::KEYED_LOAD_IC) {
628 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
629 nexus->ConfigureMonomorphic(name, map, handler);
630 } else if (kind() == Code::STORE_IC) {
631 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
632 nexus->ConfigureMonomorphic(map, handler);
634 DCHECK(kind() == Code::KEYED_STORE_IC);
635 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
636 nexus->ConfigureMonomorphic(name, map, handler);
640 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
645 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
646 CodeHandleList* handlers) {
648 if (kind() == Code::LOAD_IC) {
649 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
650 nexus->ConfigurePolymorphic(maps, handlers);
651 } else if (kind() == Code::KEYED_LOAD_IC) {
652 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
653 nexus->ConfigurePolymorphic(name, maps, handlers);
654 } else if (kind() == Code::STORE_IC) {
655 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
656 nexus->ConfigurePolymorphic(maps, handlers);
658 DCHECK(kind() == Code::KEYED_STORE_IC);
659 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
660 nexus->ConfigurePolymorphic(name, maps, handlers);
664 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
669 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
670 // If the object is undefined or null it's illegal to try to get any
671 // of its properties; throw a TypeError in that case.
672 if (object->IsUndefined() || object->IsNull()) {
673 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
676 // Check if the name is trivially convertible to an index and get
677 // the element or char if so.
679 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
680 // Rewrite to the generic keyed load stub.
683 ConfigureVectorState(MEGAMORPHIC);
684 TRACE_IC("LoadIC", name);
685 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
687 Handle<Object> result;
688 ASSIGN_RETURN_ON_EXCEPTION(
690 Object::GetElement(isolate(), object, index, language_mode()), Object);
694 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
696 if (object->IsGlobalObject() && name->IsString()) {
697 // Look up in script context table.
698 Handle<String> str_name = Handle<String>::cast(name);
699 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
700 Handle<ScriptContextTable> script_contexts(
701 global->native_context()->script_context_table());
703 ScriptContextTable::LookupResult lookup_result;
704 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
705 Handle<Object> result =
706 FixedArray::get(ScriptContextTable::GetContext(
707 script_contexts, lookup_result.context_index),
708 lookup_result.slot_index);
709 if (*result == *isolate()->factory()->the_hole_value()) {
710 // Do not install stubs and stay pre-monomorphic for
711 // uninitialized accesses.
712 return ReferenceError(name);
715 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
716 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
717 PatchCache(name, stub.GetCode());
723 // Named lookup in the object.
724 LookupIterator it(object, name);
727 if (it.IsFound() || !ShouldThrowReferenceError(object)) {
728 // Update inline cache and stub cache.
729 if (use_ic) UpdateCaches(&it);
732 Handle<Object> result;
734 ASSIGN_RETURN_ON_EXCEPTION(
735 isolate(), result, Object::GetProperty(&it, language_mode()), Object);
738 } else if (!ShouldThrowReferenceError(object)) {
739 LOG(isolate(), SuspectReadEvent(*name, *object));
743 return ReferenceError(name);
747 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
748 Handle<Map> new_receiver_map) {
749 DCHECK(!new_receiver_map.is_null());
750 for (int current = 0; current < receiver_maps->length(); ++current) {
751 if (!receiver_maps->at(current).is_null() &&
752 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
756 receiver_maps->Add(new_receiver_map);
761 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
762 if (!code->is_handler()) return false;
763 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
764 Handle<Map> map = receiver_map();
766 CodeHandleList handlers;
769 int number_of_maps = maps.length();
770 int deprecated_maps = 0;
771 int handler_to_overwrite = -1;
773 for (int i = 0; i < number_of_maps; i++) {
774 Handle<Map> current_map = maps.at(i);
775 if (current_map->is_deprecated()) {
776 // Filter out deprecated maps to ensure their instances get migrated.
778 } else if (map.is_identical_to(current_map)) {
779 // If the receiver type is already in the polymorphic IC, this indicates
780 // there was a prototoype chain failure. In that case, just overwrite the
782 handler_to_overwrite = i;
783 } else if (handler_to_overwrite == -1 &&
784 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
785 handler_to_overwrite = i;
789 int number_of_valid_maps =
790 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
792 if (number_of_valid_maps >= 4) return false;
793 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
797 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
799 if (!target()->FindHandlers(&handlers, maps.length())) return false;
802 number_of_valid_maps++;
803 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
805 if (number_of_valid_maps == 1) {
807 ConfigureVectorState(name, receiver_map(), code);
809 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, map, code,
813 if (handler_to_overwrite >= 0) {
814 handlers.Set(handler_to_overwrite, code);
815 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
816 maps.Set(handler_to_overwrite, map);
824 ConfigureVectorState(name, &maps, &handlers);
826 ic = PropertyICCompiler::ComputePolymorphic(kind(), &maps, &handlers,
827 number_of_valid_maps, name,
832 if (!UseVector()) set_target(*ic);
837 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
838 DCHECK(handler->is_handler());
840 ConfigureVectorState(name, receiver_map(), handler);
842 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
843 kind(), name, receiver_map(), handler, extra_ic_state());
849 void IC::CopyICToMegamorphicCache(Handle<Name> name) {
851 CodeHandleList handlers;
853 if (!target()->FindHandlers(&handlers, maps.length())) return;
854 for (int i = 0; i < maps.length(); i++) {
855 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
860 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
861 if (source_map == NULL) return true;
862 if (target_map == NULL) return false;
863 ElementsKind target_elements_kind = target_map->elements_kind();
864 bool more_general_transition = IsMoreGeneralElementsKindTransition(
865 source_map->elements_kind(), target_elements_kind);
866 Map* transitioned_map =
867 more_general_transition
868 ? source_map->LookupElementsTransitionMap(target_elements_kind)
871 return transitioned_map == target_map;
875 void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
879 UpdateMonomorphicIC(code, name);
881 case PROTOTYPE_FAILURE:
884 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
885 if (UpdatePolymorphicIC(name, code)) break;
886 // For keyed stubs, we can't know whether old handlers were for the
888 CopyICToMegamorphicCache(name);
891 ConfigureVectorState(MEGAMORPHIC);
893 set_target(*megamorphic_stub());
897 UpdateMegamorphicCache(*receiver_map(), *name, *code);
898 // Indicate that we've handled this case.
915 Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
916 ExtraICState extra_state) {
917 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
921 Handle<Code> LoadIC::initialize_stub_in_optimized_code(
922 Isolate* isolate, ExtraICState extra_state, State initialization_state) {
923 return LoadICStub(isolate, LoadICState(extra_state)).GetCode();
927 Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate,
928 ExtraICState extra_state) {
929 return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
933 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
934 Isolate* isolate, State initialization_state, ExtraICState extra_state) {
935 if (initialization_state != MEGAMORPHIC) {
936 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode();
938 return is_strong(LoadICState::GetLanguageMode(extra_state))
939 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong()
940 : isolate->builtins()->KeyedLoadIC_Megamorphic();
944 static Handle<Code> KeyedStoreICInitializeStubHelper(
945 Isolate* isolate, LanguageMode language_mode,
946 InlineCacheState initialization_state) {
947 switch (initialization_state) {
949 return is_strict(language_mode)
950 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
951 : isolate->builtins()->KeyedStoreIC_Initialize();
953 return is_strict(language_mode)
954 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
955 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
957 return is_strict(language_mode)
958 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
959 : isolate->builtins()->KeyedStoreIC_Megamorphic();
963 return Handle<Code>();
967 Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
968 LanguageMode language_mode,
969 State initialization_state) {
970 if (FLAG_vector_stores) {
971 VectorKeyedStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
972 return stub.GetCode();
975 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
976 initialization_state);
980 Handle<Code> KeyedStoreIC::initialize_stub_in_optimized_code(
981 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
982 if (FLAG_vector_stores && initialization_state != MEGAMORPHIC) {
983 VectorKeyedStoreICStub stub(isolate, StoreICState(language_mode));
984 return stub.GetCode();
987 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
988 initialization_state);
992 Handle<Code> LoadIC::megamorphic_stub() {
993 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
994 return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state());
998 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
999 LoadFieldStub stub(isolate(), index);
1000 return stub.GetCode();
1004 void LoadIC::UpdateCaches(LookupIterator* lookup) {
1005 if (state() == UNINITIALIZED) {
1006 // This is the first time we execute this inline cache. Set the target to
1007 // the pre monomorphic stub to delay setting the monomorphic state.
1008 ConfigureVectorState(PREMONOMORPHIC);
1009 TRACE_IC("LoadIC", lookup->name());
1014 if (lookup->state() == LookupIterator::JSPROXY ||
1015 lookup->state() == LookupIterator::ACCESS_CHECK) {
1017 } else if (!lookup->IsFound()) {
1018 if (kind() == Code::LOAD_IC && !is_strong(language_mode())) {
1019 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
1021 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1022 if (code.is_null()) code = slow_stub();
1027 if (lookup->state() == LookupIterator::ACCESSOR) {
1028 Handle<Object> accessors = lookup->GetAccessors();
1029 Handle<Map> map = receiver_map();
1030 if (accessors->IsExecutableAccessorInfo()) {
1031 Handle<ExecutableAccessorInfo> info =
1032 Handle<ExecutableAccessorInfo>::cast(accessors);
1033 if ((v8::ToCData<Address>(info->getter()) != 0) &&
1034 !ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1036 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1039 } else if (accessors->IsAccessorPair()) {
1040 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1042 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1043 Handle<Object> receiver = lookup->GetReceiver();
1044 if (getter->IsJSFunction() && holder->HasFastProperties()) {
1045 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1046 if (receiver->IsJSObject() || function->IsBuiltin() ||
1047 !is_sloppy(function->shared()->language_mode())) {
1048 CallOptimization call_optimization(function);
1049 if (call_optimization.is_simple_api_call() &&
1050 !call_optimization.IsCompatibleReceiver(receiver, holder)) {
1051 TRACE_GENERIC_IC(isolate(), "LoadIC",
1052 "incompatible receiver type");
1059 if (code.is_null()) code = ComputeHandler(lookup);
1062 PatchCache(lookup->name(), code);
1063 TRACE_IC("LoadIC", lookup->name());
1067 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1068 isolate()->stub_cache()->Set(name, map, code);
1072 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1073 bool receiver_is_holder =
1074 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1075 CacheHolderFlag flag;
1076 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
1077 receiver_map(), receiver_is_holder, isolate(), &flag);
1079 Handle<Code> code = PropertyHandlerCompiler::Find(
1080 lookup->name(), stub_holder_map, kind(), flag,
1081 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1082 // Use the cached value if it exists, and if it is different from the
1083 // handler that just missed.
1084 if (!code.is_null()) {
1085 if (!maybe_handler_.is_null() &&
1086 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1089 if (maybe_handler_.is_null()) {
1090 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1091 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1092 // cache (which just missed) is different from the cached handler.
1093 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1094 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1095 Code* megamorphic_cached_code =
1096 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1097 if (megamorphic_cached_code != *code) return code;
1104 code = CompileHandler(lookup, value, flag);
1105 DCHECK(code->is_handler());
1107 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1108 // code compiled for this map, otherwise it's already cached in the global
1110 // cache. We are also guarding against installing code with flags that don't
1111 // match the desired CacheHolderFlag computed above, which would lead to
1112 // invalid lookups later.
1113 if (code->type() != Code::NORMAL &&
1114 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1115 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1122 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1123 Handle<Object> unused,
1124 CacheHolderFlag cache_holder) {
1125 Handle<Object> receiver = lookup->GetReceiver();
1126 if (receiver->IsString() &&
1127 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1128 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1129 return SimpleFieldLoad(index);
1132 if (receiver->IsStringWrapper() &&
1133 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1134 StringLengthStub string_length_stub(isolate());
1135 return string_length_stub.GetCode();
1138 // Use specialized code for getting prototype of functions.
1139 if (receiver->IsJSFunction() &&
1140 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1141 Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
1142 !Handle<JSFunction>::cast(receiver)
1144 ->has_non_instance_prototype()) {
1146 FunctionPrototypeStub function_prototype_stub(isolate());
1147 return function_prototype_stub.GetCode();
1150 Handle<Map> map = receiver_map();
1151 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1152 bool receiver_is_holder = receiver.is_identical_to(holder);
1153 switch (lookup->state()) {
1154 case LookupIterator::INTERCEPTOR: {
1155 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1156 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1157 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1158 // the original iterator will be used to fetch the value.
1159 LookupIterator it = *lookup;
1162 return compiler.CompileLoadInterceptor(&it);
1165 case LookupIterator::ACCESSOR: {
1166 // Use simple field loads for some well-known callback properties.
1167 // The method will only return true for absolute truths based on the
1170 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1172 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1173 return SimpleFieldLoad(index);
1175 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
1177 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1178 ArrayBufferViewLoadFieldStub stub(isolate(), index);
1179 return stub.GetCode();
1182 Handle<Object> accessors = lookup->GetAccessors();
1183 if (accessors->IsExecutableAccessorInfo()) {
1184 Handle<ExecutableAccessorInfo> info =
1185 Handle<ExecutableAccessorInfo>::cast(accessors);
1186 if (v8::ToCData<Address>(info->getter()) == 0) break;
1187 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1189 // This case should be already handled in LoadIC::UpdateCaches.
1193 if (!holder->HasFastProperties()) break;
1194 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1195 return compiler.CompileLoadCallback(lookup->name(), info);
1197 if (accessors->IsAccessorPair()) {
1198 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1200 if (!getter->IsJSFunction()) break;
1201 if (!holder->HasFastProperties()) break;
1202 // When debugging we need to go the slow path to flood the accessor.
1203 if (GetSharedFunctionInfo()->HasDebugInfo()) break;
1204 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1205 if (!receiver->IsJSObject() && !function->IsBuiltin() &&
1206 is_sloppy(function->shared()->language_mode())) {
1207 // Calling sloppy non-builtins with a value as the receiver
1211 CallOptimization call_optimization(function);
1212 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1213 if (call_optimization.is_simple_api_call()) {
1214 if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1215 return compiler.CompileLoadCallback(
1216 lookup->name(), call_optimization, lookup->GetAccessorIndex());
1218 // This case should be already handled in LoadIC::UpdateCaches.
1222 int expected_arguments =
1223 function->shared()->internal_formal_parameter_count();
1224 return compiler.CompileLoadViaGetter(
1225 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1230 case LookupIterator::DATA: {
1231 if (lookup->is_dictionary_holder()) {
1232 if (kind() != Code::LOAD_IC) break;
1233 if (holder->IsGlobalObject()) {
1234 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1236 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1237 Handle<Code> code = compiler.CompileLoadGlobal(
1238 cell, lookup->name(), lookup->IsConfigurable());
1239 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1240 CacheHolderFlag flag;
1241 Handle<Map> stub_holder_map =
1242 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
1243 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1246 // There is only one shared stub for loading normalized
1247 // properties. It does not traverse the prototype chain, so the
1248 // property must be found in the object for the stub to be
1250 if (!receiver_is_holder) break;
1251 return is_strong(language_mode())
1252 ? isolate()->builtins()->LoadIC_Normal_Strong()
1253 : isolate()->builtins()->LoadIC_Normal();
1256 // -------------- Fields --------------
1257 if (lookup->property_details().type() == DATA) {
1258 FieldIndex field = lookup->GetFieldIndex();
1259 if (receiver_is_holder) {
1260 return SimpleFieldLoad(field);
1262 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1263 return compiler.CompileLoadField(lookup->name(), field);
1266 // -------------- Constant properties --------------
1267 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1268 if (receiver_is_holder) {
1269 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1270 return stub.GetCode();
1272 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1273 return compiler.CompileLoadConstant(lookup->name(),
1274 lookup->GetConstantIndex());
1277 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1279 case LookupIterator::ACCESS_CHECK:
1280 case LookupIterator::JSPROXY:
1281 case LookupIterator::NOT_FOUND:
1282 case LookupIterator::TRANSITION:
1290 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1291 // This helper implements a few common fast cases for converting
1292 // non-smi keys of keyed loads/stores to a smi or a string.
1293 if (key->IsHeapNumber()) {
1294 double value = Handle<HeapNumber>::cast(key)->value();
1295 if (std::isnan(value)) {
1296 key = isolate->factory()->nan_string();
1298 int int_value = FastD2I(value);
1299 if (value == int_value && Smi::IsValid(int_value)) {
1300 key = handle(Smi::FromInt(int_value), isolate);
1303 } else if (key->IsUndefined()) {
1304 key = isolate->factory()->undefined_string();
1310 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1311 Handle<Code> null_handle;
1312 Handle<Map> receiver_map(receiver->map(), isolate());
1313 MapHandleList target_receiver_maps;
1314 TargetMaps(&target_receiver_maps);
1317 if (target_receiver_maps.length() == 0) {
1318 Handle<Code> handler =
1319 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1320 receiver_map, extra_ic_state());
1321 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1325 // The first time a receiver is seen that is a transitioned version of the
1326 // previous monomorphic receiver type, assume the new ElementsKind is the
1327 // monomorphic type. This benefits global arrays that only transition
1328 // once, and all call sites accessing them are faster if they remain
1329 // monomorphic. If this optimistic assumption is not true, the IC will
1330 // miss again and it will become polymorphic and support both the
1331 // untransitioned and transitioned maps.
1332 if (state() == MONOMORPHIC && !receiver->IsString() &&
1333 IsMoreGeneralElementsKindTransition(
1334 target_receiver_maps.at(0)->elements_kind(),
1335 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1336 Handle<Code> handler =
1337 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1338 receiver_map, extra_ic_state());
1339 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1343 DCHECK(state() != GENERIC);
1345 // Determine the list of receiver maps that this call site has seen,
1346 // adding the map that was just encountered.
1347 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1348 // If the miss wasn't due to an unseen map, a polymorphic stub
1349 // won't help, use the generic stub.
1350 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
1351 return megamorphic_stub();
1354 // If the maximum number of receiver maps has been exceeded, use the generic
1355 // version of the IC.
1356 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1357 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
1358 return megamorphic_stub();
1361 CodeHandleList handlers(target_receiver_maps.length());
1362 ElementHandlerCompiler compiler(isolate());
1363 compiler.CompileElementHandlers(&target_receiver_maps, &handlers,
1365 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
1370 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1371 Handle<Object> key) {
1372 if (MigrateDeprecated(object)) {
1373 Handle<Object> result;
1374 ASSIGN_RETURN_ON_EXCEPTION(
1376 Runtime::GetObjectProperty(isolate(), object, key, language_mode()),
1381 Handle<Object> load_handle;
1382 Handle<Code> stub = megamorphic_stub();
1384 // Check for non-string values that can be converted into an
1385 // internalized string directly or is representable as a smi.
1386 key = TryConvertKey(key, isolate());
1388 if (key->IsInternalizedString() || key->IsSymbol()) {
1389 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1390 LoadIC::Load(object, Handle<Name>::cast(key)),
1392 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1393 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1394 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1395 if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
1399 DCHECK(UseVector());
1400 if (!is_vector_set() || stub.is_null()) {
1401 Code* generic = *megamorphic_stub();
1402 if (!stub.is_null() && *stub == generic) {
1403 ConfigureVectorState(MEGAMORPHIC);
1404 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1407 TRACE_IC("LoadIC", key);
1410 if (!load_handle.is_null()) return load_handle;
1412 Handle<Object> result;
1413 ASSIGN_RETURN_ON_EXCEPTION(
1415 Runtime::GetObjectProperty(isolate(), object, key, language_mode()),
1421 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1422 JSReceiver::StoreFromKeyed store_mode) {
1423 // Disable ICs for non-JSObjects for now.
1424 Handle<Object> receiver = it->GetReceiver();
1425 if (!receiver->IsJSObject()) return false;
1426 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1428 for (; it->IsFound(); it->Next()) {
1429 switch (it->state()) {
1430 case LookupIterator::NOT_FOUND:
1431 case LookupIterator::TRANSITION:
1433 case LookupIterator::JSPROXY:
1435 case LookupIterator::INTERCEPTOR: {
1436 Handle<JSObject> holder = it->GetHolder<JSObject>();
1437 InterceptorInfo* info = holder->GetNamedInterceptor();
1438 if (it->HolderIsReceiverOrHiddenPrototype()) {
1439 if (!info->setter()->IsUndefined()) return true;
1440 } else if (!info->getter()->IsUndefined() ||
1441 !info->query()->IsUndefined()) {
1446 case LookupIterator::ACCESS_CHECK:
1447 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1449 case LookupIterator::ACCESSOR:
1450 return !it->IsReadOnly();
1451 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1453 case LookupIterator::DATA: {
1454 if (it->IsReadOnly()) return false;
1455 Handle<JSObject> holder = it->GetHolder<JSObject>();
1456 if (receiver.is_identical_to(holder)) {
1457 it->PrepareForDataProperty(value);
1458 // The previous receiver map might just have been deprecated,
1460 update_receiver_map(receiver);
1464 // Receiver != holder.
1465 PrototypeIterator iter(it->isolate(), receiver);
1466 if (receiver->IsJSGlobalProxy()) {
1467 return it->GetHolder<Object>().is_identical_to(
1468 PrototypeIterator::GetCurrent(iter));
1471 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1472 return it->IsCacheableTransition();
1477 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1478 return it->IsCacheableTransition();
1482 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1483 Handle<Object> value,
1484 JSReceiver::StoreFromKeyed store_mode) {
1485 // Check if the name is trivially convertible to an index and set the element.
1487 if (kind() == Code::KEYED_STORE_IC && name->AsArrayIndex(&index)) {
1488 // Rewrite to the generic keyed store stub.
1491 ConfigureVectorState(MEGAMORPHIC);
1492 } else if (!AddressIsDeoptimizedCode()) {
1493 set_target(*megamorphic_stub());
1495 TRACE_IC("StoreIC", name);
1496 TRACE_GENERIC_IC(isolate(), "StoreIC", "name as array index");
1498 Handle<Object> result;
1499 ASSIGN_RETURN_ON_EXCEPTION(
1501 Object::SetElement(isolate(), object, index, value, language_mode()),
1506 if (object->IsGlobalObject() && name->IsString()) {
1507 // Look up in script context table.
1508 Handle<String> str_name = Handle<String>::cast(name);
1509 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
1510 Handle<ScriptContextTable> script_contexts(
1511 global->native_context()->script_context_table());
1513 ScriptContextTable::LookupResult lookup_result;
1514 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1515 Handle<Context> script_context = ScriptContextTable::GetContext(
1516 script_contexts, lookup_result.context_index);
1517 if (lookup_result.mode == CONST) {
1518 return TypeError(MessageTemplate::kConstAssign, object, name);
1521 Handle<Object> previous_value =
1522 FixedArray::get(script_context, lookup_result.slot_index);
1524 if (*previous_value == *isolate()->factory()->the_hole_value()) {
1525 // Do not install stubs and stay pre-monomorphic for
1526 // uninitialized accesses.
1527 return ReferenceError(name);
1531 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1532 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1533 PatchCache(name, stub.GetCode());
1536 script_context->set(lookup_result.slot_index, *value);
1541 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1542 // might deprecate the current map again, if value does not fit.
1543 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1544 Handle<Object> result;
1545 ASSIGN_RETURN_ON_EXCEPTION(
1547 Object::SetProperty(object, name, value, language_mode()), Object);
1551 // If the object is undefined or null it's illegal to try to set any
1552 // properties on it; throw a TypeError in that case.
1553 if (object->IsUndefined() || object->IsNull()) {
1554 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1557 // Observed objects are always modified through the runtime.
1558 if (object->IsHeapObject() &&
1559 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1560 Handle<Object> result;
1561 ASSIGN_RETURN_ON_EXCEPTION(
1563 Object::SetProperty(object, name, value, language_mode(), store_mode),
1568 LookupIterator it(object, name);
1569 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1571 // Set the property.
1572 Handle<Object> result;
1573 ASSIGN_RETURN_ON_EXCEPTION(
1575 Object::SetProperty(&it, value, language_mode(), store_mode), Object);
1580 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
1581 CallICState::CallType call_type) {
1582 CallICTrampolineStub stub(isolate, CallICState(argc, call_type));
1583 Handle<Code> code = stub.GetCode();
1588 Handle<Code> CallIC::initialize_stub_in_optimized_code(
1589 Isolate* isolate, int argc, CallICState::CallType call_type) {
1590 CallICStub stub(isolate, CallICState(argc, call_type));
1591 Handle<Code> code = stub.GetCode();
1596 static Handle<Code> StoreICInitializeStubHelper(
1597 Isolate* isolate, ExtraICState extra_state,
1598 InlineCacheState initialization_state) {
1599 Handle<Code> ic = PropertyICCompiler::ComputeStore(
1600 isolate, initialization_state, extra_state);
1605 Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1606 LanguageMode language_mode,
1607 State initialization_state) {
1608 DCHECK(initialization_state == UNINITIALIZED ||
1609 initialization_state == PREMONOMORPHIC ||
1610 initialization_state == MEGAMORPHIC);
1611 if (FLAG_vector_stores) {
1612 VectorStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
1613 return stub.GetCode();
1616 return StoreICInitializeStubHelper(
1617 isolate, ComputeExtraICState(language_mode), initialization_state);
1621 Handle<Code> StoreIC::initialize_stub_in_optimized_code(
1622 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
1623 DCHECK(initialization_state == UNINITIALIZED ||
1624 initialization_state == PREMONOMORPHIC ||
1625 initialization_state == MEGAMORPHIC);
1626 if (FLAG_vector_stores && initialization_state != MEGAMORPHIC) {
1627 VectorStoreICStub stub(isolate, StoreICState(language_mode));
1628 return stub.GetCode();
1631 return StoreICInitializeStubHelper(
1632 isolate, ComputeExtraICState(language_mode), initialization_state);
1636 Handle<Code> StoreIC::megamorphic_stub() {
1637 if (kind() == Code::STORE_IC) {
1638 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1641 DCHECK(kind() == Code::KEYED_STORE_IC);
1642 if (is_strict(language_mode())) {
1643 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
1645 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
1651 Handle<Code> StoreIC::slow_stub() const {
1652 if (kind() == Code::STORE_IC) {
1653 return isolate()->builtins()->StoreIC_Slow();
1655 DCHECK(kind() == Code::KEYED_STORE_IC);
1656 return isolate()->builtins()->KeyedStoreIC_Slow();
1661 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1662 LanguageMode language_mode) {
1663 ExtraICState state = ComputeExtraICState(language_mode);
1664 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1668 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1669 JSReceiver::StoreFromKeyed store_mode) {
1670 if (state() == UNINITIALIZED) {
1671 // This is the first time we execute this inline cache. Set the target to
1672 // the pre monomorphic stub to delay setting the monomorphic state.
1673 if (FLAG_vector_stores) {
1674 ConfigureVectorState(PREMONOMORPHIC);
1676 set_target(*pre_monomorphic_stub());
1678 TRACE_IC("StoreIC", lookup->name());
1682 bool use_ic = LookupForWrite(lookup, value, store_mode);
1684 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1686 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1688 PatchCache(lookup->name(), code);
1689 TRACE_IC("StoreIC", lookup->name());
1693 static Handle<Code> PropertyCellStoreHandler(
1694 Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
1695 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1696 auto constant_type = Nothing<PropertyCellConstantType>();
1697 if (type == PropertyCellType::kConstantType) {
1698 constant_type = Just(cell->GetConstantType());
1700 StoreGlobalStub stub(isolate, type, constant_type,
1701 receiver->IsJSGlobalProxy());
1702 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1703 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1704 HeapObject::UpdateMapCodeCache(receiver, name, code);
1709 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1710 Handle<Object> value,
1711 CacheHolderFlag cache_holder) {
1712 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1714 // This is currently guaranteed by checks in StoreIC::Store.
1715 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1716 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1717 DCHECK(!receiver->IsAccessCheckNeeded() ||
1718 isolate()->IsInternallyUsedPropertyName(lookup->name()));
1720 switch (lookup->state()) {
1721 case LookupIterator::TRANSITION: {
1722 auto store_target = lookup->GetStoreTarget();
1723 if (store_target->IsGlobalObject()) {
1724 // TODO(dcarney): this currently just deopts. Use the transition cell.
1725 auto cell = isolate()->factory()->NewPropertyCell();
1726 cell->set_value(*value);
1727 auto code = PropertyCellStoreHandler(
1728 isolate(), store_target, Handle<GlobalObject>::cast(store_target),
1729 lookup->name(), cell, PropertyCellType::kConstant);
1730 cell->set_value(isolate()->heap()->the_hole_value());
1733 Handle<Map> transition = lookup->transition_map();
1734 // Currently not handled by CompileStoreTransition.
1735 if (!holder->HasFastProperties()) {
1736 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1740 DCHECK(lookup->IsCacheableTransition());
1741 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1742 return compiler.CompileStoreTransition(transition, lookup->name());
1745 case LookupIterator::INTERCEPTOR: {
1746 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1747 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1748 return compiler.CompileStoreInterceptor(lookup->name());
1751 case LookupIterator::ACCESSOR: {
1752 if (!holder->HasFastProperties()) {
1753 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1756 Handle<Object> accessors = lookup->GetAccessors();
1757 if (accessors->IsExecutableAccessorInfo()) {
1758 Handle<ExecutableAccessorInfo> info =
1759 Handle<ExecutableAccessorInfo>::cast(accessors);
1760 if (v8::ToCData<Address>(info->setter()) == 0) {
1761 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1764 if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1765 !lookup->HolderIsReceiverOrHiddenPrototype()) {
1766 TRACE_GENERIC_IC(isolate(), "StoreIC",
1767 "special data property in prototype chain");
1770 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1772 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1775 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1776 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1777 } else if (accessors->IsAccessorPair()) {
1778 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1780 if (!setter->IsJSFunction()) {
1781 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1784 // When debugging we need to go the slow path to flood the accessor.
1785 if (GetSharedFunctionInfo()->HasDebugInfo()) break;
1786 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1787 CallOptimization call_optimization(function);
1788 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1789 if (call_optimization.is_simple_api_call() &&
1790 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1791 return compiler.CompileStoreCallback(receiver, lookup->name(),
1793 lookup->GetAccessorIndex());
1795 int expected_arguments =
1796 function->shared()->internal_formal_parameter_count();
1797 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
1798 lookup->GetAccessorIndex(),
1799 expected_arguments);
1804 case LookupIterator::DATA: {
1805 if (lookup->is_dictionary_holder()) {
1806 if (holder->IsGlobalObject()) {
1807 DCHECK(holder.is_identical_to(receiver) ||
1808 receiver->map()->prototype() == *holder);
1809 auto cell = lookup->GetPropertyCell();
1810 auto updated_type = PropertyCell::UpdatedType(
1811 cell, value, lookup->property_details());
1812 auto code = PropertyCellStoreHandler(
1813 isolate(), receiver, Handle<GlobalObject>::cast(holder),
1814 lookup->name(), cell, updated_type);
1817 DCHECK(holder.is_identical_to(receiver));
1818 return isolate()->builtins()->StoreIC_Normal();
1821 // -------------- Fields --------------
1822 if (lookup->property_details().type() == DATA) {
1823 bool use_stub = true;
1824 if (lookup->representation().IsHeapObject()) {
1825 // Only use a generic stub if no types need to be tracked.
1826 Handle<HeapType> field_type = lookup->GetFieldType();
1827 HeapType::Iterator<Map> it = field_type->Classes();
1828 use_stub = it.Done();
1831 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1832 lookup->representation());
1833 return stub.GetCode();
1835 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1836 return compiler.CompileStoreField(lookup);
1839 // -------------- Constant properties --------------
1840 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
1841 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1845 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1846 case LookupIterator::ACCESS_CHECK:
1847 case LookupIterator::JSPROXY:
1848 case LookupIterator::NOT_FOUND:
1855 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1856 KeyedAccessStoreMode store_mode) {
1857 // Don't handle megamorphic property accesses for INTERCEPTORS or
1858 // ACCESSOR_CONSTANT
1859 // via megamorphic stubs, since they don't have a map in their relocation info
1860 // and so the stubs can't be harvested for the object needed for a map check.
1861 if (target()->type() != Code::NORMAL) {
1862 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
1863 return megamorphic_stub();
1866 Handle<Map> receiver_map(receiver->map(), isolate());
1867 MapHandleList target_receiver_maps;
1868 TargetMaps(&target_receiver_maps);
1869 if (target_receiver_maps.length() == 0) {
1870 Handle<Map> monomorphic_map =
1871 ComputeTransitionedMap(receiver_map, store_mode);
1872 store_mode = GetNonTransitioningStoreMode(store_mode);
1873 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1874 monomorphic_map, language_mode(), store_mode);
1877 // There are several special cases where an IC that is MONOMORPHIC can still
1878 // transition to a different GetNonTransitioningStoreMode IC that handles a
1879 // superset of the original IC. Handle those here if the receiver map hasn't
1880 // changed or it has transitioned to a more general kind.
1881 KeyedAccessStoreMode old_store_mode =
1882 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
1883 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1884 if (state() == MONOMORPHIC) {
1885 Handle<Map> transitioned_receiver_map = receiver_map;
1886 if (IsTransitionStoreMode(store_mode)) {
1887 transitioned_receiver_map =
1888 ComputeTransitionedMap(receiver_map, store_mode);
1890 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1891 IsTransitionStoreMode(store_mode)) ||
1892 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1893 *transitioned_receiver_map)) {
1894 // If the "old" and "new" maps are in the same elements map family, or
1895 // if they at least come from the same origin for a transitioning store,
1896 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1897 store_mode = GetNonTransitioningStoreMode(store_mode);
1898 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1899 transitioned_receiver_map, language_mode(), store_mode);
1900 } else if (*previous_receiver_map == receiver->map() &&
1901 old_store_mode == STANDARD_STORE &&
1902 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1903 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1904 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1905 // A "normal" IC that handles stores can switch to a version that can
1906 // grow at the end of the array, handle OOB accesses or copy COW arrays
1907 // and still stay MONOMORPHIC.
1908 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1909 receiver_map, language_mode(), store_mode);
1913 DCHECK(state() != GENERIC);
1916 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1918 if (IsTransitionStoreMode(store_mode)) {
1919 Handle<Map> transitioned_receiver_map =
1920 ComputeTransitionedMap(receiver_map, store_mode);
1921 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1922 transitioned_receiver_map);
1926 // If the miss wasn't due to an unseen map, a polymorphic stub
1927 // won't help, use the megamorphic stub which can handle everything.
1928 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
1929 return megamorphic_stub();
1932 // If the maximum number of receiver maps has been exceeded, use the
1933 // megamorphic version of the IC.
1934 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1935 return megamorphic_stub();
1938 // Make sure all polymorphic handlers have the same store mode, otherwise the
1939 // megamorphic stub must be used.
1940 store_mode = GetNonTransitioningStoreMode(store_mode);
1941 if (old_store_mode != STANDARD_STORE) {
1942 if (store_mode == STANDARD_STORE) {
1943 store_mode = old_store_mode;
1944 } else if (store_mode != old_store_mode) {
1945 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
1946 return megamorphic_stub();
1950 // If the store mode isn't the standard mode, make sure that all polymorphic
1951 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1952 // use the megamorphic stub.
1953 if (store_mode != STANDARD_STORE) {
1954 int external_arrays = 0;
1955 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1956 if (target_receiver_maps[i]->has_external_array_elements() ||
1957 target_receiver_maps[i]->has_fixed_typed_array_elements()) {
1961 if (external_arrays != 0 &&
1962 external_arrays != target_receiver_maps.length()) {
1963 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1964 "unsupported combination of external and normal arrays");
1965 return megamorphic_stub();
1969 return PropertyICCompiler::ComputeKeyedStorePolymorphic(
1970 &target_receiver_maps, store_mode, language_mode());
1974 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1975 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1976 switch (store_mode) {
1977 case STORE_TRANSITION_SMI_TO_OBJECT:
1978 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1979 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1980 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1981 return Map::TransitionElementsTo(map, FAST_ELEMENTS);
1982 case STORE_TRANSITION_SMI_TO_DOUBLE:
1983 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1984 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS);
1985 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1986 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1987 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1988 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1989 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS);
1990 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1991 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1992 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
1993 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1994 DCHECK(map->has_external_array_elements());
1996 case STORE_NO_TRANSITION_HANDLE_COW:
1997 case STANDARD_STORE:
1998 case STORE_AND_GROW_NO_TRANSITION:
2002 return MaybeHandle<Map>().ToHandleChecked();
2006 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
2007 uint32_t length = 0;
2008 if (receiver->IsJSArray()) {
2009 JSArray::cast(*receiver)->length()->ToArrayLength(&length);
2011 length = static_cast<uint32_t>(receiver->elements()->length());
2013 return index >= length;
2017 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2018 uint32_t index, Handle<Object> value) {
2019 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2020 // Don't consider this a growing store if the store would send the receiver to
2022 bool allow_growth = receiver->IsJSArray() && oob_access &&
2023 !receiver->WouldConvertToSlowElements(index);
2025 // Handle growing array in stub if necessary.
2026 if (receiver->HasFastSmiElements()) {
2027 if (value->IsHeapNumber()) {
2028 if (receiver->HasFastHoleyElements()) {
2029 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2031 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
2034 if (value->IsHeapObject()) {
2035 if (receiver->HasFastHoleyElements()) {
2036 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
2038 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
2041 } else if (receiver->HasFastDoubleElements()) {
2042 if (!value->IsSmi() && !value->IsHeapNumber()) {
2043 if (receiver->HasFastHoleyElements()) {
2044 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2046 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
2050 return STORE_AND_GROW_NO_TRANSITION;
2052 // Handle only in-bounds elements accesses.
2053 if (receiver->HasFastSmiElements()) {
2054 if (value->IsHeapNumber()) {
2055 if (receiver->HasFastHoleyElements()) {
2056 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2058 return STORE_TRANSITION_SMI_TO_DOUBLE;
2060 } else if (value->IsHeapObject()) {
2061 if (receiver->HasFastHoleyElements()) {
2062 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
2064 return STORE_TRANSITION_SMI_TO_OBJECT;
2067 } else if (receiver->HasFastDoubleElements()) {
2068 if (!value->IsSmi() && !value->IsHeapNumber()) {
2069 if (receiver->HasFastHoleyElements()) {
2070 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2072 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
2076 if (!FLAG_trace_external_array_abuse &&
2077 receiver->map()->has_external_array_elements() && oob_access) {
2078 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2080 Heap* heap = receiver->GetHeap();
2081 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2082 return STORE_NO_TRANSITION_HANDLE_COW;
2084 return STANDARD_STORE;
2090 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2092 Handle<Object> value) {
2093 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2094 // might deprecate the current map again, if value does not fit.
2095 if (MigrateDeprecated(object)) {
2096 Handle<Object> result;
2097 ASSIGN_RETURN_ON_EXCEPTION(
2098 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2099 value, language_mode()),
2104 // Check for non-string values that can be converted into an
2105 // internalized string directly or is representable as a smi.
2106 key = TryConvertKey(key, isolate());
2108 Handle<Object> store_handle;
2109 Handle<Code> stub = megamorphic_stub();
2112 if ((key->IsInternalizedString() &&
2113 !String::cast(*key)->AsArrayIndex(&index)) ||
2115 ASSIGN_RETURN_ON_EXCEPTION(
2116 isolate(), store_handle,
2117 StoreIC::Store(object, Handle<Name>::cast(key), value,
2118 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2120 if (FLAG_vector_stores) {
2121 if (!is_vector_set()) {
2122 ConfigureVectorState(MEGAMORPHIC);
2123 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2124 "unhandled internalized string key");
2125 TRACE_IC("StoreIC", key);
2128 if (!is_target_set()) {
2129 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2130 "unhandled internalized string key");
2131 TRACE_IC("StoreIC", key);
2135 return store_handle;
2139 FLAG_use_ic && !object->IsStringWrapper() &&
2140 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2141 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2142 if (use_ic && !object->IsSmi()) {
2143 // Don't use ICs for maps of the objects in Array's prototype chain. We
2144 // expect to be able to trap element sets to objects with those maps in
2145 // the runtime to enable optimization of element hole access.
2146 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2147 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2148 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2154 if (object->IsJSObject()) {
2155 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2156 if (receiver->elements()->map() ==
2157 isolate()->heap()->sloppy_arguments_elements_map() &&
2158 !is_sloppy(language_mode())) {
2159 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2160 } else if (key->IsSmi() && Smi::cast(*key)->value() >= 0) {
2161 uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2162 // We should go generic if receiver isn't a dictionary, but our
2163 // prototype chain does have dictionary elements. This ensures that
2164 // other non-dictionary receivers in the polymorphic case benefit
2165 // from fast path keyed stores.
2166 if (!receiver->map()->DictionaryElementsInPrototypeChainOnly()) {
2167 KeyedAccessStoreMode store_mode =
2168 GetStoreMode(receiver, index, value);
2169 stub = StoreElementStub(receiver, store_mode);
2171 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype");
2174 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2177 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2181 if (store_handle.is_null()) {
2182 ASSIGN_RETURN_ON_EXCEPTION(
2183 isolate(), store_handle,
2184 Runtime::SetObjectProperty(isolate(), object, key, value,
2189 if (FLAG_vector_stores) {
2190 if (!is_vector_set() || stub.is_null()) {
2191 Code* megamorphic = *megamorphic_stub();
2192 if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) {
2193 ConfigureVectorState(MEGAMORPHIC);
2194 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2195 *stub == megamorphic ? "set generic" : "slow stub");
2199 DCHECK(!is_target_set());
2200 Code* megamorphic = *megamorphic_stub();
2201 if (*stub == megamorphic) {
2202 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2203 } else if (*stub == *slow_stub()) {
2204 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
2207 DCHECK(!stub.is_null());
2208 if (!AddressIsDeoptimizedCode()) {
2212 TRACE_IC("StoreIC", key);
2214 return store_handle;
2218 bool CallIC::DoCustomHandler(Handle<Object> function,
2219 const CallICState& callic_state) {
2220 DCHECK(FLAG_use_ic && function->IsJSFunction());
2222 // Are we the array function?
2223 Handle<JSFunction> array_function =
2224 Handle<JSFunction>(isolate()->native_context()->array_function());
2225 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
2227 CallICNexus* nexus = casted_nexus<CallICNexus>();
2228 nexus->ConfigureMonomorphicArray();
2230 // Vector-based ICs have a different calling convention in optimized code
2231 // than full code so the correct stub has to be chosen.
2232 if (AddressIsOptimizedCode()) {
2233 CallIC_ArrayStub stub(isolate(), callic_state);
2234 set_target(*stub.GetCode());
2236 CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
2237 set_target(*stub.GetCode());
2240 Handle<String> name;
2241 if (array_function->shared()->name()->IsString()) {
2242 name = Handle<String>(String::cast(array_function->shared()->name()),
2245 TRACE_IC("CallIC", name);
2246 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2254 void CallIC::PatchMegamorphic(Handle<Object> function) {
2255 CallICState callic_state(target()->extra_ic_state());
2257 // We are going generic.
2258 CallICNexus* nexus = casted_nexus<CallICNexus>();
2259 nexus->ConfigureMegamorphic();
2261 // Vector-based ICs have a different calling convention in optimized code
2262 // than full code so the correct stub has to be chosen.
2263 if (AddressIsOptimizedCode()) {
2264 CallICStub stub(isolate(), callic_state);
2265 set_target(*stub.GetCode());
2267 CallICTrampolineStub stub(isolate(), callic_state);
2268 set_target(*stub.GetCode());
2271 Handle<Object> name = isolate()->factory()->empty_string();
2272 if (function->IsJSFunction()) {
2273 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2274 name = handle(js_function->shared()->name(), isolate());
2277 TRACE_IC("CallIC", name);
2278 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2283 void CallIC::HandleMiss(Handle<Object> function) {
2284 CallICState callic_state(target()->extra_ic_state());
2285 Handle<Object> name = isolate()->factory()->empty_string();
2286 CallICNexus* nexus = casted_nexus<CallICNexus>();
2287 Object* feedback = nexus->GetFeedback();
2289 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2290 DCHECK(!feedback->IsSmi());
2292 if (feedback->IsWeakCell() || !function->IsJSFunction()) {
2293 // We are going generic.
2294 nexus->ConfigureMegamorphic();
2296 // The feedback is either uninitialized or an allocation site.
2297 // It might be an allocation site because if we re-compile the full code
2298 // to add deoptimization support, we call with the default call-ic, and
2299 // merely need to patch the target to match the feedback.
2300 // TODO(mvstanton): the better approach is to dispense with patching
2301 // altogether, which is in progress.
2302 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) ||
2303 feedback->IsAllocationSite());
2305 // Do we want to install a custom handler?
2306 if (FLAG_use_ic && DoCustomHandler(function, callic_state)) {
2310 nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
2313 if (function->IsJSFunction()) {
2314 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2315 name = handle(js_function->shared()->name(), isolate());
2318 IC::State new_state = nexus->StateFromFeedback();
2319 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
2320 TRACE_IC("CallIC", name);
2327 // ----------------------------------------------------------------------------
2328 // Static IC stub generators.
2331 // Used from ic-<arch>.cc.
2332 RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
2333 TimerEventScope<TimerEventIcMiss> timer(isolate);
2334 HandleScope scope(isolate);
2335 DCHECK(args.length() == 3);
2336 Handle<Object> function = args.at<Object>(0);
2337 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2338 Handle<Smi> slot = args.at<Smi>(2);
2339 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2340 CallICNexus nexus(vector, vector_slot);
2341 CallIC ic(isolate, &nexus);
2342 ic.HandleMiss(function);
2347 RUNTIME_FUNCTION(Runtime_CallIC_Customization_Miss) {
2348 TimerEventScope<TimerEventIcMiss> timer(isolate);
2349 HandleScope scope(isolate);
2350 DCHECK(args.length() == 3);
2351 Handle<Object> function = args.at<Object>(0);
2352 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2353 Handle<Smi> slot = args.at<Smi>(2);
2354 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2355 CallICNexus nexus(vector, vector_slot);
2356 // A miss on a custom call ic always results in going megamorphic.
2357 CallIC ic(isolate, &nexus);
2358 ic.PatchMegamorphic(function);
2363 // Used from ic-<arch>.cc.
2364 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2365 TimerEventScope<TimerEventIcMiss> timer(isolate);
2366 HandleScope scope(isolate);
2367 Handle<Object> receiver = args.at<Object>(0);
2368 Handle<Name> key = args.at<Name>(1);
2369 Handle<Object> result;
2371 DCHECK(args.length() == 4);
2372 Handle<Smi> slot = args.at<Smi>(2);
2373 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2374 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2375 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2376 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2377 // set up outside the IC, handle that here.
2378 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2379 LoadICNexus nexus(vector, vector_slot);
2380 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2381 ic.UpdateState(receiver, key);
2382 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2384 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2385 KeyedLoadICNexus nexus(vector, vector_slot);
2386 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2387 ic.UpdateState(receiver, key);
2388 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2394 // Used from ic-<arch>.cc
2395 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2396 TimerEventScope<TimerEventIcMiss> timer(isolate);
2397 HandleScope scope(isolate);
2398 Handle<Object> receiver = args.at<Object>(0);
2399 Handle<Object> key = args.at<Object>(1);
2400 Handle<Object> result;
2402 DCHECK(args.length() == 4);
2403 Handle<Smi> slot = args.at<Smi>(2);
2404 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2405 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2406 KeyedLoadICNexus nexus(vector, vector_slot);
2407 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2408 ic.UpdateState(receiver, key);
2409 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2414 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
2415 TimerEventScope<TimerEventIcMiss> timer(isolate);
2416 HandleScope scope(isolate);
2417 Handle<Object> receiver = args.at<Object>(0);
2418 Handle<Object> key = args.at<Object>(1);
2419 Handle<Object> result;
2421 DCHECK(args.length() == 4);
2422 Handle<Smi> slot = args.at<Smi>(2);
2423 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2424 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2425 KeyedLoadICNexus nexus(vector, vector_slot);
2426 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2427 ic.UpdateState(receiver, key);
2428 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2434 // Used from ic-<arch>.cc.
2435 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2436 TimerEventScope<TimerEventIcMiss> timer(isolate);
2437 HandleScope scope(isolate);
2438 Handle<Object> receiver = args.at<Object>(0);
2439 Handle<Name> key = args.at<Name>(1);
2440 Handle<Object> value = args.at<Object>(2);
2441 Handle<Object> result;
2443 if (FLAG_vector_stores) {
2444 DCHECK(args.length() == 5);
2445 Handle<Smi> slot = args.at<Smi>(3);
2446 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2447 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2448 if (vector->GetKind(vector_slot) == Code::STORE_IC) {
2449 StoreICNexus nexus(vector, vector_slot);
2450 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2451 ic.UpdateState(receiver, key);
2452 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2453 ic.Store(receiver, key, value));
2455 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_STORE_IC);
2456 KeyedStoreICNexus nexus(vector, vector_slot);
2457 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2458 ic.UpdateState(receiver, key);
2459 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2460 ic.Store(receiver, key, value));
2463 DCHECK(args.length() == 3);
2464 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2465 ic.UpdateState(receiver, key);
2466 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2467 ic.Store(receiver, key, value));
2473 RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
2474 TimerEventScope<TimerEventIcMiss> timer(isolate);
2475 HandleScope scope(isolate);
2476 Handle<Object> receiver = args.at<Object>(0);
2477 Handle<Name> key = args.at<Name>(1);
2478 Handle<Object> value = args.at<Object>(2);
2479 Handle<Object> result;
2481 if (FLAG_vector_stores) {
2482 DCHECK(args.length() == 5 || args.length() == 6);
2483 Handle<Smi> slot = args.at<Smi>(3);
2484 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2485 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2486 if (vector->GetKind(vector_slot) == Code::STORE_IC) {
2487 StoreICNexus nexus(vector, vector_slot);
2488 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2489 ic.UpdateState(receiver, key);
2490 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2491 ic.Store(receiver, key, value));
2493 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_STORE_IC);
2494 KeyedStoreICNexus nexus(vector, vector_slot);
2495 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2496 ic.UpdateState(receiver, key);
2497 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2498 ic.Store(receiver, key, value));
2501 DCHECK(args.length() == 3 || args.length() == 4);
2502 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2503 ic.UpdateState(receiver, key);
2504 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2505 ic.Store(receiver, key, value));
2511 // Used from ic-<arch>.cc.
2512 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2513 TimerEventScope<TimerEventIcMiss> timer(isolate);
2514 HandleScope scope(isolate);
2515 Handle<Object> receiver = args.at<Object>(0);
2516 Handle<Object> key = args.at<Object>(1);
2517 Handle<Object> value = args.at<Object>(2);
2518 Handle<Object> result;
2520 if (FLAG_vector_stores) {
2521 DCHECK(args.length() == 5);
2522 Handle<Smi> slot = args.at<Smi>(3);
2523 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2524 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2525 KeyedStoreICNexus nexus(vector, vector_slot);
2526 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2527 ic.UpdateState(receiver, key);
2528 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2529 ic.Store(receiver, key, value));
2531 DCHECK(args.length() == 3);
2532 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2533 ic.UpdateState(receiver, key);
2534 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2535 ic.Store(receiver, key, value));
2541 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) {
2542 TimerEventScope<TimerEventIcMiss> timer(isolate);
2543 HandleScope scope(isolate);
2544 Handle<Object> receiver = args.at<Object>(0);
2545 Handle<Object> key = args.at<Object>(1);
2546 Handle<Object> value = args.at<Object>(2);
2547 Handle<Object> result;
2549 if (FLAG_vector_stores) {
2550 DCHECK(args.length() == 5);
2551 Handle<Smi> slot = args.at<Smi>(3);
2552 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2553 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2554 KeyedStoreICNexus nexus(vector, vector_slot);
2555 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2556 ic.UpdateState(receiver, key);
2557 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2558 ic.Store(receiver, key, value));
2560 DCHECK(args.length() == 3);
2561 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2562 ic.UpdateState(receiver, key);
2563 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2564 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2570 RUNTIME_FUNCTION(Runtime_StoreIC_Slow) {
2571 HandleScope scope(isolate);
2572 DCHECK(args.length() == 3);
2573 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2574 Handle<Object> object = args.at<Object>(0);
2575 Handle<Object> key = args.at<Object>(1);
2576 Handle<Object> value = args.at<Object>(2);
2577 LanguageMode language_mode = ic.language_mode();
2578 Handle<Object> result;
2579 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2581 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2586 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2587 HandleScope scope(isolate);
2588 DCHECK(args.length() == 3);
2589 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2590 Handle<Object> object = args.at<Object>(0);
2591 Handle<Object> key = args.at<Object>(1);
2592 Handle<Object> value = args.at<Object>(2);
2593 LanguageMode language_mode = ic.language_mode();
2594 Handle<Object> result;
2595 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2597 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2602 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2603 TimerEventScope<TimerEventIcMiss> timer(isolate);
2604 HandleScope scope(isolate);
2605 DCHECK(args.length() == 4);
2606 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2607 Handle<Object> object = args.at<Object>(0);
2608 Handle<Object> key = args.at<Object>(1);
2609 Handle<Object> value = args.at<Object>(2);
2610 Handle<Map> map = args.at<Map>(3);
2612 LanguageMode language_mode = ic.language_mode();
2613 if (object->IsJSObject()) {
2614 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2615 map->elements_kind());
2617 Handle<Object> result;
2618 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2620 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2625 MaybeHandle<Object> BinaryOpIC::Transition(
2626 Handle<AllocationSite> allocation_site, Handle<Object> left,
2627 Handle<Object> right) {
2628 BinaryOpICState state(isolate(), target()->extra_ic_state());
2630 // Compute the actual result using the builtin for the binary operation.
2631 Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
2632 TokenToJSBuiltin(state.op(), state.strength()));
2633 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
2634 Handle<Object> result;
2635 ASSIGN_RETURN_ON_EXCEPTION(
2636 isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
2639 // Do not try to update the target if the code was marked for lazy
2640 // deoptimization. (Since we do not relocate addresses in these
2641 // code objects, an attempt to access the target could fail.)
2642 if (AddressIsDeoptimizedCode()) {
2646 // Execution::Call can execute arbitrary JavaScript, hence potentially
2647 // update the state of this very IC, so we must update the stored state.
2650 // Compute the new state.
2651 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2652 state.Update(left, right, result);
2654 // Check if we have a string operation here.
2655 Handle<Code> target;
2656 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2657 // Setup the allocation site on-demand.
2658 if (allocation_site.is_null()) {
2659 allocation_site = isolate()->factory()->NewAllocationSite();
2662 // Install the stub with an allocation site.
2663 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2664 target = stub.GetCodeCopyFromTemplate(allocation_site);
2666 // Sanity check the trampoline stub.
2667 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2669 // Install the generic stub.
2670 BinaryOpICStub stub(isolate(), state);
2671 target = stub.GetCode();
2673 // Sanity check the generic stub.
2674 DCHECK_NULL(target->FindFirstAllocationSite());
2676 set_target(*target);
2678 if (FLAG_trace_ic) {
2679 OFStream os(stdout);
2680 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2681 << static_cast<void*>(*target) << " <- ";
2682 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2683 if (!allocation_site.is_null()) {
2684 os << " using allocation site " << static_cast<void*>(*allocation_site);
2686 os << "]" << std::endl;
2689 // Patch the inlined smi code as necessary.
2690 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2691 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2692 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2693 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2700 RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
2701 TimerEventScope<TimerEventIcMiss> timer(isolate);
2702 HandleScope scope(isolate);
2703 DCHECK_EQ(2, args.length());
2704 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2705 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2706 BinaryOpIC ic(isolate);
2707 Handle<Object> result;
2708 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2710 ic.Transition(Handle<AllocationSite>::null(), left, right));
2715 RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
2716 TimerEventScope<TimerEventIcMiss> timer(isolate);
2717 HandleScope scope(isolate);
2718 DCHECK_EQ(3, args.length());
2719 Handle<AllocationSite> allocation_site =
2720 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2721 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2722 Handle<Object> right =
2723 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2724 BinaryOpIC ic(isolate);
2725 Handle<Object> result;
2726 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2727 isolate, result, ic.Transition(allocation_site, left, right));
2732 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op,
2733 Strength strength) {
2734 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
2735 CompareICState::UNINITIALIZED,
2736 CompareICState::UNINITIALIZED);
2738 CHECK(stub.FindCodeInCache(&code));
2743 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op,
2744 Strength strength) {
2745 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
2746 CompareICState::UNINITIALIZED,
2747 CompareICState::UNINITIALIZED);
2748 return stub.GetCode();
2752 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2753 HandleScope scope(isolate());
2754 CompareICStub old_stub(target()->stub_key(), isolate());
2755 CompareICState::State new_left =
2756 CompareICState::NewInputState(old_stub.left(), x);
2757 CompareICState::State new_right =
2758 CompareICState::NewInputState(old_stub.right(), y);
2759 CompareICState::State state = CompareICState::TargetState(
2760 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2761 HasInlinedSmiCode(address()), x, y);
2762 CompareICStub stub(isolate(), op_, old_stub.strength(), new_left, new_right,
2764 if (state == CompareICState::KNOWN_OBJECT) {
2766 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2768 Handle<Code> new_target = stub.GetCode();
2769 set_target(*new_target);
2771 if (FLAG_trace_ic) {
2772 PrintF("[CompareIC in ");
2773 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2774 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2775 CompareICState::GetStateName(old_stub.left()),
2776 CompareICState::GetStateName(old_stub.right()),
2777 CompareICState::GetStateName(old_stub.state()),
2778 CompareICState::GetStateName(new_left),
2779 CompareICState::GetStateName(new_right),
2780 CompareICState::GetStateName(state), Token::Name(op_),
2781 static_cast<void*>(*stub.GetCode()));
2784 // Activate inlined smi code.
2785 if (old_stub.state() == CompareICState::UNINITIALIZED) {
2786 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2793 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2794 RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
2795 TimerEventScope<TimerEventIcMiss> timer(isolate);
2796 HandleScope scope(isolate);
2797 DCHECK(args.length() == 3);
2798 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2799 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2803 void CompareNilIC::Clear(Address address, Code* target, Address constant_pool) {
2804 if (IsCleared(target)) return;
2805 ExtraICState state = target->extra_ic_state();
2807 CompareNilICStub stub(target->GetIsolate(), state,
2808 HydrogenCodeStub::UNINITIALIZED);
2812 CHECK(stub.FindCodeInCache(&code));
2814 SetTargetAtAddress(address, code, constant_pool);
2818 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2819 Handle<Object> object) {
2820 if (object->IsNull() || object->IsUndefined()) {
2821 return handle(Smi::FromInt(true), isolate);
2823 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate);
2827 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2828 ExtraICState extra_ic_state = target()->extra_ic_state();
2830 CompareNilICStub stub(isolate(), extra_ic_state);
2832 // Extract the current supported types from the patched IC and calculate what
2833 // types must be supported as a result of the miss.
2834 bool already_monomorphic = stub.IsMonomorphic();
2836 stub.UpdateStatus(object);
2838 NilValue nil = stub.nil_value();
2840 // Find or create the specialized stub to support the new set of types.
2842 if (stub.IsMonomorphic()) {
2843 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2845 : HeapObject::cast(*object)->map());
2846 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2848 code = stub.GetCode();
2851 return DoCompareNilSlow(isolate(), nil, object);
2855 RUNTIME_FUNCTION(Runtime_CompareNilIC_Miss) {
2856 TimerEventScope<TimerEventIcMiss> timer(isolate);
2857 HandleScope scope(isolate);
2858 Handle<Object> object = args.at<Object>(0);
2859 CompareNilIC ic(isolate);
2860 return *ic.CompareNil(object);
2864 RUNTIME_FUNCTION(Runtime_Unreachable) {
2867 return isolate->heap()->undefined_value();
2871 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op,
2872 Strength strength) {
2873 if (is_strong(strength)) {
2875 default: UNREACHABLE();
2876 case Token::ADD: return Builtins::ADD_STRONG;
2877 case Token::SUB: return Builtins::SUB_STRONG;
2878 case Token::MUL: return Builtins::MUL_STRONG;
2879 case Token::DIV: return Builtins::DIV_STRONG;
2880 case Token::MOD: return Builtins::MOD_STRONG;
2881 case Token::BIT_OR: return Builtins::BIT_OR_STRONG;
2882 case Token::BIT_AND: return Builtins::BIT_AND_STRONG;
2883 case Token::BIT_XOR: return Builtins::BIT_XOR_STRONG;
2884 case Token::SAR: return Builtins::SAR_STRONG;
2885 case Token::SHR: return Builtins::SHR_STRONG;
2886 case Token::SHL: return Builtins::SHL_STRONG;
2890 default: UNREACHABLE();
2891 case Token::ADD: return Builtins::ADD;
2892 case Token::SUB: return Builtins::SUB;
2893 case Token::MUL: return Builtins::MUL;
2894 case Token::DIV: return Builtins::DIV;
2895 case Token::MOD: return Builtins::MOD;
2896 case Token::BIT_OR: return Builtins::BIT_OR;
2897 case Token::BIT_AND: return Builtins::BIT_AND;
2898 case Token::BIT_XOR: return Builtins::BIT_XOR;
2899 case Token::SAR: return Builtins::SAR;
2900 case Token::SHR: return Builtins::SHR;
2901 case Token::SHL: return Builtins::SHL;
2907 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2908 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2909 bool to_boolean_value = stub.UpdateStatus(object);
2910 Handle<Code> code = stub.GetCode();
2912 return handle(Smi::FromInt(to_boolean_value ? 1 : 0), isolate());
2916 RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
2917 TimerEventScope<TimerEventIcMiss> timer(isolate);
2918 DCHECK(args.length() == 1);
2919 HandleScope scope(isolate);
2920 Handle<Object> object = args.at<Object>(0);
2921 ToBooleanIC ic(isolate);
2922 return *ic.ToBoolean(object);
2926 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2927 Handle<JSObject> receiver = args.at<JSObject>(0);
2928 Handle<JSObject> holder = args.at<JSObject>(1);
2929 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
2930 Handle<Name> name = args.at<Name>(3);
2931 Handle<Object> value = args.at<Object>(4);
2932 HandleScope scope(isolate);
2934 Handle<ExecutableAccessorInfo> callback(
2935 callback_or_cell->IsWeakCell()
2936 ? ExecutableAccessorInfo::cast(
2937 WeakCell::cast(*callback_or_cell)->value())
2938 : ExecutableAccessorInfo::cast(*callback_or_cell));
2940 DCHECK(callback->IsCompatibleReceiver(*receiver));
2942 Address setter_address = v8::ToCData<Address>(callback->setter());
2943 v8::AccessorNameSetterCallback fun =
2944 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2945 DCHECK(fun != NULL);
2947 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2948 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2950 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2951 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2957 * Attempts to load a property with an interceptor (which must be present),
2958 * but doesn't search the prototype chain.
2960 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2961 * provide any value for the given name.
2963 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
2964 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2966 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2967 Handle<JSObject> receiver =
2968 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2969 Handle<JSObject> holder =
2970 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2971 HandleScope scope(isolate);
2972 LookupIterator it(receiver, name, holder, LookupIterator::OWN);
2974 Handle<Object> result;
2975 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2976 isolate, result, JSObject::GetPropertyWithInterceptor(&it, &done));
2977 if (done) return *result;
2978 return isolate->heap()->no_interceptor_result_sentinel();
2983 * Loads a property with an interceptor performing post interceptor
2984 * lookup if interceptor failed.
2986 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2987 HandleScope scope(isolate);
2988 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2990 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2991 Handle<JSObject> receiver =
2992 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2993 Handle<JSObject> holder =
2994 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2996 Handle<Object> result;
2997 LookupIterator it(receiver, name, holder);
2998 // TODO(conradw): Investigate strong mode semantics for this.
2999 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
3000 JSObject::GetProperty(&it));
3002 if (it.IsFound()) return *result;
3004 // Return the undefined result if the reference error should not be thrown.
3005 // Note that both keyed and non-keyed loads may end up here.
3006 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
3007 if (!ic.ShouldThrowReferenceError(it.GetReceiver())) {
3008 return isolate->heap()->undefined_value();
3011 // Throw a reference error.
3012 THROW_NEW_ERROR_RETURN_FAILURE(
3013 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
3017 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
3018 HandleScope scope(isolate);
3019 DCHECK(args.length() == 3);
3020 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
3021 Handle<JSObject> receiver = args.at<JSObject>(0);
3022 Handle<Name> name = args.at<Name>(1);
3023 Handle<Object> value = args.at<Object>(2);
3025 PrototypeIterator iter(isolate, receiver,
3026 PrototypeIterator::START_AT_RECEIVER);
3028 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
3029 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
3030 if (current->IsJSObject() &&
3031 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
3038 Handle<Object> result;
3039 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3041 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
3046 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
3047 // TODO(verwaest): This should probably get the holder and receiver as input.
3048 HandleScope scope(isolate);
3049 Handle<JSObject> receiver = args.at<JSObject>(0);
3050 DCHECK(args.smi_at(1) >= 0);
3051 uint32_t index = args.smi_at(1);
3052 Handle<Object> result;
3053 // TODO(conradw): Investigate strong mode semantics for this.
3054 LanguageMode language_mode = SLOPPY;
3055 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
3057 Object::GetElement(isolate, receiver, index, language_mode));
3062 RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
3063 TimerEventScope<TimerEventIcMiss> timer(isolate);
3064 HandleScope scope(isolate);
3065 Handle<Object> receiver = args.at<Object>(0);
3066 Handle<Name> key = args.at<Name>(1);
3067 Handle<Object> result;
3069 DCHECK(args.length() == 4);
3070 Handle<Smi> slot = args.at<Smi>(2);
3071 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
3072 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
3073 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
3074 // LoadIC miss handler if the handler misses. Since the vector Nexus is
3075 // set up outside the IC, handle that here.
3076 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
3077 LoadICNexus nexus(vector, vector_slot);
3078 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
3079 ic.UpdateState(receiver, key);
3080 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
3082 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
3083 KeyedLoadICNexus nexus(vector, vector_slot);
3084 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
3085 ic.UpdateState(receiver, key);
3086 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
3091 } // namespace internal