1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "accessors.h"
32 #include "arguments.h"
34 #include "execution.h"
37 #include "stub-cache.h"
43 char IC::TransitionMarkFromState(IC::State state) {
45 case UNINITIALIZED: return '0';
46 case PREMONOMORPHIC: return '.';
47 case MONOMORPHIC: return '1';
48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
49 case POLYMORPHIC: return 'P';
50 case MEGAMORPHIC: return 'N';
51 case GENERIC: return 'G';
53 // We never see the debugger states here, because the state is
54 // computed from the original code - not the patched code. Let
55 // these cases fall through to the unreachable code below.
56 case DEBUG_STUB: break;
63 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
64 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
65 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
68 if (IsGrowStoreMode(mode)) return ".GROW";
73 void IC::TraceIC(const char* type,
74 Handle<Object> name) {
76 Code* new_target = raw_target();
77 State new_state = new_target->ic_state();
78 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
79 StackFrameIterator it(isolate());
80 while (it.frame()->fp() != this->fp()) it.Advance();
81 StackFrame* raw_frame = it.frame();
82 if (raw_frame->is_internal()) {
83 Code* apply_builtin = isolate()->builtins()->builtin(
84 Builtins::kFunctionApply);
85 if (raw_frame->unchecked_code() == apply_builtin) {
86 PrintF("apply from ");
88 raw_frame = it.frame();
91 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
92 Code::ExtraICState extra_state = new_target->extra_ic_state();
93 const char* modifier =
94 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(extra_state));
96 TransitionMarkFromState(state()),
97 TransitionMarkFromState(new_state),
104 #define TRACE_GENERIC_IC(isolate, type, reason) \
106 if (FLAG_trace_ic) { \
107 PrintF("[%s patching generic stub in ", type); \
108 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
109 PrintF(" (%s)]\n", reason); \
114 #define TRACE_GENERIC_IC(isolate, type, reason)
117 #define TRACE_IC(type, name) \
118 ASSERT((TraceIC(type, name), true))
120 IC::IC(FrameDepth depth, Isolate* isolate)
123 // To improve the performance of the (much used) IC code, we unfold a few
124 // levels of the stack frame iteration code. This yields a ~35% speedup when
125 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
126 const Address entry =
127 Isolate::c_entry_fp(isolate->thread_local_top());
128 Address* pc_address =
129 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
130 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
131 // If there's another JavaScript frame on the stack or a
132 // StubFailureTrampoline, we need to look one frame further down the stack to
133 // find the frame pointer and the return address stack slot.
134 if (depth == EXTRA_CALL_FRAME) {
135 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
136 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
137 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
140 StackFrameIterator it(isolate);
141 for (int i = 0; i < depth + 1; i++) it.Advance();
142 StackFrame* frame = it.frame();
143 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
146 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
147 target_ = handle(raw_target(), isolate);
148 state_ = target_->ic_state();
152 #ifdef ENABLE_DEBUGGER_SUPPORT
153 Address IC::OriginalCodeAddress() const {
154 HandleScope scope(isolate());
155 // Compute the JavaScript frame for the frame pointer of this IC
156 // structure. We need this to be able to find the function
157 // corresponding to the frame.
158 StackFrameIterator it(isolate());
159 while (it.frame()->fp() != this->fp()) it.Advance();
160 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
161 // Find the function on the stack and both the active code for the
162 // function and the original code.
163 JSFunction* function = frame->function();
164 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
165 Code* code = shared->code();
166 ASSERT(Debug::HasDebugInfo(shared));
167 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
168 ASSERT(original_code->IsCode());
169 // Get the address of the call site in the active code. This is the
170 // place where the call to DebugBreakXXX is and where the IC
171 // normally would be.
172 Address addr = Assembler::target_address_from_return_address(pc());
173 // Return the address in the original code. This is the place where
174 // the call which has been overwritten by the DebugBreakXXX resides
175 // and the place where the inline cache system should look.
177 original_code->instruction_start() - code->instruction_start();
183 static bool HasInterceptorGetter(JSObject* object) {
184 return !object->GetNamedInterceptor()->getter()->IsUndefined();
188 static bool HasInterceptorSetter(JSObject* object) {
189 return !object->GetNamedInterceptor()->setter()->IsUndefined();
193 static void LookupForRead(Handle<Object> object,
195 LookupResult* lookup) {
196 // Skip all the objects with named interceptors, but
197 // without actual getter.
199 object->Lookup(*name, lookup);
200 // Besides normal conditions (property not found or it's not
201 // an interceptor), bail out if lookup is not cacheable: we won't
202 // be able to IC it anyway and regular lookup should work fine.
203 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
207 Handle<JSObject> holder(lookup->holder(), lookup->isolate());
208 if (HasInterceptorGetter(*holder)) {
212 holder->LocalLookupRealNamedProperty(*name, lookup);
213 if (lookup->IsFound()) {
214 ASSERT(!lookup->IsInterceptor());
218 Handle<Object> proto(holder->GetPrototype(), lookup->isolate());
219 if (proto->IsNull()) {
220 ASSERT(!lookup->IsFound());
229 bool CallIC::TryUpdateExtraICState(LookupResult* lookup,
230 Handle<Object> object) {
231 if (!lookup->IsConstantFunction()) return false;
232 JSFunction* function = lookup->GetConstantFunction();
233 if (!function->shared()->HasBuiltinFunctionId()) return false;
235 // Fetch the arguments passed to the called function.
236 const int argc = target()->arguments_count();
237 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
238 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
239 Arguments args(argc + 1,
240 &Memory::Object_at(fp +
241 StandardFrameConstants::kCallerSPOffset +
242 argc * kPointerSize));
243 switch (function->shared()->builtin_function_id()) {
244 case kStringCharCodeAt:
246 if (object->IsString()) {
247 String* string = String::cast(*object);
248 // Check there's the right string value or wrapper in the receiver slot.
249 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
250 // If we're in the default (fastest) state and the index is
251 // out of bounds, update the state to record this fact.
252 if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB &&
253 argc >= 1 && args[1]->IsNumber()) {
254 double index = DoubleToInteger(args.number_at(1));
255 if (index < 0 || index >= string->length()) {
257 StringStubState::update(extra_ic_state(),
258 STRING_INDEX_OUT_OF_BOUNDS);
271 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
272 Handle<String> name) {
273 DisallowHeapAllocation no_gc;
275 if (target()->is_call_stub()) {
276 LookupResult lookup(isolate());
277 LookupForRead(receiver, name, &lookup);
278 if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) {
283 if (target()->is_keyed_stub()) {
284 // Determine whether the failure is due to a name failure.
285 if (!name->IsName()) return false;
286 Name* stub_name = target()->FindFirstName();
287 if (*name != stub_name) return false;
290 InlineCacheHolderFlag cache_holder =
291 Code::ExtractCacheHolderFromFlags(target()->flags());
293 switch (cache_holder) {
295 // The stub was generated for JSObject but called for non-JSObject.
296 // IC::GetCodeCacheHolder is not applicable.
297 if (!receiver->IsJSObject()) return false;
300 // IC::GetCodeCacheHolder is not applicable.
301 if (receiver->GetPrototype(isolate())->IsNull()) return false;
306 IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
308 // Decide whether the inline cache failed because of changes to the
309 // receiver itself or changes to one of its prototypes.
311 // If there are changes to the receiver itself, the map of the
312 // receiver will have changed and the current target will not be in
313 // the receiver map's code cache. Therefore, if the current target
314 // is in the receiver map's code cache, the inline cache failed due
315 // to prototype check failure.
316 int index = map->IndexInCodeCache(*name, *target());
318 map->RemoveFromCodeCache(*name, *target(), index);
319 // Handlers are stored in addition to the ICs on the map. Remove those, too.
320 TryRemoveInvalidHandlers(map, name);
324 // The stub is not in the cache. We've ruled out all other kinds of failure
325 // except for proptotype chain changes, a deprecated map, a map that's
326 // different from the one that the stub expects, elements kind changes, or a
327 // constant global property that will become mutable. Threat all those
328 // situations as prototype failures (stay monomorphic if possible).
330 // If the IC is shared between multiple receivers (slow dictionary mode), then
331 // the map cannot be deprecated and the stub invalidated.
332 if (cache_holder == OWN_MAP) {
333 Map* old_map = target()->FindFirstMap();
334 if (old_map == *map) return true;
335 if (old_map != NULL) {
336 if (old_map->is_deprecated()) return true;
337 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
338 map->elements_kind())) {
344 if (receiver->IsGlobalObject()) {
345 LookupResult lookup(isolate());
346 GlobalObject* global = GlobalObject::cast(*receiver);
347 global->LocalLookupRealNamedProperty(*name, &lookup);
348 if (!lookup.IsFound()) return false;
349 PropertyCell* cell = global->GetPropertyCell(&lookup);
350 return cell->type()->IsConstant();
357 void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
358 CodeHandleList handlers;
359 target()->FindHandlers(&handlers);
360 for (int i = 0; i < handlers.length(); i++) {
361 Handle<Code> handler = handlers.at(i);
362 int index = map->IndexInCodeCache(*name, *handler);
364 map->RemoveFromCodeCache(*name, *handler, index);
371 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
372 if (!name->IsString()) return;
373 if (state() != MONOMORPHIC) {
374 if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
375 TryRemoveInvalidHandlers(
376 handle(Handle<HeapObject>::cast(receiver)->map()),
377 Handle<String>::cast(name));
381 if (receiver->IsUndefined() || receiver->IsNull()) return;
383 // Remove the target from the code cache if it became invalid
384 // because of changes in the prototype chain to avoid hitting it
386 if (TryRemoveInvalidPrototypeDependentStub(
387 receiver, Handle<String>::cast(name))) {
388 return MarkMonomorphicPrototypeFailure();
391 // The builtins object is special. It only changes when JavaScript
392 // builtins are loaded lazily. It is important to keep inline
393 // caches for the builtins object monomorphic. Therefore, if we get
394 // an inline cache miss for the builtins object after lazily loading
395 // JavaScript builtins, we return uninitialized as the state to
396 // force the inline cache back to monomorphic state.
397 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED;
401 RelocInfo::Mode IC::ComputeMode() {
402 Address addr = address();
403 Code* code = Code::cast(isolate()->FindCodeObject(addr));
404 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
405 !it.done(); it.next()) {
406 RelocInfo* info = it.rinfo();
407 if (info->pc() == addr) return info->rmode();
410 return RelocInfo::NONE32;
414 Failure* IC::TypeError(const char* type,
415 Handle<Object> object,
416 Handle<Object> key) {
417 HandleScope scope(isolate());
418 Handle<Object> args[2] = { key, object };
419 Handle<Object> error = isolate()->factory()->NewTypeError(
420 type, HandleVector(args, 2));
421 return isolate()->Throw(*error);
425 Failure* IC::ReferenceError(const char* type, Handle<String> name) {
426 HandleScope scope(isolate());
427 Handle<Object> error = isolate()->factory()->NewReferenceError(
428 type, HandleVector(&name, 1));
429 return isolate()->Throw(*error);
433 static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
434 bool was_uninitialized =
435 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC;
436 bool is_uninitialized =
437 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC;
438 return (was_uninitialized && !is_uninitialized) ? 1 :
439 (!was_uninitialized && is_uninitialized) ? -1 : 0;
443 void IC::PostPatching(Address address, Code* target, Code* old_target) {
444 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) {
447 Isolate* isolate = target->GetHeap()->isolate();
448 Code* host = isolate->
449 inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
450 if (host->kind() != Code::FUNCTION) return;
452 if (FLAG_type_info_threshold > 0 &&
453 old_target->is_inline_cache_stub() &&
454 target->is_inline_cache_stub()) {
455 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(),
457 // Not all Code objects have TypeFeedbackInfo.
458 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) {
459 TypeFeedbackInfo* info =
460 TypeFeedbackInfo::cast(host->type_feedback_info());
461 info->change_ic_with_type_info_count(delta);
464 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
465 TypeFeedbackInfo* info =
466 TypeFeedbackInfo::cast(host->type_feedback_info());
467 info->change_own_type_change_checksum();
469 if (FLAG_watch_ic_patching) {
470 host->set_profiler_ticks(0);
471 isolate->runtime_profiler()->NotifyICChanged();
473 // TODO(2029): When an optimized function is patched, it would
474 // be nice to propagate the corresponding type information to its
475 // unoptimized version for the benefit of later inlining.
479 void IC::Clear(Isolate* isolate, Address address) {
480 Code* target = GetTargetAtAddress(address);
482 // Don't clear debug break inline cache as it will remove the break point.
483 if (target->is_debug_stub()) return;
485 switch (target->kind()) {
486 case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target);
487 case Code::KEYED_LOAD_IC:
488 return KeyedLoadIC::Clear(isolate, address, target);
489 case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
490 case Code::KEYED_STORE_IC:
491 return KeyedStoreIC::Clear(isolate, address, target);
492 case Code::CALL_IC: return CallIC::Clear(address, target);
493 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
494 case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
495 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
496 case Code::BINARY_OP_IC:
497 case Code::TO_BOOLEAN_IC:
498 // Clearing these is tricky and does not
499 // make any performance difference.
501 default: UNREACHABLE();
506 void CallICBase::Clear(Address address, Code* target) {
507 if (IsCleared(target)) return;
508 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
510 target->GetIsolate()->stub_cache()->FindCallInitialize(
511 target->arguments_count(),
512 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
514 SetTargetAtAddress(address, code);
518 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
519 if (IsCleared(target)) return;
520 // Make sure to also clear the map used in inline fast cases. If we
521 // do not clear these maps, cached code can keep objects alive
522 // through the embedded maps.
523 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
527 void LoadIC::Clear(Isolate* isolate, Address address, Code* target) {
528 if (IsCleared(target)) return;
529 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
533 void StoreIC::Clear(Isolate* isolate, Address address, Code* target) {
534 if (IsCleared(target)) return;
535 SetTargetAtAddress(address,
536 *pre_monomorphic_stub(
537 isolate, Code::GetStrictMode(target->extra_ic_state())));
541 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) {
542 if (IsCleared(target)) return;
543 SetTargetAtAddress(address,
544 *pre_monomorphic_stub(
545 isolate, Code::GetStrictMode(target->extra_ic_state())));
549 void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
550 ASSERT(target->major_key() == CodeStub::CompareIC);
551 CompareIC::State handler_state;
553 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
554 &handler_state, &op);
555 // Only clear CompareICs that can retain objects.
556 if (handler_state != KNOWN_OBJECT) return;
557 SetTargetAtAddress(address, GetRawUninitialized(isolate, op));
558 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
562 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
563 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object);
565 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
566 // Patch the receiver and use the delegate as the function to
567 // invoke. This is used for invoking objects as if they were functions.
568 const int argc = target()->arguments_count();
569 StackFrameLocator locator(isolate());
570 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
571 int index = frame->ComputeExpressionsCount() - (argc + 1);
572 frame->SetExpression(index, *object);
579 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
580 Handle<Object> object) {
581 while (callee->IsJSFunctionProxy()) {
582 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(),
586 if (callee->IsJSFunction()) {
587 Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
588 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) {
589 // Do not wrap receiver for strict mode functions or for builtins.
594 // And only wrap string, number or boolean.
595 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
596 // Change the receiver to the result of calling ToObject on it.
597 const int argc = this->target()->arguments_count();
598 StackFrameLocator locator(isolate());
599 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
600 int index = frame->ComputeExpressionsCount() - (argc + 1);
601 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
606 static bool MigrateDeprecated(Handle<Object> object) {
607 if (!object->IsJSObject()) return false;
608 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
609 if (!receiver->map()->is_deprecated()) return false;
610 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
615 MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
616 Handle<String> name) {
617 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
619 // If the object is undefined or null it's illegal to try to get any
620 // of its properties; throw a TypeError in that case.
621 if (object->IsUndefined() || object->IsNull()) {
622 return TypeError("non_object_property_call", object, name);
625 // Check if the name is trivially convertible to an index and get
626 // the element if so.
628 if (name->AsArrayIndex(&index)) {
629 Handle<Object> result = Object::GetElement(isolate(), object, index);
630 RETURN_IF_EMPTY_HANDLE(isolate(), result);
631 if (result->IsJSFunction()) return *result;
633 // Try to find a suitable function delegate for the object at hand.
634 result = TryCallAsFunction(result);
635 if (result->IsJSFunction()) return *result;
637 // Otherwise, it will fail in the lookup step.
640 // Lookup the property in the object.
641 LookupResult lookup(isolate());
642 LookupForRead(object, name, &lookup);
644 if (!lookup.IsFound()) {
645 // If the object does not have the requested property, check which
646 // exception we need to throw.
647 return IsUndeclaredGlobal(object)
648 ? ReferenceError("not_defined", name)
649 : TypeError("undefined_method", object, name);
652 // Lookup is valid: Update inline cache and stub cache.
653 if (use_ic) UpdateCaches(&lookup, object, name);
656 PropertyAttributes attr;
657 Handle<Object> result =
658 Object::GetProperty(object, object, &lookup, name, &attr);
659 RETURN_IF_EMPTY_HANDLE(isolate(), result);
661 if (lookup.IsInterceptor() && attr == ABSENT) {
662 // If the object does not have the requested property, check which
663 // exception we need to throw.
664 return IsUndeclaredGlobal(object)
665 ? ReferenceError("not_defined", name)
666 : TypeError("undefined_method", object, name);
669 ASSERT(!result->IsTheHole());
671 // Make receiver an object if the callee requires it. Strict mode or builtin
672 // functions do not wrap the receiver, non-strict functions and objects
673 // called as functions do.
674 ReceiverToObjectIfRequired(result, object);
676 if (result->IsJSFunction()) {
677 Handle<JSFunction> function = Handle<JSFunction>::cast(result);
678 #ifdef ENABLE_DEBUGGER_SUPPORT
679 // Handle stepping into a function if step into is active.
680 Debug* debug = isolate()->debug();
681 if (debug->StepInActive()) {
682 // Protect the result in a handle as the debugger can allocate and might
684 debug->HandleStepIn(function, object, fp(), false);
690 // Try to find a suitable function delegate for the object at hand.
691 result = TryCallAsFunction(result);
692 if (result->IsJSFunction()) return *result;
694 return TypeError("property_not_function", object, name);
698 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
699 Handle<Object> object,
700 Handle<String> name) {
701 int argc = target()->arguments_count();
702 Handle<JSObject> holder(lookup->holder(), isolate());
703 switch (lookup->type()) {
705 PropertyIndex index = lookup->GetFieldIndex();
706 return isolate()->stub_cache()->ComputeCallField(
707 argc, kind_, extra_ic_state(), name, object, holder, index);
710 if (!lookup->IsConstantFunction()) return Handle<Code>::null();
711 // Get the constant function and compute the code stub for this
712 // call; used for rewriting to monomorphic state and making sure
713 // that the code stub is in the stub cache.
714 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate());
715 return isolate()->stub_cache()->ComputeCallConstant(
716 argc, kind_, extra_ic_state(), name, object, holder, function);
719 // If we return a null handle, the IC will not be patched.
720 if (!object->IsJSObject()) return Handle<Code>::null();
721 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
723 if (holder->IsGlobalObject()) {
724 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
725 Handle<PropertyCell> cell(
726 global->GetPropertyCell(lookup), isolate());
727 if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
728 Handle<JSFunction> function(JSFunction::cast(cell->value()));
729 return isolate()->stub_cache()->ComputeCallGlobal(
730 argc, kind_, extra_ic_state(), name,
731 receiver, global, cell, function);
733 // There is only one shared stub for calling normalized
734 // properties. It does not traverse the prototype chain, so the
735 // property must be found in the receiver for the stub to be
737 if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
738 return isolate()->stub_cache()->ComputeCallNormal(
739 argc, kind_, extra_ic_state());
744 ASSERT(HasInterceptorGetter(*holder));
745 return isolate()->stub_cache()->ComputeCallInterceptor(
746 argc, kind_, extra_ic_state(), name, object, holder);
748 return Handle<Code>::null();
753 Handle<Code> CallICBase::megamorphic_stub() {
754 return isolate()->stub_cache()->ComputeCallMegamorphic(
755 target()->arguments_count(), kind_, extra_ic_state());
759 Handle<Code> CallICBase::pre_monomorphic_stub() {
760 return isolate()->stub_cache()->ComputeCallPreMonomorphic(
761 target()->arguments_count(), kind_, extra_ic_state());
765 void CallICBase::UpdateCaches(LookupResult* lookup,
766 Handle<Object> object,
767 Handle<String> name) {
768 // Bail out if we didn't find a result.
769 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
771 // Compute the number of arguments.
773 code = state() == UNINITIALIZED
774 ? pre_monomorphic_stub()
775 : ComputeMonomorphicStub(lookup, object, name);
777 // If there's no appropriate stub we simply avoid updating the caches.
778 // TODO(verwaest): Install a slow fallback in this case to avoid not learning,
779 // and deopting Crankshaft code.
780 if (code.is_null()) return;
782 Handle<JSObject> cache_object = object->IsJSObject()
783 ? Handle<JSObject>::cast(object)
784 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
787 PatchCache(cache_object, name, code);
788 TRACE_IC("CallIC", name);
792 MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object,
793 Handle<Object> key) {
794 if (key->IsInternalizedString()) {
795 return CallICBase::LoadFunction(object, Handle<String>::cast(key));
798 if (object->IsUndefined() || object->IsNull()) {
799 return TypeError("non_object_property_call", object, key);
802 bool use_ic = MigrateDeprecated(object)
803 ? false : FLAG_use_ic && !object->IsAccessCheckNeeded();
805 if (use_ic && state() != MEGAMORPHIC) {
806 ASSERT(!object->IsJSGlobalProxy());
807 int argc = target()->arguments_count();
808 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic(
809 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
810 if (object->IsJSObject()) {
811 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
812 if (receiver->elements()->map() ==
813 isolate()->heap()->non_strict_arguments_elements_map()) {
814 stub = isolate()->stub_cache()->ComputeCallArguments(argc);
817 ASSERT(!stub.is_null());
819 TRACE_IC("CallIC", key);
822 Handle<Object> result = GetProperty(isolate(), object, key);
823 RETURN_IF_EMPTY_HANDLE(isolate(), result);
825 // Make receiver an object if the callee requires it. Strict mode or builtin
826 // functions do not wrap the receiver, non-strict functions and objects
827 // called as functions do.
828 ReceiverToObjectIfRequired(result, object);
829 if (result->IsJSFunction()) return *result;
831 result = TryCallAsFunction(result);
832 if (result->IsJSFunction()) return *result;
834 return TypeError("property_not_function", object, key);
838 MaybeObject* LoadIC::Load(Handle<Object> object,
839 Handle<String> name) {
840 // If the object is undefined or null it's illegal to try to get any
841 // of its properties; throw a TypeError in that case.
842 if (object->IsUndefined() || object->IsNull()) {
843 return TypeError("non_object_property_load", object, name);
847 // Use specialized code for getting the length of strings and
848 // string wrapper objects. The length property of string wrapper
849 // objects is read-only and therefore always returns the length of
850 // the underlying string value. See ECMA-262 15.5.5.1.
851 if (object->IsStringWrapper() &&
852 name->Equals(isolate()->heap()->length_string())) {
854 if (state() == UNINITIALIZED) {
855 stub = pre_monomorphic_stub();
856 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
857 StringLengthStub string_length_stub(kind());
858 stub = string_length_stub.GetCode(isolate());
859 } else if (state() != MEGAMORPHIC) {
860 ASSERT(state() != GENERIC);
861 stub = megamorphic_stub();
863 if (!stub.is_null()) {
866 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
869 // Get the string if we have a string wrapper object.
870 String* string = String::cast(JSValue::cast(*object)->value());
871 return Smi::FromInt(string->length());
874 // Use specialized code for getting prototype of functions.
875 if (object->IsJSFunction() &&
876 name->Equals(isolate()->heap()->prototype_string()) &&
877 Handle<JSFunction>::cast(object)->should_have_prototype()) {
879 if (state() == UNINITIALIZED) {
880 stub = pre_monomorphic_stub();
881 } else if (state() == PREMONOMORPHIC) {
882 FunctionPrototypeStub function_prototype_stub(kind());
883 stub = function_prototype_stub.GetCode(isolate());
884 } else if (state() != MEGAMORPHIC) {
885 ASSERT(state() != GENERIC);
886 stub = megamorphic_stub();
888 if (!stub.is_null()) {
891 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
894 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
898 // Check if the name is trivially convertible to an index and get
899 // the element or char if so.
901 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
902 // Rewrite to the generic keyed load stub.
903 if (FLAG_use_ic) set_target(*generic_stub());
904 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index);
907 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
909 // Named lookup in the object.
910 LookupResult lookup(isolate());
911 LookupForRead(object, name, &lookup);
913 // If we did not find a property, check if we need to throw an exception.
914 if (!lookup.IsFound()) {
915 if (IsUndeclaredGlobal(object)) {
916 return ReferenceError("not_defined", name);
918 LOG(isolate(), SuspectReadEvent(*name, *object));
921 // Update inline cache and stub cache.
922 if (use_ic) UpdateCaches(&lookup, object, name);
924 PropertyAttributes attr;
926 Handle<Object> result =
927 Object::GetProperty(object, object, &lookup, name, &attr);
928 RETURN_IF_EMPTY_HANDLE(isolate(), result);
929 // If the property is not present, check if we need to throw an
931 if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
932 attr == ABSENT && IsUndeclaredGlobal(object)) {
933 return ReferenceError("not_defined", name);
939 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
940 Handle<Map> new_receiver_map) {
941 ASSERT(!new_receiver_map.is_null());
942 for (int current = 0; current < receiver_maps->length(); ++current) {
943 if (!receiver_maps->at(current).is_null() &&
944 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
948 receiver_maps->Add(new_receiver_map);
953 bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver,
956 if (!code->is_handler()) return false;
958 MapHandleList receiver_maps;
959 CodeHandleList handlers;
961 int number_of_valid_maps;
962 int handler_to_overwrite = -1;
963 Handle<Map> new_receiver_map(receiver->map());
965 DisallowHeapAllocation no_gc;
966 target()->FindAllMaps(&receiver_maps);
967 int number_of_maps = receiver_maps.length();
968 number_of_valid_maps = number_of_maps;
970 for (int i = 0; i < number_of_maps; i++) {
971 Handle<Map> map = receiver_maps.at(i);
972 // Filter out deprecated maps to ensure its instances get migrated.
973 if (map->is_deprecated()) {
974 number_of_valid_maps--;
975 // If the receiver map is already in the polymorphic IC, this indicates
976 // there was a prototoype chain failure. In that case, just overwrite the
978 } else if (map.is_identical_to(new_receiver_map)) {
979 number_of_valid_maps--;
980 handler_to_overwrite = i;
984 if (number_of_valid_maps >= 4) return false;
985 if (number_of_maps == 0) return false;
987 if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
992 number_of_valid_maps++;
993 if (handler_to_overwrite >= 0) {
994 handlers.Set(handler_to_overwrite, code);
996 receiver_maps.Add(new_receiver_map);
1000 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
1001 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode());
1007 void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
1008 Handle<Code> handler,
1009 Handle<String> name) {
1010 if (!handler->is_handler()) return set_target(*handler);
1011 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
1012 receiver, handler, name, strict_mode());
1017 void IC::CopyICToMegamorphicCache(Handle<String> name) {
1018 MapHandleList receiver_maps;
1019 CodeHandleList handlers;
1021 DisallowHeapAllocation no_gc;
1022 target()->FindAllMaps(&receiver_maps);
1023 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
1025 for (int i = 0; i < receiver_maps.length(); i++) {
1026 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1031 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
1032 DisallowHeapAllocation no_allocation;
1034 Map* current_map = target()->FindFirstMap();
1035 ElementsKind receiver_elements_kind = receiver_map->elements_kind();
1036 bool more_general_transition =
1037 IsMoreGeneralElementsKindTransition(
1038 current_map->elements_kind(), receiver_elements_kind);
1039 Map* transitioned_map = more_general_transition
1040 ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
1043 return transitioned_map == receiver_map;
1047 void IC::PatchCache(Handle<HeapObject> receiver,
1048 Handle<String> name,
1049 Handle<Code> code) {
1052 case PREMONOMORPHIC:
1053 case MONOMORPHIC_PROTOTYPE_FAILURE:
1054 UpdateMonomorphicIC(receiver, code, name);
1057 // For now, call stubs are allowed to rewrite to the same stub. This
1058 // happens e.g., when the field does not contain a function.
1059 ASSERT(target()->is_call_stub() ||
1060 target()->is_keyed_call_stub() ||
1061 !target().is_identical_to(code));
1062 if (!target()->is_keyed_stub()) {
1063 bool is_same_handler = false;
1065 DisallowHeapAllocation no_allocation;
1066 Code* old_handler = target()->FindFirstHandler();
1067 is_same_handler = old_handler == *code;
1070 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
1071 UpdateMonomorphicIC(receiver, code, name);
1074 if (UpdatePolymorphicIC(receiver, name, code)) {
1078 CopyICToMegamorphicCache(name);
1081 UpdateMegamorphicCache(receiver->map(), *name, *code);
1082 set_target(*megamorphic_stub());
1085 UpdateMegamorphicCache(receiver->map(), *name, *code);
1088 if (target()->is_keyed_stub()) {
1089 // When trying to patch a polymorphic keyed stub with anything other
1090 // than another polymorphic stub, go generic.
1091 set_target(*generic_stub());
1093 if (UpdatePolymorphicIC(receiver, name, code)) {
1096 CopyICToMegamorphicCache(name);
1097 UpdateMegamorphicCache(receiver->map(), *name, *code);
1098 set_target(*megamorphic_stub());
1110 Handle<Code> LoadIC::SimpleFieldLoad(int offset,
1112 Representation representation) {
1113 if (kind() == Code::LOAD_IC) {
1114 LoadFieldStub stub(inobject, offset, representation);
1115 return stub.GetCode(isolate());
1117 KeyedLoadFieldStub stub(inobject, offset, representation);
1118 return stub.GetCode(isolate());
1122 void LoadIC::UpdateCaches(LookupResult* lookup,
1123 Handle<Object> object,
1124 Handle<String> name) {
1125 // TODO(verwaest): It would be nice to support loading fields from smis as
1126 // well. For now just fail to update the cache.
1127 if (!object->IsHeapObject()) return;
1129 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1132 if (state() == UNINITIALIZED) {
1133 // This is the first time we execute this inline cache.
1134 // Set the target to the pre monomorphic stub to delay
1135 // setting the monomorphic state.
1136 code = pre_monomorphic_stub();
1137 } else if (!lookup->IsCacheable()) {
1138 // Bail out if the result is not cacheable.
1140 } else if (object->IsString() &&
1141 name->Equals(isolate()->heap()->length_string())) {
1142 int length_index = String::kLengthOffset / kPointerSize;
1143 code = SimpleFieldLoad(length_index);
1144 } else if (!object->IsJSObject()) {
1145 // TODO(jkummerow): It would be nice to support non-JSObjects in
1146 // ComputeLoadHandler, then we wouldn't need to go generic here.
1148 } else if (!lookup->IsProperty()) {
1149 code = kind() == Code::LOAD_IC
1150 ? isolate()->stub_cache()->ComputeLoadNonexistent(
1151 name, Handle<JSObject>::cast(receiver))
1154 code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
1157 PatchCache(receiver, name, code);
1158 TRACE_IC("LoadIC", name);
1162 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
1163 // Cache code holding map should be consistent with
1164 // GenerateMonomorphicCacheProbe.
1165 isolate()->stub_cache()->Set(name, map, code);
1169 Handle<Code> IC::ComputeHandler(LookupResult* lookup,
1170 Handle<JSObject> receiver,
1171 Handle<String> name,
1172 Handle<Object> value) {
1173 Handle<Code> code = isolate()->stub_cache()->FindHandler(
1174 name, receiver, kind());
1175 if (!code.is_null()) return code;
1177 code = CompileHandler(lookup, receiver, name, value);
1179 if (code->is_handler() && code->type() != Code::NORMAL) {
1180 HeapObject::UpdateMapCodeCache(receiver, name, code);
1187 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
1188 Handle<JSObject> receiver,
1189 Handle<String> name,
1190 Handle<Object> unused) {
1191 Handle<JSObject> holder(lookup->holder());
1192 LoadStubCompiler compiler(isolate(), kind());
1194 switch (lookup->type()) {
1196 PropertyIndex field = lookup->GetFieldIndex();
1197 if (receiver.is_identical_to(holder)) {
1198 return SimpleFieldLoad(field.translate(holder),
1199 field.is_inobject(holder),
1200 lookup->representation());
1202 return compiler.CompileLoadField(
1203 receiver, holder, name, field, lookup->representation());
1206 Handle<Object> constant(lookup->GetConstant(), isolate());
1207 // TODO(2803): Don't compute a stub for cons strings because they cannot
1208 // be embedded into code.
1209 if (constant->IsConsString()) break;
1210 return compiler.CompileLoadConstant(receiver, holder, name, constant);
1213 if (kind() != Code::LOAD_IC) break;
1214 if (holder->IsGlobalObject()) {
1215 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
1216 Handle<PropertyCell> cell(
1217 global->GetPropertyCell(lookup), isolate());
1218 // TODO(verwaest): Turn into a handler.
1219 return isolate()->stub_cache()->ComputeLoadGlobal(
1220 name, receiver, global, cell, lookup->IsDontDelete());
1222 // There is only one shared stub for loading normalized
1223 // properties. It does not traverse the prototype chain, so the
1224 // property must be found in the receiver for the stub to be
1226 if (!holder.is_identical_to(receiver)) break;
1227 return isolate()->builtins()->LoadIC_Normal();
1229 // Use simple field loads for some well-known callback properties.
1231 Handle<Map> map(receiver->map());
1232 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
1233 PropertyIndex index =
1234 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
1235 return compiler.CompileLoadField(
1236 receiver, receiver, name, index, Representation::Tagged());
1239 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1240 if (callback->IsExecutableAccessorInfo()) {
1241 Handle<ExecutableAccessorInfo> info =
1242 Handle<ExecutableAccessorInfo>::cast(callback);
1243 if (v8::ToCData<Address>(info->getter()) == 0) break;
1244 if (!info->IsCompatibleReceiver(*receiver)) break;
1245 return compiler.CompileLoadCallback(receiver, holder, name, info);
1246 } else if (callback->IsAccessorPair()) {
1247 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
1249 if (!getter->IsJSFunction()) break;
1250 if (holder->IsGlobalObject()) break;
1251 if (!holder->HasFastProperties()) break;
1252 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1253 CallOptimization call_optimization(function);
1254 if (call_optimization.is_simple_api_call() &&
1255 call_optimization.IsCompatibleReceiver(*receiver)) {
1256 return compiler.CompileLoadCallback(
1257 receiver, holder, name, call_optimization);
1259 return compiler.CompileLoadViaGetter(receiver, holder, name, function);
1261 // TODO(dcarney): Handle correctly.
1262 if (callback->IsDeclaredAccessorInfo()) break;
1263 ASSERT(callback->IsForeign());
1264 // No IC support for old-style native accessors.
1268 ASSERT(HasInterceptorGetter(*holder));
1269 return compiler.CompileLoadInterceptor(receiver, holder, name);
1278 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1279 // This helper implements a few common fast cases for converting
1280 // non-smi keys of keyed loads/stores to a smi or a string.
1281 if (key->IsHeapNumber()) {
1282 double value = Handle<HeapNumber>::cast(key)->value();
1283 if (std::isnan(value)) {
1284 key = isolate->factory()->nan_string();
1286 int int_value = FastD2I(value);
1287 if (value == int_value && Smi::IsValid(int_value)) {
1288 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1291 } else if (key->IsUndefined()) {
1292 key = isolate->factory()->undefined_string();
1298 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
1299 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1300 // via megamorphic stubs, since they don't have a map in their relocation info
1301 // and so the stubs can't be harvested for the object needed for a map check.
1302 if (target()->type() != Code::NORMAL) {
1303 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
1304 return generic_stub();
1307 Handle<Map> receiver_map(receiver->map(), isolate());
1308 MapHandleList target_receiver_maps;
1309 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
1310 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1311 // yet will do so and stay there.
1312 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1315 if (target().is_identical_to(string_stub())) {
1316 target_receiver_maps.Add(isolate()->factory()->string_map());
1318 target()->FindAllMaps(&target_receiver_maps);
1319 if (target_receiver_maps.length() == 0) {
1320 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1324 // The first time a receiver is seen that is a transitioned version of the
1325 // previous monomorphic receiver type, assume the new ElementsKind is the
1326 // monomorphic type. This benefits global arrays that only transition
1327 // once, and all call sites accessing them are faster if they remain
1328 // monomorphic. If this optimistic assumption is not true, the IC will
1329 // miss again and it will become polymorphic and support both the
1330 // untransitioned and transitioned maps.
1331 if (state() == MONOMORPHIC &&
1332 IsMoreGeneralElementsKindTransition(
1333 target_receiver_maps.at(0)->elements_kind(),
1334 receiver->GetElementsKind())) {
1335 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1338 ASSERT(state() != GENERIC);
1340 // Determine the list of receiver maps that this call site has seen,
1341 // adding the map that was just encountered.
1342 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1343 // If the miss wasn't due to an unseen map, a polymorphic stub
1344 // won't help, use the generic stub.
1345 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
1346 return generic_stub();
1349 // If the maximum number of receiver maps has been exceeded, use the generic
1350 // version of the IC.
1351 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1352 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
1353 return generic_stub();
1356 return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
1357 &target_receiver_maps);
1361 MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
1363 ICMissMode miss_mode) {
1364 if (MigrateDeprecated(object)) {
1365 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1368 MaybeObject* maybe_object = NULL;
1369 Handle<Code> stub = generic_stub();
1371 // Check for values that can be converted into an internalized string directly
1372 // or is representable as a smi.
1373 key = TryConvertKey(key, isolate());
1375 if (key->IsInternalizedString()) {
1376 maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
1377 if (maybe_object->IsFailure()) return maybe_object;
1378 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1379 ASSERT(!object->IsJSGlobalProxy());
1380 if (miss_mode != MISS_FORCE_GENERIC) {
1381 if (object->IsString() && key->IsNumber()) {
1382 if (state() == UNINITIALIZED) stub = string_stub();
1383 } else if (object->IsJSObject()) {
1384 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1385 if (receiver->elements()->map() ==
1386 isolate()->heap()->non_strict_arguments_elements_map()) {
1387 stub = non_strict_arguments_stub();
1388 } else if (receiver->HasIndexedInterceptor()) {
1389 stub = indexed_interceptor_stub();
1390 } else if (!key->ToSmi()->IsFailure() &&
1391 (!target().is_identical_to(non_strict_arguments_stub()))) {
1392 stub = LoadElementStub(receiver);
1398 if (!is_target_set()) {
1399 if (*stub == *generic_stub()) {
1400 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1402 ASSERT(!stub.is_null());
1404 TRACE_IC("LoadIC", key);
1407 if (maybe_object != NULL) return maybe_object;
1408 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1412 static bool LookupForWrite(Handle<JSObject> receiver,
1413 Handle<String> name,
1414 Handle<Object> value,
1415 LookupResult* lookup,
1417 Handle<JSObject> holder = receiver;
1418 receiver->Lookup(*name, lookup);
1419 if (lookup->IsFound()) {
1420 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1422 if (lookup->holder() == *receiver) {
1423 if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) {
1424 receiver->LocalLookupRealNamedProperty(*name, lookup);
1425 return lookup->IsFound() &&
1426 !lookup->IsReadOnly() &&
1427 lookup->CanHoldValue(value) &&
1428 lookup->IsCacheable();
1430 return lookup->CanHoldValue(value);
1433 if (lookup->IsPropertyCallbacks()) return true;
1435 // Currently normal holders in the prototype chain are not supported. They
1436 // would require a runtime positive lookup and verification that the details
1437 // have not changed.
1438 if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1439 holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
1442 // While normally LookupTransition gets passed the receiver, in this case we
1443 // pass the holder of the property that we overwrite. This keeps the holder in
1444 // the LookupResult intact so we can later use it to generate a prototype
1445 // chain check. This avoids a double lookup, but requires us to pass in the
1446 // receiver when trying to fetch extra information from the transition.
1447 receiver->map()->LookupTransition(*holder, *name, lookup);
1448 if (!lookup->IsTransition()) return false;
1449 PropertyDetails target_details =
1450 lookup->GetTransitionDetails(receiver->map());
1451 if (target_details.IsReadOnly()) return false;
1453 // If the value that's being stored does not fit in the field that the
1454 // instance would transition to, create a new transition that fits the value.
1455 // This has to be done before generating the IC, since that IC will embed the
1456 // transition target.
1457 // Ensure the instance and its map were migrated before trying to update the
1458 // transition target.
1459 ASSERT(!receiver->map()->is_deprecated());
1460 if (!value->FitsRepresentation(target_details.representation())) {
1461 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
1462 Map::GeneralizeRepresentation(
1463 target, target->LastAdded(),
1464 value->OptimalRepresentation(), FORCE_FIELD);
1465 // Lookup the transition again since the transition tree may have changed
1466 // entirely by the migration above.
1467 receiver->map()->LookupTransition(*holder, *name, lookup);
1468 if (!lookup->IsTransition()) return false;
1469 ic->MarkMonomorphicPrototypeFailure();
1475 MaybeObject* StoreIC::Store(Handle<Object> object,
1476 Handle<String> name,
1477 Handle<Object> value,
1478 JSReceiver::StoreFromKeyed store_mode) {
1479 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1480 Handle<Object> result = JSReceiver::SetProperty(
1481 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode());
1482 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1486 // If the object is undefined or null it's illegal to try to set any
1487 // properties on it; throw a TypeError in that case.
1488 if (object->IsUndefined() || object->IsNull()) {
1489 return TypeError("non_object_property_store", object, name);
1492 // The length property of string values is read-only. Throw in strict mode.
1493 if (strict_mode() == kStrictMode && object->IsString() &&
1494 name->Equals(isolate()->heap()->length_string())) {
1495 return TypeError("strict_read_only_property", object, name);
1498 // Ignore other stores where the receiver is not a JSObject.
1499 // TODO(1475): Must check prototype chains of object wrappers.
1500 if (!object->IsJSObject()) return *value;
1502 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1504 // Check if the given name is an array index.
1506 if (name->AsArrayIndex(&index)) {
1507 Handle<Object> result =
1508 JSObject::SetElement(receiver, index, value, NONE, strict_mode());
1509 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1513 // Observed objects are always modified through the runtime.
1514 if (FLAG_harmony_observation && receiver->map()->is_observed()) {
1515 Handle<Object> result = JSReceiver::SetProperty(
1516 receiver, name, value, NONE, strict_mode(), store_mode);
1517 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1521 // Use specialized code for setting the length of arrays with fast
1522 // properties. Slow properties might indicate redefinition of the length
1523 // property. Note that when redefined using Object.freeze, it's possible
1524 // to have fast properties but a read-only length.
1526 receiver->IsJSArray() &&
1527 name->Equals(isolate()->heap()->length_string()) &&
1528 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
1529 receiver->HasFastProperties() &&
1530 !receiver->map()->is_frozen()) {
1532 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate());
1534 TRACE_IC("StoreIC", name);
1535 Handle<Object> result = JSReceiver::SetProperty(
1536 receiver, name, value, NONE, strict_mode(), store_mode);
1537 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1541 if (receiver->IsJSGlobalProxy()) {
1542 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
1543 // Generate a generic stub that goes to the runtime when we see a global
1544 // proxy as receiver.
1545 Handle<Code> stub = global_proxy_stub();
1547 TRACE_IC("StoreIC", name);
1549 Handle<Object> result = JSReceiver::SetProperty(
1550 receiver, name, value, NONE, strict_mode(), store_mode);
1551 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1555 LookupResult lookup(isolate());
1556 bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
1558 strict_mode() == kStrictMode &&
1559 !(lookup.IsProperty() && lookup.IsReadOnly()) &&
1560 IsUndeclaredGlobal(object)) {
1561 // Strict mode doesn't allow setting non-existent global property.
1562 return ReferenceError("not_defined", name);
1565 if (state() == UNINITIALIZED) {
1566 Handle<Code> stub = pre_monomorphic_stub();
1568 TRACE_IC("StoreIC", name);
1569 } else if (can_store) {
1570 UpdateCaches(&lookup, receiver, name, value);
1571 } else if (!name->IsCacheable(isolate()) ||
1572 lookup.IsNormal() ||
1573 (lookup.IsField() && lookup.CanHoldValue(value))) {
1574 Handle<Code> stub = generic_stub();
1579 // Set the property.
1580 Handle<Object> result = JSReceiver::SetProperty(
1581 receiver, name, value, NONE, strict_mode(), store_mode);
1582 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1587 void StoreIC::UpdateCaches(LookupResult* lookup,
1588 Handle<JSObject> receiver,
1589 Handle<String> name,
1590 Handle<Object> value) {
1591 ASSERT(!receiver->IsJSGlobalProxy());
1592 ASSERT(lookup->IsFound());
1594 // These are not cacheable, so we never see such LookupResults here.
1595 ASSERT(!lookup->IsHandler());
1597 Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
1599 PatchCache(receiver, name, code);
1600 TRACE_IC("StoreIC", name);
1604 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
1605 Handle<JSObject> receiver,
1606 Handle<String> name,
1607 Handle<Object> value) {
1608 Handle<JSObject> holder(lookup->holder());
1609 StoreStubCompiler compiler(isolate(), strict_mode(), kind());
1610 switch (lookup->type()) {
1612 return compiler.CompileStoreField(receiver, lookup, name);
1614 // Explicitly pass in the receiver map since LookupForWrite may have
1615 // stored something else than the receiver in the holder.
1616 Handle<Map> transition(
1617 lookup->GetTransitionTarget(receiver->map()), isolate());
1618 int descriptor = transition->LastAdded();
1620 DescriptorArray* target_descriptors = transition->instance_descriptors();
1621 PropertyDetails details = target_descriptors->GetDetails(descriptor);
1623 if (details.type() == CALLBACKS || details.attributes() != NONE) break;
1625 return compiler.CompileStoreTransition(
1626 receiver, lookup, transition, name);
1629 if (kind() == Code::KEYED_STORE_IC) break;
1630 if (receiver->IsGlobalObject()) {
1631 // The stub generated for the global object picks the value directly
1632 // from the property cell. So the property must be directly on the
1634 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1635 Handle<PropertyCell> cell(
1636 global->GetPropertyCell(lookup), isolate());
1637 // TODO(verwaest): Turn into a handler.
1638 return isolate()->stub_cache()->ComputeStoreGlobal(
1639 name, global, cell, value, strict_mode());
1641 ASSERT(holder.is_identical_to(receiver));
1642 return strict_mode() == kStrictMode
1643 ? isolate()->builtins()->StoreIC_Normal_Strict()
1644 : isolate()->builtins()->StoreIC_Normal();
1646 if (kind() == Code::KEYED_STORE_IC) break;
1647 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1648 if (callback->IsExecutableAccessorInfo()) {
1649 Handle<ExecutableAccessorInfo> info =
1650 Handle<ExecutableAccessorInfo>::cast(callback);
1651 if (v8::ToCData<Address>(info->setter()) == 0) break;
1652 if (!holder->HasFastProperties()) break;
1653 if (!info->IsCompatibleReceiver(*receiver)) break;
1654 return compiler.CompileStoreCallback(receiver, holder, name, info);
1655 } else if (callback->IsAccessorPair()) {
1656 Handle<Object> setter(
1657 Handle<AccessorPair>::cast(callback)->setter(), isolate());
1658 if (!setter->IsJSFunction()) break;
1659 if (holder->IsGlobalObject()) break;
1660 if (!holder->HasFastProperties()) break;
1661 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1662 CallOptimization call_optimization(function);
1663 if (call_optimization.is_simple_api_call() &&
1664 call_optimization.IsCompatibleReceiver(*receiver)) {
1665 return compiler.CompileStoreCallback(
1666 receiver, holder, name, call_optimization);
1668 return compiler.CompileStoreViaSetter(
1669 receiver, holder, name, Handle<JSFunction>::cast(setter));
1671 // TODO(dcarney): Handle correctly.
1672 if (callback->IsDeclaredAccessorInfo()) break;
1673 ASSERT(callback->IsForeign());
1674 // No IC support for old-style native accessors.
1678 if (kind() == Code::KEYED_STORE_IC) break;
1679 ASSERT(HasInterceptorSetter(*receiver));
1680 return compiler.CompileStoreInterceptor(receiver, name);
1692 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1693 KeyedAccessStoreMode store_mode) {
1694 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1695 // via megamorphic stubs, since they don't have a map in their relocation info
1696 // and so the stubs can't be harvested for the object needed for a map check.
1697 if (target()->type() != Code::NORMAL) {
1698 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
1699 return generic_stub();
1702 Handle<Map> receiver_map(receiver->map(), isolate());
1703 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
1704 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1705 // yet will do so and stay there.
1706 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
1707 store_mode = GetNonTransitioningStoreMode(store_mode);
1708 return isolate()->stub_cache()->ComputeKeyedStoreElement(
1709 monomorphic_map, strict_mode(), store_mode);
1712 MapHandleList target_receiver_maps;
1713 target()->FindAllMaps(&target_receiver_maps);
1714 if (target_receiver_maps.length() == 0) {
1715 // In the case that there is a non-map-specific IC is installed (e.g. keyed
1716 // stores into properties in dictionary mode), then there will be not
1717 // receiver maps in the target.
1718 return generic_stub();
1721 // There are several special cases where an IC that is MONOMORPHIC can still
1722 // transition to a different GetNonTransitioningStoreMode IC that handles a
1723 // superset of the original IC. Handle those here if the receiver map hasn't
1724 // changed or it has transitioned to a more general kind.
1725 KeyedAccessStoreMode old_store_mode =
1726 Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
1727 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1728 if (state() == MONOMORPHIC) {
1729 // If the "old" and "new" maps are in the same elements map family, stay
1730 // MONOMORPHIC and use the map for the most generic ElementsKind.
1731 Handle<Map> transitioned_receiver_map = receiver_map;
1732 if (IsTransitionStoreMode(store_mode)) {
1733 transitioned_receiver_map =
1734 ComputeTransitionedMap(receiver, store_mode);
1736 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
1737 // Element family is the same, use the "worst" case map.
1738 store_mode = GetNonTransitioningStoreMode(store_mode);
1739 return isolate()->stub_cache()->ComputeKeyedStoreElement(
1740 transitioned_receiver_map, strict_mode(), store_mode);
1741 } else if (*previous_receiver_map == receiver->map() &&
1742 old_store_mode == STANDARD_STORE &&
1743 (IsGrowStoreMode(store_mode) ||
1744 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1745 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1746 // A "normal" IC that handles stores can switch to a version that can
1747 // grow at the end of the array, handle OOB accesses or copy COW arrays
1748 // and still stay MONOMORPHIC.
1749 return isolate()->stub_cache()->ComputeKeyedStoreElement(
1750 receiver_map, strict_mode(), store_mode);
1754 ASSERT(state() != GENERIC);
1757 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1759 if (IsTransitionStoreMode(store_mode)) {
1760 Handle<Map> transitioned_receiver_map =
1761 ComputeTransitionedMap(receiver, store_mode);
1762 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1763 transitioned_receiver_map);
1767 // If the miss wasn't due to an unseen map, a polymorphic stub
1768 // won't help, use the generic stub.
1769 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
1770 return generic_stub();
1773 // If the maximum number of receiver maps has been exceeded, use the generic
1774 // version of the IC.
1775 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1776 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
1777 return generic_stub();
1780 // Make sure all polymorphic handlers have the same store mode, otherwise the
1781 // generic stub must be used.
1782 store_mode = GetNonTransitioningStoreMode(store_mode);
1783 if (old_store_mode != STANDARD_STORE) {
1784 if (store_mode == STANDARD_STORE) {
1785 store_mode = old_store_mode;
1786 } else if (store_mode != old_store_mode) {
1787 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
1788 return generic_stub();
1792 // If the store mode isn't the standard mode, make sure that all polymorphic
1793 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1794 // use the generic stub.
1795 if (store_mode != STANDARD_STORE) {
1796 int external_arrays = 0;
1797 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1798 if (target_receiver_maps[i]->has_external_array_elements()) {
1802 if (external_arrays != 0 &&
1803 external_arrays != target_receiver_maps.length()) {
1804 TRACE_GENERIC_IC(isolate(), "KeyedIC",
1805 "unsupported combination of external and normal arrays");
1806 return generic_stub();
1810 return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
1811 &target_receiver_maps, store_mode, strict_mode());
1815 Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1816 Handle<JSObject> receiver,
1817 KeyedAccessStoreMode store_mode) {
1818 switch (store_mode) {
1819 case STORE_TRANSITION_SMI_TO_OBJECT:
1820 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1821 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1822 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1823 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
1824 case STORE_TRANSITION_SMI_TO_DOUBLE:
1825 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1826 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
1827 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1828 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1829 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1830 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1831 return JSObject::GetElementsTransitionMap(receiver,
1832 FAST_HOLEY_ELEMENTS);
1833 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1834 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1835 return JSObject::GetElementsTransitionMap(receiver,
1836 FAST_HOLEY_DOUBLE_ELEMENTS);
1837 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1838 ASSERT(receiver->map()->has_external_array_elements());
1840 case STORE_NO_TRANSITION_HANDLE_COW:
1841 case STANDARD_STORE:
1842 case STORE_AND_GROW_NO_TRANSITION:
1843 return Handle<Map>(receiver->map(), isolate());
1845 return Handle<Map>::null();
1849 bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
1851 if (receiver->IsJSArray()) {
1852 return JSArray::cast(*receiver)->length()->IsSmi() &&
1853 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1855 return index >= receiver->elements()->length();
1859 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1861 Handle<Object> value) {
1862 ASSERT(!key->ToSmi()->IsFailure());
1863 Smi* smi_key = NULL;
1864 key->ToSmi()->To(&smi_key);
1865 int index = smi_key->value();
1866 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1867 bool allow_growth = receiver->IsJSArray() && oob_access;
1869 // Handle growing array in stub if necessary.
1870 if (receiver->HasFastSmiElements()) {
1871 if (value->IsHeapNumber()) {
1872 if (receiver->HasFastHoleyElements()) {
1873 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1875 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1878 if (value->IsHeapObject()) {
1879 if (receiver->HasFastHoleyElements()) {
1880 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1882 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1885 } else if (receiver->HasFastDoubleElements()) {
1886 if (!value->IsSmi() && !value->IsHeapNumber()) {
1887 if (receiver->HasFastHoleyElements()) {
1888 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1890 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1894 return STORE_AND_GROW_NO_TRANSITION;
1896 // Handle only in-bounds elements accesses.
1897 if (receiver->HasFastSmiElements()) {
1898 if (value->IsHeapNumber()) {
1899 if (receiver->HasFastHoleyElements()) {
1900 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1902 return STORE_TRANSITION_SMI_TO_DOUBLE;
1904 } else if (value->IsHeapObject()) {
1905 if (receiver->HasFastHoleyElements()) {
1906 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1908 return STORE_TRANSITION_SMI_TO_OBJECT;
1911 } else if (receiver->HasFastDoubleElements()) {
1912 if (!value->IsSmi() && !value->IsHeapNumber()) {
1913 if (receiver->HasFastHoleyElements()) {
1914 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1916 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1920 if (!FLAG_trace_external_array_abuse &&
1921 receiver->map()->has_external_array_elements() && oob_access) {
1922 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1924 Heap* heap = receiver->GetHeap();
1925 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1926 return STORE_NO_TRANSITION_HANDLE_COW;
1928 return STANDARD_STORE;
1934 MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
1936 Handle<Object> value,
1937 ICMissMode miss_mode) {
1938 if (MigrateDeprecated(object)) {
1939 return Runtime::SetObjectPropertyOrFail(
1940 isolate(), object , key, value, NONE, strict_mode());
1943 // Check for values that can be converted into an internalized string directly
1944 // or is representable as a smi.
1945 key = TryConvertKey(key, isolate());
1947 MaybeObject* maybe_object = NULL;
1948 Handle<Code> stub = generic_stub();
1950 if (key->IsInternalizedString()) {
1951 maybe_object = StoreIC::Store(object,
1952 Handle<String>::cast(key),
1954 JSReceiver::MAY_BE_STORE_FROM_KEYED);
1955 if (maybe_object->IsFailure()) return maybe_object;
1957 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1958 !(FLAG_harmony_observation && object->IsJSObject() &&
1959 JSObject::cast(*object)->map()->is_observed());
1960 if (use_ic && !object->IsSmi()) {
1961 // Don't use ICs for maps of the objects in Array's prototype chain. We
1962 // expect to be able to trap element sets to objects with those maps in
1963 // the runtime to enable optimization of element hole access.
1964 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
1965 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
1969 ASSERT(!object->IsJSGlobalProxy());
1971 if (miss_mode != MISS_FORCE_GENERIC) {
1972 if (object->IsJSObject()) {
1973 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1974 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
1975 if (receiver->elements()->map() ==
1976 isolate()->heap()->non_strict_arguments_elements_map()) {
1977 stub = non_strict_arguments_stub();
1978 } else if (key_is_smi_like &&
1979 (!target().is_identical_to(non_strict_arguments_stub()))) {
1980 KeyedAccessStoreMode store_mode =
1981 GetStoreMode(receiver, key, value);
1982 stub = StoreElementStub(receiver, store_mode);
1989 if (!is_target_set()) {
1990 if (*stub == *generic_stub()) {
1991 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
1993 ASSERT(!stub.is_null());
1995 TRACE_IC("StoreIC", key);
1998 if (maybe_object) return maybe_object;
1999 return Runtime::SetObjectPropertyOrFail(
2000 isolate(), object , key, value, NONE, strict_mode());
2007 // ----------------------------------------------------------------------------
2008 // Static IC stub generators.
2011 // Used from ic-<arch>.cc.
2012 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
2013 HandleScope scope(isolate);
2014 ASSERT(args.length() == 2);
2016 Handle<Object> receiver = args.at<Object>(0);
2017 Handle<String> key = args.at<String>(1);
2018 ic.UpdateState(receiver, key);
2019 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
2020 JSFunction* raw_function;
2021 if (!maybe_result->To(&raw_function)) return maybe_result;
2023 // The first time the inline cache is updated may be the first time the
2024 // function it references gets called. If the function is lazily compiled
2025 // then the first call will trigger a compilation. We check for this case
2026 // and we do the compilation immediately, instead of waiting for the stub
2027 // currently attached to the JSFunction object to trigger compilation.
2028 if (raw_function->is_compiled()) return raw_function;
2030 Handle<JSFunction> function(raw_function);
2031 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2036 // Used from ic-<arch>.cc.
2037 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
2038 HandleScope scope(isolate);
2039 ASSERT(args.length() == 2);
2040 KeyedCallIC ic(isolate);
2041 Handle<Object> receiver = args.at<Object>(0);
2042 Handle<Object> key = args.at<Object>(1);
2043 ic.UpdateState(receiver, key);
2044 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
2045 // Result could be a function or a failure.
2046 JSFunction* raw_function = NULL;
2047 if (!maybe_result->To(&raw_function)) return maybe_result;
2049 if (raw_function->is_compiled()) return raw_function;
2051 Handle<JSFunction> function(raw_function, isolate);
2052 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2057 // Used from ic-<arch>.cc.
2058 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
2059 HandleScope scope(isolate);
2060 ASSERT(args.length() == 2);
2061 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2062 Handle<Object> receiver = args.at<Object>(0);
2063 Handle<String> key = args.at<String>(1);
2064 ic.UpdateState(receiver, key);
2065 return ic.Load(receiver, key);
2069 // Used from ic-<arch>.cc
2070 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
2071 HandleScope scope(isolate);
2072 ASSERT(args.length() == 2);
2073 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2074 Handle<Object> receiver = args.at<Object>(0);
2075 Handle<Object> key = args.at<Object>(1);
2076 ic.UpdateState(receiver, key);
2077 return ic.Load(receiver, key, MISS);
2081 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
2082 HandleScope scope(isolate);
2083 ASSERT(args.length() == 2);
2084 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2085 Handle<Object> receiver = args.at<Object>(0);
2086 Handle<Object> key = args.at<Object>(1);
2087 ic.UpdateState(receiver, key);
2088 return ic.Load(receiver, key, MISS);
2092 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
2093 HandleScope scope(isolate);
2094 ASSERT(args.length() == 2);
2095 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2096 Handle<Object> receiver = args.at<Object>(0);
2097 Handle<Object> key = args.at<Object>(1);
2098 ic.UpdateState(receiver, key);
2099 return ic.Load(receiver, key, MISS_FORCE_GENERIC);
2103 // Used from ic-<arch>.cc.
2104 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
2105 HandleScope scope(isolate);
2106 ASSERT(args.length() == 3);
2107 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2108 Handle<Object> receiver = args.at<Object>(0);
2109 Handle<String> key = args.at<String>(1);
2110 ic.UpdateState(receiver, key);
2111 return ic.Store(receiver, key, args.at<Object>(2));
2115 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
2116 HandleScope scope(isolate);
2117 ASSERT(args.length() == 3);
2118 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2119 Handle<Object> receiver = args.at<Object>(0);
2120 Handle<String> key = args.at<String>(1);
2121 ic.UpdateState(receiver, key);
2122 return ic.Store(receiver, key, args.at<Object>(2));
2126 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
2127 SealHandleScope shs(isolate);
2129 ASSERT(args.length() == 2);
2130 JSArray* receiver = JSArray::cast(args[0]);
2131 Object* len = args[1];
2133 // The generated code should filter out non-Smis before we get here.
2134 ASSERT(len->IsSmi());
2137 // The length property has to be a writable callback property.
2138 LookupResult debug_lookup(isolate);
2139 receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
2140 ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
2144 MaybeObject* maybe_result = receiver->SetElementsLength(len);
2145 if (!maybe_result->To(&result)) return maybe_result;
2151 // Extend storage is called in a store inline cache when
2152 // it is necessary to extend the properties array of a
2154 RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
2155 SealHandleScope shs(isolate);
2156 ASSERT(args.length() == 3);
2158 // Convert the parameters
2159 JSObject* object = JSObject::cast(args[0]);
2160 Map* transition = Map::cast(args[1]);
2161 Object* value = args[2];
2163 // Check the object has run out out property space.
2164 ASSERT(object->HasFastProperties());
2165 ASSERT(object->map()->unused_property_fields() == 0);
2167 // Expand the properties array.
2168 FixedArray* old_storage = object->properties();
2169 int new_unused = transition->unused_property_fields();
2170 int new_size = old_storage->length() + new_unused + 1;
2172 MaybeObject* maybe_result = old_storage->CopySize(new_size);
2173 if (!maybe_result->ToObject(&result)) return maybe_result;
2175 FixedArray* new_storage = FixedArray::cast(result);
2177 Object* to_store = value;
2179 if (FLAG_track_double_fields) {
2180 DescriptorArray* descriptors = transition->instance_descriptors();
2181 PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
2182 if (details.representation().IsDouble()) {
2183 MaybeObject* maybe_storage =
2184 isolate->heap()->AllocateHeapNumber(value->Number());
2185 if (!maybe_storage->To(&to_store)) return maybe_storage;
2189 new_storage->set(old_storage->length(), to_store);
2191 // Set the new property value and do the map transition.
2192 object->set_properties(new_storage);
2193 object->set_map(transition);
2195 // Return the stored value.
2200 // Used from ic-<arch>.cc.
2201 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
2202 HandleScope scope(isolate);
2203 ASSERT(args.length() == 3);
2204 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2205 Handle<Object> receiver = args.at<Object>(0);
2206 Handle<Object> key = args.at<Object>(1);
2207 ic.UpdateState(receiver, key);
2208 return ic.Store(receiver, key, args.at<Object>(2), MISS);
2212 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
2213 HandleScope scope(isolate);
2214 ASSERT(args.length() == 3);
2215 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2216 Handle<Object> receiver = args.at<Object>(0);
2217 Handle<Object> key = args.at<Object>(1);
2218 ic.UpdateState(receiver, key);
2219 return ic.Store(receiver, key, args.at<Object>(2), MISS);
2223 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
2224 HandleScope scope(isolate);
2225 ASSERT(args.length() == 3);
2226 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2227 Handle<Object> object = args.at<Object>(0);
2228 Handle<Object> key = args.at<Object>(1);
2229 Handle<Object> value = args.at<Object>(2);
2230 StrictModeFlag strict_mode = ic.strict_mode();
2231 return Runtime::SetObjectProperty(isolate,
2240 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
2241 HandleScope scope(isolate);
2242 ASSERT(args.length() == 3);
2243 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2244 Handle<Object> object = args.at<Object>(0);
2245 Handle<Object> key = args.at<Object>(1);
2246 Handle<Object> value = args.at<Object>(2);
2247 StrictModeFlag strict_mode = ic.strict_mode();
2248 return Runtime::SetObjectProperty(isolate,
2257 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
2258 HandleScope scope(isolate);
2259 ASSERT(args.length() == 3);
2260 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2261 Handle<Object> receiver = args.at<Object>(0);
2262 Handle<Object> key = args.at<Object>(1);
2263 ic.UpdateState(receiver, key);
2264 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC);
2268 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
2269 HandleScope scope(isolate);
2270 ASSERT(args.length() == 4);
2271 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2272 Handle<Object> value = args.at<Object>(0);
2273 Handle<Object> key = args.at<Object>(2);
2274 Handle<Object> object = args.at<Object>(3);
2275 StrictModeFlag strict_mode = ic.strict_mode();
2276 return Runtime::SetObjectProperty(isolate,
2285 const char* BinaryOpIC::GetName(TypeInfo type_info) {
2286 switch (type_info) {
2287 case UNINITIALIZED: return "Uninitialized";
2288 case SMI: return "Smi";
2289 case INT32: return "Int32";
2290 case NUMBER: return "Number";
2291 case ODDBALL: return "Oddball";
2292 case STRING: return "String";
2293 case GENERIC: return "Generic";
2294 default: return "Invalid";
2299 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
2300 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2301 BinaryOpStub stub(extra_ic_state);
2303 Handle<Type> left_type = stub.GetLeftType(isolate());
2304 Handle<Type> right_type = stub.GetRightType(isolate());
2305 bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
2306 right_type->Maybe(Type::Smi());
2308 Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
2309 if (!result.has_value) return Failure::Exception();
2312 if (FLAG_trace_ic) {
2314 NoAllocationStringAllocator allocator(buffer,
2315 static_cast<unsigned>(sizeof(buffer)));
2316 StringStream stream(&allocator);
2318 stub.PrintName(&stream);
2320 stub.UpdateStatus(left, right, result);
2323 stub.PrintState(&stream);
2325 stream.OutputToStdOut();
2326 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
2327 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2330 stub.UpdateStatus(left, right, result);
2333 stub.UpdateStatus(left, right, result);
2336 Handle<Code> code = stub.GetCode(isolate());
2339 left_type = stub.GetLeftType(isolate());
2340 right_type = stub.GetRightType(isolate());
2341 bool enable_smi = left_type->Maybe(Type::Smi()) &&
2342 right_type->Maybe(Type::Smi());
2344 if (!smi_was_enabled && enable_smi) {
2345 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2346 } else if (smi_was_enabled && !enable_smi) {
2347 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2350 ASSERT(result.has_value);
2351 return static_cast<MaybeObject*>(*result.value);
2355 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
2356 HandleScope scope(isolate);
2357 Handle<Object> left = args.at<Object>(0);
2358 Handle<Object> right = args.at<Object>(1);
2359 BinaryOpIC ic(isolate);
2360 return ic.Transition(left, right);
2364 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2365 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
2367 CHECK(stub.FindCodeInCache(&code, isolate));
2372 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2373 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
2374 return stub.GetCode(isolate);
2378 const char* CompareIC::GetStateName(State state) {
2380 case UNINITIALIZED: return "UNINITIALIZED";
2381 case SMI: return "SMI";
2382 case NUMBER: return "NUMBER";
2383 case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
2384 case STRING: return "STRING";
2385 case UNIQUE_NAME: return "UNIQUE_NAME";
2386 case OBJECT: return "OBJECT";
2387 case KNOWN_OBJECT: return "KNOWN_OBJECT";
2388 case GENERIC: return "GENERIC";
2395 Handle<Type> CompareIC::StateToType(
2397 CompareIC::State state,
2400 case CompareIC::UNINITIALIZED:
2401 return handle(Type::None(), isolate);
2402 case CompareIC::SMI:
2403 return handle(Type::Smi(), isolate);
2404 case CompareIC::NUMBER:
2405 return handle(Type::Number(), isolate);
2406 case CompareIC::STRING:
2407 return handle(Type::String(), isolate);
2408 case CompareIC::INTERNALIZED_STRING:
2409 return handle(Type::InternalizedString(), isolate);
2410 case CompareIC::UNIQUE_NAME:
2411 return handle(Type::UniqueName(), isolate);
2412 case CompareIC::OBJECT:
2413 return handle(Type::Receiver(), isolate);
2414 case CompareIC::KNOWN_OBJECT:
2416 map.is_null() ? Type::Receiver() : Type::Class(map), isolate);
2417 case CompareIC::GENERIC:
2418 return handle(Type::Any(), isolate);
2421 return Handle<Type>();
2425 void CompareIC::StubInfoToType(int stub_minor_key,
2426 Handle<Type>* left_type,
2427 Handle<Type>* right_type,
2428 Handle<Type>* overall_type,
2431 State left_state, right_state, handler_state;
2432 ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
2433 &handler_state, NULL);
2434 *left_type = StateToType(isolate, left_state);
2435 *right_type = StateToType(isolate, right_state);
2436 *overall_type = StateToType(isolate, handler_state, map);
2440 CompareIC::State CompareIC::NewInputState(State old_state,
2441 Handle<Object> value) {
2442 switch (old_state) {
2444 if (value->IsSmi()) return SMI;
2445 if (value->IsHeapNumber()) return NUMBER;
2446 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2447 if (value->IsString()) return STRING;
2448 if (value->IsSymbol()) return UNIQUE_NAME;
2449 if (value->IsJSObject()) return OBJECT;
2452 if (value->IsSmi()) return SMI;
2453 if (value->IsHeapNumber()) return NUMBER;
2456 if (value->IsNumber()) return NUMBER;
2458 case INTERNALIZED_STRING:
2459 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2460 if (value->IsString()) return STRING;
2461 if (value->IsSymbol()) return UNIQUE_NAME;
2464 if (value->IsString()) return STRING;
2467 if (value->IsUniqueName()) return UNIQUE_NAME;
2470 if (value->IsJSObject()) return OBJECT;
2482 CompareIC::State CompareIC::TargetState(State old_state,
2485 bool has_inlined_smi_code,
2488 switch (old_state) {
2490 if (x->IsSmi() && y->IsSmi()) return SMI;
2491 if (x->IsNumber() && y->IsNumber()) return NUMBER;
2492 if (Token::IsOrderedRelationalCompareOp(op_)) {
2493 // Ordered comparisons treat undefined as NaN, so the
2494 // NUMBER stub will do the right thing.
2495 if ((x->IsNumber() && y->IsUndefined()) ||
2496 (y->IsNumber() && x->IsUndefined())) {
2500 if (x->IsInternalizedString() && y->IsInternalizedString()) {
2501 // We compare internalized strings as plain ones if we need to determine
2502 // the order in a non-equality compare.
2503 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
2505 if (x->IsString() && y->IsString()) return STRING;
2506 if (!Token::IsEqualityOp(op_)) return GENERIC;
2507 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2508 if (x->IsJSObject() && y->IsJSObject()) {
2509 if (Handle<JSObject>::cast(x)->map() ==
2510 Handle<JSObject>::cast(y)->map()) {
2511 return KNOWN_OBJECT;
2518 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
2519 case INTERNALIZED_STRING:
2520 ASSERT(Token::IsEqualityOp(op_));
2521 if (x->IsString() && y->IsString()) return STRING;
2522 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2525 // If the failure was due to one side changing from smi to heap number,
2526 // then keep the state (if other changed at the same time, we will get
2527 // a second miss and then go to generic).
2528 if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
2529 if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
2532 ASSERT(Token::IsEqualityOp(op_));
2533 if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
2542 return GENERIC; // Make the compiler happy.
2546 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2547 HandleScope scope(isolate());
2548 State previous_left, previous_right, previous_state;
2549 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
2550 &previous_right, &previous_state, NULL);
2551 State new_left = NewInputState(previous_left, x);
2552 State new_right = NewInputState(previous_right, y);
2553 State state = TargetState(previous_state, previous_left, previous_right,
2554 HasInlinedSmiCode(address()), x, y);
2555 ICCompareStub stub(op_, new_left, new_right, state);
2556 if (state == KNOWN_OBJECT) {
2558 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2560 set_target(*stub.GetCode(isolate()));
2563 if (FLAG_trace_ic) {
2564 PrintF("[CompareIC in ");
2565 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2566 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2567 GetStateName(previous_left),
2568 GetStateName(previous_right),
2569 GetStateName(previous_state),
2570 GetStateName(new_left),
2571 GetStateName(new_right),
2572 GetStateName(state),
2574 static_cast<void*>(*stub.GetCode(isolate())));
2578 // Activate inlined smi code.
2579 if (previous_state == UNINITIALIZED) {
2580 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2585 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
2586 RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
2587 HandleScope scope(isolate);
2588 ASSERT(args.length() == 3);
2589 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2590 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2591 return ic.raw_target();
2595 void CompareNilIC::Clear(Address address, Code* target) {
2596 if (IsCleared(target)) return;
2597 Code::ExtraICState state = target->extended_extra_ic_state();
2599 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED);
2603 CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
2605 SetTargetAtAddress(address, code);
2609 MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil,
2610 Handle<Object> object) {
2611 if (object->IsNull() || object->IsUndefined()) {
2612 return Smi::FromInt(true);
2614 return Smi::FromInt(object->IsUndetectableObject());
2618 MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
2619 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2621 CompareNilICStub stub(extra_ic_state);
2623 // Extract the current supported types from the patched IC and calculate what
2624 // types must be supported as a result of the miss.
2625 bool already_monomorphic = stub.IsMonomorphic();
2627 stub.UpdateStatus(object);
2629 NilValue nil = stub.GetNilValue();
2631 // Find or create the specialized stub to support the new set of types.
2633 if (stub.IsMonomorphic()) {
2634 Handle<Map> monomorphic_map(already_monomorphic
2635 ? target()->FindFirstMap()
2636 : HeapObject::cast(*object)->map());
2637 code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
2639 code = stub.GetCode(isolate());
2642 return DoCompareNilSlow(nil, object);
2646 RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
2647 HandleScope scope(isolate);
2648 Handle<Object> object = args.at<Object>(0);
2649 CompareNilIC ic(isolate);
2650 return ic.CompareNil(object);
2654 RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
2657 return isolate->heap()->undefined_value();
2661 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2666 return Builtins::ADD;
2669 return Builtins::SUB;
2672 return Builtins::MUL;
2675 return Builtins::DIV;
2678 return Builtins::MOD;
2681 return Builtins::BIT_OR;
2683 case Token::BIT_AND:
2684 return Builtins::BIT_AND;
2686 case Token::BIT_XOR:
2687 return Builtins::BIT_XOR;
2690 return Builtins::SAR;
2693 return Builtins::SHR;
2696 return Builtins::SHL;
2702 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
2703 Code::ExtraICState extra_ic_state) {
2704 ToBooleanStub stub(extra_ic_state);
2705 bool to_boolean_value = stub.UpdateStatus(object);
2706 Handle<Code> code = stub.GetCode(isolate());
2708 return Smi::FromInt(to_boolean_value ? 1 : 0);
2712 RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
2713 ASSERT(args.length() == 1);
2714 HandleScope scope(isolate);
2715 Handle<Object> object = args.at<Object>(0);
2716 ToBooleanIC ic(isolate);
2717 Code::ExtraICState extra_ic_state = ic.target()->extended_extra_ic_state();
2718 return ic.ToBoolean(object, extra_ic_state);
2722 static const Address IC_utilities[] = {
2723 #define ADDR(name) FUNCTION_ADDR(name),
2730 Address IC::AddressFromUtilityId(IC::UtilityId id) {
2731 return IC_utilities[id];
2735 } } // namespace v8::internal