blob: 0707536b84d1c7b6d8fa3154ef65c5aa3aa0c61e [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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.
4
5#include "src/v8.h"
6
7#include "src/accessors.h"
8#include "src/api.h"
9#include "src/arguments.h"
10#include "src/base/bits.h"
11#include "src/codegen.h"
12#include "src/conversions.h"
13#include "src/execution.h"
14#include "src/ic/call-optimization.h"
15#include "src/ic/handler-compiler.h"
16#include "src/ic/ic-inl.h"
17#include "src/ic/ic-compiler.h"
18#include "src/ic/stub-cache.h"
19#include "src/prototype.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021
22namespace v8 {
23namespace internal {
24
25char IC::TransitionMarkFromState(IC::State state) {
26 switch (state) {
27 case UNINITIALIZED:
28 return '0';
29 case PREMONOMORPHIC:
30 return '.';
31 case MONOMORPHIC:
32 return '1';
33 case PROTOTYPE_FAILURE:
34 return '^';
35 case POLYMORPHIC:
36 return 'P';
37 case MEGAMORPHIC:
38 return 'N';
39 case GENERIC:
40 return 'G';
41
42 // We never see the debugger states here, because the state is
43 // computed from the original code - not the patched code. Let
44 // these cases fall through to the unreachable code below.
45 case DEBUG_STUB:
46 break;
47 // Type-vector-based ICs resolve state to one of the above.
48 case DEFAULT:
49 break;
50 }
51 UNREACHABLE();
52 return 0;
53}
54
55
56const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
57 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
58 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
59 return ".IGNORE_OOB";
60 }
61 if (IsGrowStoreMode(mode)) return ".GROW";
62 return "";
63}
64
65
66#ifdef DEBUG
67
68#define TRACE_GENERIC_IC(isolate, type, reason) \
69 do { \
70 if (FLAG_trace_ic) { \
71 PrintF("[%s patching generic stub in ", type); \
72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
73 PrintF(" (%s)]\n", reason); \
74 } \
75 } while (false)
76
77#else
78
79#define TRACE_GENERIC_IC(isolate, type, reason) \
80 do { \
81 if (FLAG_trace_ic) { \
82 PrintF("[%s patching generic stub in ", type); \
83 PrintF("(see below) (%s)]\n", reason); \
84 } \
85 } while (false)
86
87#endif // DEBUG
88
89
90void IC::TraceIC(const char* type, Handle<Object> name) {
91 if (FLAG_trace_ic) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 State new_state =
93 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 TraceIC(type, name, state(), new_state);
95 }
96}
97
98
99void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
100 State new_state) {
101 if (FLAG_trace_ic) {
102 Code* new_target = raw_target();
103 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
104
105 // TODO(jkummerow): Add support for "apply". The logic is roughly:
106 // marker = [fp_ + kMarkerOffset];
107 // if marker is smi and marker.value == INTERNAL and
108 // the frame's code == builtin(Builtins::kFunctionApply):
109 // then print "apply from" and advance one frame
110
111 Object* maybe_function =
112 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
113 if (maybe_function->IsJSFunction()) {
114 JSFunction* function = JSFunction::cast(maybe_function);
115 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
116 stdout, true);
117 }
118
119 ExtraICState extra_state = new_target->extra_ic_state();
120 const char* modifier = "";
121 if (new_target->kind() == Code::KEYED_STORE_IC) {
122 modifier = GetTransitionMarkModifier(
123 KeyedStoreIC::GetKeyedAccessStoreMode(extra_state));
124 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 TransitionMarkFromState(new_state), modifier);
127#ifdef OBJECT_PRINT
128 OFStream os(stdout);
129 name->Print(os);
130#else
131 name->ShortPrint(stdout);
132#endif
133 PrintF("]\n");
134 }
135}
136
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400138#define TRACE_IC(type, name) TraceIC(type, name)
139
140
141IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
142 bool for_queries_only)
143 : isolate_(isolate),
144 target_set_(false),
145 target_maps_set_(false),
146 nexus_(nexus) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 // To improve the performance of the (much used) IC code, we unfold a few
148 // levels of the stack frame iteration code. This yields a ~35% speedup when
149 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
150 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
151 Address constant_pool = NULL;
152 if (FLAG_enable_ool_constant_pool) {
153 constant_pool =
154 Memory::Address_at(entry + ExitFrameConstants::kConstantPoolOffset);
155 }
156 Address* pc_address =
157 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
158 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
159 // If there's another JavaScript frame on the stack or a
160 // StubFailureTrampoline, we need to look one frame further down the stack to
161 // find the frame pointer and the return address stack slot.
162 if (depth == EXTRA_CALL_FRAME) {
163 if (FLAG_enable_ool_constant_pool) {
164 constant_pool =
165 Memory::Address_at(fp + StandardFrameConstants::kConstantPoolOffset);
166 }
167 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
168 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
169 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
170 }
171#ifdef DEBUG
172 StackFrameIterator it(isolate);
173 for (int i = 0; i < depth + 1; i++) it.Advance();
174 StackFrame* frame = it.frame();
175 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
176#endif
177 fp_ = fp;
178 if (FLAG_enable_ool_constant_pool) {
179 raw_constant_pool_ = handle(
180 ConstantPoolArray::cast(reinterpret_cast<Object*>(constant_pool)),
181 isolate);
182 }
183 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
184 target_ = handle(raw_target(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 kind_ = target_->kind();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186 state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
187 : target_->ic_state();
188 old_state_ = state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 extra_ic_state_ = target_->extra_ic_state();
190}
191
192
193SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
194 // Compute the JavaScript frame for the frame pointer of this IC
195 // structure. We need this to be able to find the function
196 // corresponding to the frame.
197 StackFrameIterator it(isolate());
198 while (it.frame()->fp() != this->fp()) it.Advance();
199 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
200 // Find the function on the stack and both the active code for the
201 // function and the original code.
202 JSFunction* function = frame->function();
203 return function->shared();
204}
205
206
207Code* IC::GetCode() const {
208 HandleScope scope(isolate());
209 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
210 Code* code = shared->code();
211 return code;
212}
213
214
215Code* IC::GetOriginalCode() const {
216 HandleScope scope(isolate());
217 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
218 DCHECK(Debug::HasDebugInfo(shared));
219 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
220 DCHECK(original_code->IsCode());
221 return original_code;
222}
223
224
225static void LookupForRead(LookupIterator* it) {
226 for (; it->IsFound(); it->Next()) {
227 switch (it->state()) {
228 case LookupIterator::NOT_FOUND:
229 case LookupIterator::TRANSITION:
230 UNREACHABLE();
231 case LookupIterator::JSPROXY:
232 return;
233 case LookupIterator::INTERCEPTOR: {
234 // If there is a getter, return; otherwise loop to perform the lookup.
235 Handle<JSObject> holder = it->GetHolder<JSObject>();
236 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
237 return;
238 }
239 break;
240 }
241 case LookupIterator::ACCESS_CHECK:
242 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
243 // access checks for global proxies.
244 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() &&
245 it->HasAccess(v8::ACCESS_GET)) {
246 break;
247 }
248 return;
249 case LookupIterator::ACCESSOR:
250 case LookupIterator::DATA:
251 return;
252 }
253 }
254}
255
256
257bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
258 Handle<String> name) {
259 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
260 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261 if (UseVector()) {
262 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map);
263 } else {
264 maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
265 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266
267 // The current map wasn't handled yet. There's no reason to stay monomorphic,
268 // *unless* we're moving from a deprecated map to its replacement, or
269 // to a more general elements kind.
270 // TODO(verwaest): Check if the current map is actually what the old map
271 // would transition to.
272 if (maybe_handler_.is_null()) {
273 if (!receiver_map->IsJSObjectMap()) return false;
274 Map* first_map = FirstTargetMap();
275 if (first_map == NULL) return false;
276 Handle<Map> old_map(first_map);
277 if (old_map->is_deprecated()) return true;
278 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
279 receiver_map->elements_kind())) {
280 return true;
281 }
282 return false;
283 }
284
285 CacheHolderFlag flag;
286 Handle<Map> ic_holder_map(
287 GetICCacheHolder(*receiver_type(), isolate(), &flag));
288
289 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
290 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
291 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
292
293 if (state() == MONOMORPHIC) {
294 int index = ic_holder_map->IndexInCodeCache(*name, *target());
295 if (index >= 0) {
296 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
297 }
298 }
299
300 if (receiver->IsGlobalObject()) {
301 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
302 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
303 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
304 if (!it.IsFound()) return false;
305 Handle<PropertyCell> cell = it.GetPropertyCell();
306 return cell->type()->IsConstant();
307 }
308
309 return true;
310}
311
312
313bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
314 if (target()->is_keyed_stub()) {
315 // Determine whether the failure is due to a name failure.
316 if (!name->IsName()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317 Name* stub_name =
318 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 if (*name != stub_name) return false;
320 }
321
322 return true;
323}
324
325
326void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
327 update_receiver_type(receiver);
328 if (!name->IsString()) return;
329 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
330 if (receiver->IsUndefined() || receiver->IsNull()) return;
331
332 // Remove the target from the code cache if it became invalid
333 // because of changes in the prototype chain to avoid hitting it
334 // again.
335 if (TryRemoveInvalidPrototypeDependentStub(receiver,
336 Handle<String>::cast(name))) {
337 MarkPrototypeFailure(name);
338 return;
339 }
340
341 // The builtins object is special. It only changes when JavaScript
342 // builtins are loaded lazily. It is important to keep inline
343 // caches for the builtins object monomorphic. Therefore, if we get
344 // an inline cache miss for the builtins object after lazily loading
345 // JavaScript builtins, we return uninitialized as the state to
346 // force the inline cache back to monomorphic state.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400347 if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348}
349
350
351MaybeHandle<Object> IC::TypeError(const char* type, Handle<Object> object,
352 Handle<Object> key) {
353 HandleScope scope(isolate());
354 Handle<Object> args[2] = {key, object};
355 THROW_NEW_ERROR(isolate(), NewTypeError(type, HandleVector(args, 2)), Object);
356}
357
358
359MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<Name> name) {
360 HandleScope scope(isolate());
361 THROW_NEW_ERROR(isolate(), NewReferenceError(type, HandleVector(&name, 1)),
362 Object);
363}
364
365
366static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
367 int* polymorphic_delta,
368 int* generic_delta) {
369 switch (old_state) {
370 case UNINITIALIZED:
371 case PREMONOMORPHIC:
372 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
373 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
374 *polymorphic_delta = 1;
375 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
376 *generic_delta = 1;
377 }
378 break;
379 case MONOMORPHIC:
380 case POLYMORPHIC:
381 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
382 *polymorphic_delta = -1;
383 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
384 *generic_delta = 1;
385 }
386 break;
387 case MEGAMORPHIC:
388 case GENERIC:
389 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
390 *generic_delta = -1;
391 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
392 *polymorphic_delta = 1;
393 }
394 break;
395 case PROTOTYPE_FAILURE:
396 case DEBUG_STUB:
397 case DEFAULT:
398 UNREACHABLE();
399 }
400}
401
402
403void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
404 State old_state, State new_state,
405 bool target_remains_ic_stub) {
406 Code* host =
407 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
408 if (host->kind() != Code::FUNCTION) return;
409
410 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
411 // Not all Code objects have TypeFeedbackInfo.
412 host->type_feedback_info()->IsTypeFeedbackInfo()) {
413 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
414 int generic_delta = 0; // "Generic" here includes megamorphic.
415 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
416 &generic_delta);
417 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
418 info->change_ic_with_type_info_count(polymorphic_delta);
419 info->change_ic_generic_count(generic_delta);
420 }
421 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
422 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
423 info->change_own_type_change_checksum();
424 }
425 host->set_profiler_ticks(0);
426 isolate->runtime_profiler()->NotifyICChanged();
427 // TODO(2029): When an optimized function is patched, it would
428 // be nice to propagate the corresponding type information to its
429 // unoptimized version for the benefit of later inlining.
430}
431
432
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400433// static
434void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
435 TypeFeedbackVector* vector, State old_state,
436 State new_state) {
437 if (host->kind() != Code::FUNCTION) return;
438
439 if (FLAG_type_info_threshold > 0) {
440 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
441 int generic_delta = 0; // "Generic" here includes megamorphic.
442 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
443 &generic_delta);
444 vector->change_ic_with_type_info_count(polymorphic_delta);
445 vector->change_ic_generic_count(generic_delta);
446 }
447 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
448 info->change_own_type_change_checksum();
449 host->set_profiler_ticks(0);
450 isolate->runtime_profiler()->NotifyICChanged();
451 // TODO(2029): When an optimized function is patched, it would
452 // be nice to propagate the corresponding type information to its
453 // unoptimized version for the benefit of later inlining.
454}
455
456
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457void IC::PostPatching(Address address, Code* target, Code* old_target) {
458 // Type vector based ICs update these statistics at a different time because
459 // they don't always patch on state change.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400460 if (ICUseVector(target->kind())) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461
462 Isolate* isolate = target->GetHeap()->isolate();
463 State old_state = UNINITIALIZED;
464 State new_state = UNINITIALIZED;
465 bool target_remains_ic_stub = false;
466 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
467 old_state = old_target->ic_state();
468 new_state = target->ic_state();
469 target_remains_ic_stub = true;
470 }
471
472 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
473 target_remains_ic_stub);
474}
475
476
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477void IC::Clear(Isolate* isolate, Address address,
478 ConstantPoolArray* constant_pool) {
479 Code* target = GetTargetAtAddress(address, constant_pool);
480
481 // Don't clear debug break inline cache as it will remove the break point.
482 if (target->is_debug_stub()) return;
483
484 switch (target->kind()) {
485 case Code::LOAD_IC:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400486 if (FLAG_vector_ics) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 return LoadIC::Clear(isolate, address, target, constant_pool);
488 case Code::KEYED_LOAD_IC:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400489 if (FLAG_vector_ics) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
491 case Code::STORE_IC:
492 return StoreIC::Clear(isolate, address, target, constant_pool);
493 case Code::KEYED_STORE_IC:
494 return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 case Code::COMPARE_IC:
496 return CompareIC::Clear(isolate, address, target, constant_pool);
497 case Code::COMPARE_NIL_IC:
498 return CompareNilIC::Clear(address, target, constant_pool);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400499 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 case Code::BINARY_OP_IC:
501 case Code::TO_BOOLEAN_IC:
502 // Clearing these is tricky and does not
503 // make any performance difference.
504 return;
505 default:
506 UNREACHABLE();
507 }
508}
509
510
511void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
512 ConstantPoolArray* constant_pool) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400513 DCHECK(!FLAG_vector_ics);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 if (IsCleared(target)) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400515
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516 // Make sure to also clear the map used in inline fast cases. If we
517 // do not clear these maps, cached code can keep objects alive
518 // through the embedded maps.
519 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
520}
521
522
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400523void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
524 if (IsCleared(nexus)) return;
525 // Make sure to also clear the map used in inline fast cases. If we
526 // do not clear these maps, cached code can keep objects alive
527 // through the embedded maps.
528 State state = nexus->StateFromFeedback();
529 nexus->ConfigurePremonomorphic();
530 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
531}
532
533
534void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
535 // Determine our state.
536 Object* feedback = nexus->vector()->Get(nexus->slot());
537 State state = nexus->StateFromFeedback();
538
539 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
540 nexus->ConfigureUninitialized();
541 // The change in state must be processed.
542 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
543 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544}
545
546
547void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
548 ConstantPoolArray* constant_pool) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 DCHECK(!FLAG_vector_ics);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 if (IsCleared(target)) return;
551 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC,
552 target->extra_ic_state());
553 SetTargetAtAddress(address, code, constant_pool);
554}
555
556
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400557void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
558 if (IsCleared(nexus)) return;
559 State state = nexus->StateFromFeedback();
560 nexus->ConfigurePremonomorphic();
561 OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
562}
563
564
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
566 ConstantPoolArray* constant_pool) {
567 if (IsCleared(target)) return;
568 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
569 target->extra_ic_state());
570 SetTargetAtAddress(address, code, constant_pool);
571}
572
573
574void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
575 ConstantPoolArray* constant_pool) {
576 if (IsCleared(target)) return;
577 SetTargetAtAddress(
578 address, *pre_monomorphic_stub(
579 isolate, StoreIC::GetStrictMode(target->extra_ic_state())),
580 constant_pool);
581}
582
583
584void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
585 ConstantPoolArray* constant_pool) {
586 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
587 CompareICStub stub(target->stub_key(), isolate);
588 // Only clear CompareICs that can retain objects.
589 if (stub.state() != CompareICState::KNOWN_OBJECT) return;
590 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
591 constant_pool);
592 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
593}
594
595
596// static
597Handle<Code> KeyedLoadIC::generic_stub(Isolate* isolate) {
598 if (FLAG_compiled_keyed_generic_loads) {
599 return KeyedLoadGenericStub(isolate).GetCode();
600 } else {
601 return isolate->builtins()->KeyedLoadIC_Generic();
602 }
603}
604
605
606static 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));
611 return true;
612}
613
614
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400615void IC::ConfigureVectorState(IC::State new_state) {
616 DCHECK(UseVector());
617 if (kind() == Code::LOAD_IC) {
618 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
619 if (new_state == PREMONOMORPHIC) {
620 nexus->ConfigurePremonomorphic();
621 } else if (new_state == MEGAMORPHIC) {
622 nexus->ConfigureMegamorphic();
623 } else {
624 UNREACHABLE();
625 }
626 } else if (kind() == Code::KEYED_LOAD_IC) {
627 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
628 if (new_state == GENERIC) {
629 nexus->ConfigureGeneric();
630 } else if (new_state == PREMONOMORPHIC) {
631 nexus->ConfigurePremonomorphic();
632 } else {
633 UNREACHABLE();
634 }
635 } else {
636 UNREACHABLE();
637 }
638
639 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
640 new_state);
641}
642
643
644void IC::ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
645 Handle<Code> handler) {
646 DCHECK(UseVector());
647 if (kind() == Code::LOAD_IC) {
648 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
649 nexus->ConfigureMonomorphic(type, handler);
650 } else {
651 DCHECK(kind() == Code::KEYED_LOAD_IC);
652 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
653 nexus->ConfigureMonomorphic(name, type, handler);
654 }
655
656 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
657 MONOMORPHIC);
658}
659
660
661void IC::ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
662 CodeHandleList* handlers) {
663 DCHECK(UseVector());
664 if (kind() == Code::LOAD_IC) {
665 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
666 nexus->ConfigurePolymorphic(types, handlers);
667 } else {
668 DCHECK(kind() == Code::KEYED_LOAD_IC);
669 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
670 nexus->ConfigurePolymorphic(name, types, handlers);
671 }
672
673 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
674 POLYMORPHIC);
675}
676
677
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
679 // If the object is undefined or null it's illegal to try to get any
680 // of its properties; throw a TypeError in that case.
681 if (object->IsUndefined() || object->IsNull()) {
682 return TypeError("non_object_property_load", object, name);
683 }
684
685 // Check if the name is trivially convertible to an index and get
686 // the element or char if so.
687 uint32_t index;
688 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
689 // Rewrite to the generic keyed load stub.
690 if (FLAG_use_ic) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400691 if (UseVector()) {
692 ConfigureVectorState(GENERIC);
693 } else {
694 set_target(*KeyedLoadIC::generic_stub(isolate()));
695 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000696 TRACE_IC("LoadIC", name);
697 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
698 }
699 Handle<Object> result;
700 ASSIGN_RETURN_ON_EXCEPTION(
701 isolate(), result,
702 Runtime::GetElementOrCharAt(isolate(), object, index), Object);
703 return result;
704 }
705
706 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
707
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400708 if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
709 // Look up in script context table.
710 Handle<String> str_name = Handle<String>::cast(name);
711 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
712 Handle<ScriptContextTable> script_contexts(
713 global->native_context()->script_context_table());
714
715 ScriptContextTable::LookupResult lookup_result;
716 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
717 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
718 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
719 PatchCache(name, stub.GetCode());
720 }
721 return FixedArray::get(ScriptContextTable::GetContext(
722 script_contexts, lookup_result.context_index),
723 lookup_result.slot_index);
724 }
725 }
726
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 // Named lookup in the object.
728 LookupIterator it(object, name);
729 LookupForRead(&it);
730
731 if (it.IsFound() || !IsUndeclaredGlobal(object)) {
732 // Update inline cache and stub cache.
733 if (use_ic) UpdateCaches(&it);
734
735 // Get the property.
736 Handle<Object> result;
737 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
738 Object);
739 if (it.IsFound()) {
740 return result;
741 } else if (!IsUndeclaredGlobal(object)) {
742 LOG(isolate(), SuspectReadEvent(*name, *object));
743 return result;
744 }
745 }
746 return ReferenceError("not_defined", name);
747}
748
749
750static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
751 Handle<Map> new_receiver_map) {
752 DCHECK(!new_receiver_map.is_null());
753 for (int current = 0; current < receiver_maps->length(); ++current) {
754 if (!receiver_maps->at(current).is_null() &&
755 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
756 return false;
757 }
758 }
759 receiver_maps->Add(new_receiver_map);
760 return true;
761}
762
763
764bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
765 if (!code->is_handler()) return false;
766 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
767 Handle<HeapType> type = receiver_type();
768 TypeHandleList types;
769 CodeHandleList handlers;
770
771 TargetTypes(&types);
772 int number_of_types = types.length();
773 int deprecated_types = 0;
774 int handler_to_overwrite = -1;
775
776 for (int i = 0; i < number_of_types; i++) {
777 Handle<HeapType> current_type = types.at(i);
778 if (current_type->IsClass() &&
779 current_type->AsClass()->Map()->is_deprecated()) {
780 // Filter out deprecated maps to ensure their instances get migrated.
781 ++deprecated_types;
782 } else if (type->NowIs(current_type)) {
783 // If the receiver type is already in the polymorphic IC, this indicates
784 // there was a prototoype chain failure. In that case, just overwrite the
785 // handler.
786 handler_to_overwrite = i;
787 } else if (handler_to_overwrite == -1 && current_type->IsClass() &&
788 type->IsClass() &&
789 IsTransitionOfMonomorphicTarget(*current_type->AsClass()->Map(),
790 *type->AsClass()->Map())) {
791 handler_to_overwrite = i;
792 }
793 }
794
795 int number_of_valid_types =
796 number_of_types - deprecated_types - (handler_to_overwrite != -1);
797
798 if (number_of_valid_types >= 4) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400799 if (number_of_types == 0 && state() != MONOMORPHIC &&
800 state() != POLYMORPHIC) {
801 return false;
802 }
803 if (UseVector()) {
804 if (!nexus()->FindHandlers(&handlers, types.length())) return false;
805 } else {
806 if (!target()->FindHandlers(&handlers, types.length())) return false;
807 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808
809 number_of_valid_types++;
810 if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
811 Handle<Code> ic;
812 if (number_of_valid_types == 1) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400813 if (UseVector()) {
814 ConfigureVectorState(name, receiver_type(), code);
815 } else {
816 ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
817 extra_ic_state());
818 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819 } else {
820 if (handler_to_overwrite >= 0) {
821 handlers.Set(handler_to_overwrite, code);
822 if (!type->NowIs(types.at(handler_to_overwrite))) {
823 types.Set(handler_to_overwrite, type);
824 }
825 } else {
826 types.Add(type);
827 handlers.Add(code);
828 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400829
830 if (UseVector()) {
831 ConfigureVectorState(name, &types, &handlers);
832 } else {
833 ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
834 number_of_valid_types, name,
835 extra_ic_state());
836 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400838
839 if (!UseVector()) set_target(*ic);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 return true;
841}
842
843
844Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) {
845 return object->IsJSGlobalObject()
846 ? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate)
847 : HeapType::NowOf(object, isolate);
848}
849
850
851Handle<Map> IC::TypeToMap(HeapType* type, Isolate* isolate) {
852 if (type->Is(HeapType::Number()))
853 return isolate->factory()->heap_number_map();
854 if (type->Is(HeapType::Boolean())) return isolate->factory()->boolean_map();
855 if (type->IsConstant()) {
856 return handle(
857 Handle<JSGlobalObject>::cast(type->AsConstant()->Value())->map());
858 }
859 DCHECK(type->IsClass());
860 return type->AsClass()->Map();
861}
862
863
864template <class T>
865typename T::TypeHandle IC::MapToType(Handle<Map> map,
866 typename T::Region* region) {
867 if (map->instance_type() == HEAP_NUMBER_TYPE) {
868 return T::Number(region);
869 } else if (map->instance_type() == ODDBALL_TYPE) {
870 // The only oddballs that can be recorded in ICs are booleans.
871 return T::Boolean(region);
872 } else {
873 return T::Class(map, region);
874 }
875}
876
877
878template Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone);
879
880
881template Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map,
882 Isolate* region);
883
884
885void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
886 DCHECK(handler->is_handler());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400887 if (UseVector()) {
888 ConfigureVectorState(name, receiver_type(), handler);
889 } else {
890 Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
891 kind(), name, receiver_type(), handler, extra_ic_state());
892 set_target(*ic);
893 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000894}
895
896
897void IC::CopyICToMegamorphicCache(Handle<Name> name) {
898 TypeHandleList types;
899 CodeHandleList handlers;
900 TargetTypes(&types);
901 if (!target()->FindHandlers(&handlers, types.length())) return;
902 for (int i = 0; i < types.length(); i++) {
903 UpdateMegamorphicCache(*types.at(i), *name, *handlers.at(i));
904 }
905}
906
907
908bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
909 if (source_map == NULL) return true;
910 if (target_map == NULL) return false;
911 ElementsKind target_elements_kind = target_map->elements_kind();
912 bool more_general_transition = IsMoreGeneralElementsKindTransition(
913 source_map->elements_kind(), target_elements_kind);
914 Map* transitioned_map =
915 more_general_transition
916 ? source_map->LookupElementsTransitionMap(target_elements_kind)
917 : NULL;
918
919 return transitioned_map == target_map;
920}
921
922
923void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
924 switch (state()) {
925 case UNINITIALIZED:
926 case PREMONOMORPHIC:
927 UpdateMonomorphicIC(code, name);
928 break;
929 case PROTOTYPE_FAILURE:
930 case MONOMORPHIC:
931 case POLYMORPHIC:
932 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
933 if (UpdatePolymorphicIC(name, code)) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400934 // For keyed stubs, we can't know whether old handlers were for the
935 // same key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000936 CopyICToMegamorphicCache(name);
937 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400938 if (UseVector()) {
939 ConfigureVectorState(kind() == Code::KEYED_LOAD_IC ? GENERIC
940 : MEGAMORPHIC);
941 } else {
942 set_target(*megamorphic_stub());
943 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000944 // Fall through.
945 case MEGAMORPHIC:
946 UpdateMegamorphicCache(*receiver_type(), *name, *code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400947 // Indicate that we've handled this case.
948 target_set_ = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949 break;
950 case DEBUG_STUB:
951 break;
952 case DEFAULT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 UNREACHABLE();
954 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400955 case GENERIC:
956 // The generic keyed store stub re-uses store handlers, which can miss.
957 // That's ok, no reason to do anything.
958 DCHECK(target()->kind() == Code::KEYED_STORE_IC);
959 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960 }
961}
962
963
964Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
965 ExtraICState extra_state) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400966 if (FLAG_vector_ics) {
967 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
968 }
969
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000970 return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state);
971}
972
973
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400974Handle<Code> LoadIC::initialize_stub_in_optimized_code(
975 Isolate* isolate, ExtraICState extra_state) {
976 if (FLAG_vector_ics) {
977 return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
978 }
979 return initialize_stub(isolate, extra_state);
980}
981
982
983Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
984 if (FLAG_vector_ics) {
985 return KeyedLoadICTrampolineStub(isolate).GetCode();
986 }
987
988 return isolate->builtins()->KeyedLoadIC_Initialize();
989}
990
991
992Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
993 if (FLAG_vector_ics) {
994 return VectorKeyedLoadStub(isolate).GetCode();
995 }
996 return initialize_stub(isolate);
997}
998
999
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001000Handle<Code> LoadIC::megamorphic_stub() {
1001 if (kind() == Code::LOAD_IC) {
1002 MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state()));
1003 return stub.GetCode();
1004 } else {
1005 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
1006 return KeyedLoadIC::generic_stub(isolate());
1007 }
1008}
1009
1010
1011Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
1012 ExtraICState extra_state) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001013 DCHECK(!FLAG_vector_ics);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
1015}
1016
1017
1018Handle<Code> KeyedLoadIC::pre_monomorphic_stub(Isolate* isolate) {
1019 return isolate->builtins()->KeyedLoadIC_PreMonomorphic();
1020}
1021
1022
1023Handle<Code> LoadIC::pre_monomorphic_stub() const {
1024 if (kind() == Code::LOAD_IC) {
1025 return LoadIC::pre_monomorphic_stub(isolate(), extra_ic_state());
1026 } else {
1027 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
1028 return KeyedLoadIC::pre_monomorphic_stub(isolate());
1029 }
1030}
1031
1032
1033Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
1034 LoadFieldStub stub(isolate(), index);
1035 return stub.GetCode();
1036}
1037
1038
1039void LoadIC::UpdateCaches(LookupIterator* lookup) {
1040 if (state() == UNINITIALIZED) {
1041 // This is the first time we execute this inline cache. Set the target to
1042 // the pre monomorphic stub to delay setting the monomorphic state.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001043 if (UseVector()) {
1044 ConfigureVectorState(PREMONOMORPHIC);
1045 } else {
1046 set_target(*pre_monomorphic_stub());
1047 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001048 TRACE_IC("LoadIC", lookup->name());
1049 return;
1050 }
1051
1052 Handle<Code> code;
1053 if (lookup->state() == LookupIterator::JSPROXY ||
1054 lookup->state() == LookupIterator::ACCESS_CHECK) {
1055 code = slow_stub();
1056 } else if (!lookup->IsFound()) {
1057 if (kind() == Code::LOAD_IC) {
1058 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
1059 receiver_type());
1060 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1061 if (code.is_null()) code = slow_stub();
1062 } else {
1063 code = slow_stub();
1064 }
1065 } else {
1066 code = ComputeHandler(lookup);
1067 }
1068
1069 PatchCache(lookup->name(), code);
1070 TRACE_IC("LoadIC", lookup->name());
1071}
1072
1073
1074void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001075 // Megamorphic state isn't implemented for keyed loads currently.
1076 if (kind() == Code::KEYED_LOAD_IC) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 Map* map = *TypeToMap(type, isolate());
1078 isolate()->stub_cache()->Set(name, map, code);
1079}
1080
1081
1082Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1083 bool receiver_is_holder =
1084 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1085 CacheHolderFlag flag;
1086 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
1087 *receiver_type(), receiver_is_holder, isolate(), &flag);
1088
1089 Handle<Code> code = PropertyHandlerCompiler::Find(
1090 lookup->name(), stub_holder_map, kind(), flag,
1091 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1092 // Use the cached value if it exists, and if it is different from the
1093 // handler that just missed.
1094 if (!code.is_null()) {
1095 if (!maybe_handler_.is_null() &&
1096 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1097 return code;
1098 }
1099 if (maybe_handler_.is_null()) {
1100 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1101 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1102 // cache (which just missed) is different from the cached handler.
1103 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1104 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1105 Code* megamorphic_cached_code =
1106 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1107 if (megamorphic_cached_code != *code) return code;
1108 } else {
1109 return code;
1110 }
1111 }
1112 }
1113
1114 code = CompileHandler(lookup, value, flag);
1115 DCHECK(code->is_handler());
1116
1117 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1118 // code compiled for this map, otherwise it's already cached in the global
1119 // code
1120 // cache. We are also guarding against installing code with flags that don't
1121 // match the desired CacheHolderFlag computed above, which would lead to
1122 // invalid lookups later.
1123 if (code->type() != Code::NORMAL &&
1124 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1125 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1126 }
1127
1128 return code;
1129}
1130
1131
1132Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1133 Handle<Object> unused,
1134 CacheHolderFlag cache_holder) {
1135 Handle<Object> receiver = lookup->GetReceiver();
1136 if (receiver->IsString() &&
1137 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1138 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1139 return SimpleFieldLoad(index);
1140 }
1141
1142 if (receiver->IsStringWrapper() &&
1143 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1144 StringLengthStub string_length_stub(isolate());
1145 return string_length_stub.GetCode();
1146 }
1147
1148 // Use specialized code for getting prototype of functions.
1149 if (receiver->IsJSFunction() &&
1150 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
1151 Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
1152 !Handle<JSFunction>::cast(receiver)
1153 ->map()
1154 ->has_non_instance_prototype()) {
1155 Handle<Code> stub;
1156 FunctionPrototypeStub function_prototype_stub(isolate());
1157 return function_prototype_stub.GetCode();
1158 }
1159
1160 Handle<HeapType> type = receiver_type();
1161 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1162 bool receiver_is_holder = receiver.is_identical_to(holder);
1163 switch (lookup->state()) {
1164 case LookupIterator::INTERCEPTOR: {
1165 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1166 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1167 cache_holder);
1168 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1169 // the original iterator will be used to fetch the value.
1170 LookupIterator it = *lookup;
1171 it.Next();
1172 LookupForRead(&it);
1173 return compiler.CompileLoadInterceptor(&it);
1174 }
1175
1176 case LookupIterator::ACCESSOR: {
1177 // Use simple field loads for some well-known callback properties.
1178 if (receiver_is_holder) {
1179 DCHECK(receiver->IsJSObject());
1180 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
1181 int object_offset;
1182 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(),
1183 &object_offset)) {
1184 FieldIndex index =
1185 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map());
1186 return SimpleFieldLoad(index);
1187 }
1188 }
1189
1190 Handle<Object> accessors = lookup->GetAccessors();
1191 if (accessors->IsExecutableAccessorInfo()) {
1192 Handle<ExecutableAccessorInfo> info =
1193 Handle<ExecutableAccessorInfo>::cast(accessors);
1194 if (v8::ToCData<Address>(info->getter()) == 0) break;
1195 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
1196 type)) {
1197 break;
1198 }
1199 if (!holder->HasFastProperties()) break;
1200 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1201 cache_holder);
1202 return compiler.CompileLoadCallback(lookup->name(), info);
1203 }
1204 if (accessors->IsAccessorPair()) {
1205 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1206 isolate());
1207 if (!getter->IsJSFunction()) break;
1208 if (!holder->HasFastProperties()) break;
1209 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1210 if (!receiver->IsJSObject() && !function->IsBuiltin() &&
1211 function->shared()->strict_mode() == SLOPPY) {
1212 // Calling sloppy non-builtins with a value as the receiver
1213 // requires boxing.
1214 break;
1215 }
1216 CallOptimization call_optimization(function);
1217 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1218 cache_holder);
1219 if (call_optimization.is_simple_api_call() &&
1220 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1221 return compiler.CompileLoadCallback(lookup->name(),
1222 call_optimization);
1223 }
1224 return compiler.CompileLoadViaGetter(lookup->name(), function);
1225 }
1226 // TODO(dcarney): Handle correctly.
1227 DCHECK(accessors->IsDeclaredAccessorInfo());
1228 break;
1229 }
1230
1231 case LookupIterator::DATA: {
1232 if (lookup->is_dictionary_holder()) {
1233 if (kind() != Code::LOAD_IC) break;
1234 if (holder->IsGlobalObject()) {
1235 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1236 cache_holder);
1237 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1238 Handle<Code> code = compiler.CompileLoadGlobal(
1239 cell, lookup->name(), lookup->IsConfigurable());
1240 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1241 CacheHolderFlag flag;
1242 Handle<Map> stub_holder_map = GetHandlerCacheHolder(
1243 *type, receiver_is_holder, isolate(), &flag);
1244 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1245 return code;
1246 }
1247 // There is only one shared stub for loading normalized
1248 // properties. It does not traverse the prototype chain, so the
1249 // property must be found in the object for the stub to be
1250 // applicable.
1251 if (!receiver_is_holder) break;
1252 return isolate()->builtins()->LoadIC_Normal();
1253 }
1254
1255 // -------------- Fields --------------
1256 if (lookup->property_details().type() == FIELD) {
1257 FieldIndex field = lookup->GetFieldIndex();
1258 if (receiver_is_holder) {
1259 return SimpleFieldLoad(field);
1260 }
1261 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1262 cache_holder);
1263 return compiler.CompileLoadField(lookup->name(), field);
1264 }
1265
1266 // -------------- Constant properties --------------
1267 DCHECK(lookup->property_details().type() == CONSTANT);
1268 if (receiver_is_holder) {
1269 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1270 return stub.GetCode();
1271 }
1272 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1273 cache_holder);
1274 return compiler.CompileLoadConstant(lookup->name(),
1275 lookup->GetConstantIndex());
1276 }
1277
1278 case LookupIterator::ACCESS_CHECK:
1279 case LookupIterator::JSPROXY:
1280 case LookupIterator::NOT_FOUND:
1281 case LookupIterator::TRANSITION:
1282 UNREACHABLE();
1283 }
1284
1285 return slow_stub();
1286}
1287
1288
1289static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1290 // This helper implements a few common fast cases for converting
1291 // non-smi keys of keyed loads/stores to a smi or a string.
1292 if (key->IsHeapNumber()) {
1293 double value = Handle<HeapNumber>::cast(key)->value();
1294 if (std::isnan(value)) {
1295 key = isolate->factory()->nan_string();
1296 } else {
1297 int int_value = FastD2I(value);
1298 if (value == int_value && Smi::IsValid(int_value)) {
1299 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
1300 }
1301 }
1302 } else if (key->IsUndefined()) {
1303 key = isolate->factory()->undefined_string();
1304 }
1305 return key;
1306}
1307
1308
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001309Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1310 Handle<Code> null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311 Handle<Map> receiver_map(receiver->map(), isolate());
1312 MapHandleList target_receiver_maps;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001313 TargetMaps(&target_receiver_maps);
1314
1315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316 if (target_receiver_maps.length() == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001317 if (FLAG_vector_ics) {
1318 Handle<Code> handler =
1319 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1320 ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
1321 return null_handle;
1322 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1324 }
1325
1326 // The first time a receiver is seen that is a transitioned version of the
1327 // previous monomorphic receiver type, assume the new ElementsKind is the
1328 // monomorphic type. This benefits global arrays that only transition
1329 // once, and all call sites accessing them are faster if they remain
1330 // monomorphic. If this optimistic assumption is not true, the IC will
1331 // miss again and it will become polymorphic and support both the
1332 // untransitioned and transitioned maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001333 if (state() == MONOMORPHIC && !receiver->IsString() &&
1334 IsMoreGeneralElementsKindTransition(
1335 target_receiver_maps.at(0)->elements_kind(),
1336 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1337 if (FLAG_vector_ics) {
1338 Handle<Code> handler =
1339 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
1340 ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
1341 return null_handle;
1342 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343 return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
1344 }
1345
1346 DCHECK(state() != GENERIC);
1347
1348 // Determine the list of receiver maps that this call site has seen,
1349 // adding the map that was just encountered.
1350 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1351 // If the miss wasn't due to an unseen map, a polymorphic stub
1352 // won't help, use the generic stub.
1353 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001354 if (FLAG_vector_ics) {
1355 ConfigureVectorState(GENERIC);
1356 return null_handle;
1357 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 return generic_stub();
1359 }
1360
1361 // If the maximum number of receiver maps has been exceeded, use the generic
1362 // version of the IC.
1363 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1364 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001365 if (FLAG_vector_ics) {
1366 ConfigureVectorState(GENERIC);
1367 return null_handle;
1368 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 return generic_stub();
1370 }
1371
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001372 if (FLAG_vector_ics) {
1373 CodeHandleList handlers(target_receiver_maps.length());
1374 ElementHandlerCompiler compiler(isolate());
1375 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
1376 TypeHandleList types(target_receiver_maps.length());
1377 for (int i = 0; i < target_receiver_maps.length(); i++) {
1378 types.Add(HeapType::Class(target_receiver_maps.at(i), isolate()));
1379 }
1380 ConfigureVectorState(Handle<Name>::null(), &types, &handlers);
1381 return null_handle;
1382 }
1383
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001384 return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps);
1385}
1386
1387
1388MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1389 Handle<Object> key) {
1390 if (MigrateDeprecated(object)) {
1391 Handle<Object> result;
1392 ASSIGN_RETURN_ON_EXCEPTION(
1393 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1394 Object);
1395 return result;
1396 }
1397
1398 Handle<Object> load_handle;
1399 Handle<Code> stub = generic_stub();
1400
1401 // Check for non-string values that can be converted into an
1402 // internalized string directly or is representable as a smi.
1403 key = TryConvertKey(key, isolate());
1404
1405 if (key->IsInternalizedString() || key->IsSymbol()) {
1406 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1407 LoadIC::Load(object, Handle<Name>::cast(key)),
1408 Object);
1409 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001410 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1411 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
1412 if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 stub = LoadElementStub(receiver);
1414 }
1415 }
1416 }
1417
1418 if (!is_target_set()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001419 if (!FLAG_vector_ics) {
1420 Code* generic = *generic_stub();
1421 if (*stub == generic) {
1422 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1423 }
1424
1425 set_target(*stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001426 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 TRACE_IC("LoadIC", key);
1428 }
1429
1430 if (!load_handle.is_null()) return load_handle;
1431 Handle<Object> result;
1432 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1433 Runtime::GetObjectProperty(isolate(), object, key),
1434 Object);
1435 return result;
1436}
1437
1438
1439bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1440 JSReceiver::StoreFromKeyed store_mode) {
1441 // Disable ICs for non-JSObjects for now.
1442 Handle<Object> receiver = it->GetReceiver();
1443 if (!receiver->IsJSObject()) return false;
1444 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1445
1446 for (; it->IsFound(); it->Next()) {
1447 switch (it->state()) {
1448 case LookupIterator::NOT_FOUND:
1449 case LookupIterator::TRANSITION:
1450 UNREACHABLE();
1451 case LookupIterator::JSPROXY:
1452 return false;
1453 case LookupIterator::INTERCEPTOR: {
1454 Handle<JSObject> holder = it->GetHolder<JSObject>();
1455 InterceptorInfo* info = holder->GetNamedInterceptor();
1456 if (it->HolderIsReceiverOrHiddenPrototype()) {
1457 if (!info->setter()->IsUndefined()) return true;
1458 } else if (!info->getter()->IsUndefined() ||
1459 !info->query()->IsUndefined()) {
1460 return false;
1461 }
1462 break;
1463 }
1464 case LookupIterator::ACCESS_CHECK:
1465 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1466 break;
1467 case LookupIterator::ACCESSOR:
1468 return !it->IsReadOnly();
1469 case LookupIterator::DATA: {
1470 if (it->IsReadOnly()) return false;
1471 Handle<JSObject> holder = it->GetHolder<JSObject>();
1472 if (receiver.is_identical_to(holder)) {
1473 it->PrepareForDataProperty(value);
1474 // The previous receiver map might just have been deprecated,
1475 // so reload it.
1476 update_receiver_type(receiver);
1477 return true;
1478 }
1479
1480 // Receiver != holder.
1481 PrototypeIterator iter(it->isolate(), receiver);
1482 if (receiver->IsJSGlobalProxy()) {
1483 return it->GetHolder<Object>().is_identical_to(
1484 PrototypeIterator::GetCurrent(iter));
1485 }
1486
1487 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1488 return it->IsCacheableTransition();
1489 }
1490 }
1491 }
1492
1493 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1494 return it->IsCacheableTransition();
1495}
1496
1497
1498MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1499 Handle<Object> value,
1500 JSReceiver::StoreFromKeyed store_mode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001501 if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
1502 // Look up in script context table.
1503 Handle<String> str_name = Handle<String>::cast(name);
1504 Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
1505 Handle<ScriptContextTable> script_contexts(
1506 global->native_context()->script_context_table());
1507
1508 ScriptContextTable::LookupResult lookup_result;
1509 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1510 Handle<Context> script_context = ScriptContextTable::GetContext(
1511 script_contexts, lookup_result.context_index);
1512 if (lookup_result.mode == CONST) {
1513 return TypeError("harmony_const_assign", object, name);
1514 }
1515
1516 if (FLAG_use_ic &&
1517 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1518 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1519 PatchCache(name, stub.GetCode());
1520 }
1521
1522 script_context->set(lookup_result.slot_index, *value);
1523 return value;
1524 }
1525 }
1526
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001527 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1528 // might deprecate the current map again, if value does not fit.
1529 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1530 Handle<Object> result;
1531 ASSIGN_RETURN_ON_EXCEPTION(
1532 isolate(), result,
1533 Object::SetProperty(object, name, value, strict_mode()), Object);
1534 return result;
1535 }
1536
1537 // If the object is undefined or null it's illegal to try to set any
1538 // properties on it; throw a TypeError in that case.
1539 if (object->IsUndefined() || object->IsNull()) {
1540 return TypeError("non_object_property_store", object, name);
1541 }
1542
1543 // Check if the given name is an array index.
1544 uint32_t index;
1545 if (name->AsArrayIndex(&index)) {
1546 // Ignore other stores where the receiver is not a JSObject.
1547 // TODO(1475): Must check prototype chains of object wrappers.
1548 if (!object->IsJSObject()) return value;
1549 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1550
1551 Handle<Object> result;
1552 ASSIGN_RETURN_ON_EXCEPTION(
1553 isolate(), result,
1554 JSObject::SetElement(receiver, index, value, NONE, strict_mode()),
1555 Object);
1556 return value;
1557 }
1558
1559 // Observed objects are always modified through the runtime.
1560 if (object->IsHeapObject() &&
1561 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1562 Handle<Object> result;
1563 ASSIGN_RETURN_ON_EXCEPTION(
1564 isolate(), result,
1565 Object::SetProperty(object, name, value, strict_mode(), store_mode),
1566 Object);
1567 return result;
1568 }
1569
1570 LookupIterator it(object, name);
1571 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1572
1573 // Set the property.
1574 Handle<Object> result;
1575 ASSIGN_RETURN_ON_EXCEPTION(
1576 isolate(), result,
1577 Object::SetProperty(&it, value, strict_mode(), store_mode), Object);
1578 return result;
1579}
1580
1581
1582Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
1583 CallICState::CallType call_type) {
1584 CallICStub stub(isolate, CallICState(argc, call_type));
1585 Handle<Code> code = stub.GetCode();
1586 return code;
1587}
1588
1589
1590Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1591 StrictMode strict_mode) {
1592 ExtraICState extra_state = ComputeExtraICState(strict_mode);
1593 Handle<Code> ic =
1594 PropertyICCompiler::ComputeStore(isolate, UNINITIALIZED, extra_state);
1595 return ic;
1596}
1597
1598
1599Handle<Code> StoreIC::megamorphic_stub() {
1600 if (kind() == Code::STORE_IC) {
1601 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1602 extra_ic_state());
1603 } else {
1604 DCHECK(kind() == Code::KEYED_STORE_IC);
1605 if (strict_mode() == STRICT) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001606 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001608 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609 }
1610 }
1611}
1612
1613
1614Handle<Code> StoreIC::generic_stub() const {
1615 if (kind() == Code::STORE_IC) {
1616 return PropertyICCompiler::ComputeStore(isolate(), GENERIC,
1617 extra_ic_state());
1618 } else {
1619 DCHECK(kind() == Code::KEYED_STORE_IC);
1620 if (strict_mode() == STRICT) {
1621 return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
1622 } else {
1623 return isolate()->builtins()->KeyedStoreIC_Generic();
1624 }
1625 }
1626}
1627
1628
1629Handle<Code> StoreIC::slow_stub() const {
1630 if (kind() == Code::STORE_IC) {
1631 return isolate()->builtins()->StoreIC_Slow();
1632 } else {
1633 DCHECK(kind() == Code::KEYED_STORE_IC);
1634 return isolate()->builtins()->KeyedStoreIC_Slow();
1635 }
1636}
1637
1638
1639Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1640 StrictMode strict_mode) {
1641 ExtraICState state = ComputeExtraICState(strict_mode);
1642 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1643}
1644
1645
1646void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1647 JSReceiver::StoreFromKeyed store_mode) {
1648 if (state() == UNINITIALIZED) {
1649 // This is the first time we execute this inline cache. Set the target to
1650 // the pre monomorphic stub to delay setting the monomorphic state.
1651 set_target(*pre_monomorphic_stub());
1652 TRACE_IC("StoreIC", lookup->name());
1653 return;
1654 }
1655
1656 bool use_ic = LookupForWrite(lookup, value, store_mode);
1657 if (!use_ic) {
1658 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1659 }
1660 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1661
1662 PatchCache(lookup->name(), code);
1663 TRACE_IC("StoreIC", lookup->name());
1664}
1665
1666
1667Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1668 Handle<Object> value,
1669 CacheHolderFlag cache_holder) {
1670 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1671
1672 // This is currently guaranteed by checks in StoreIC::Store.
1673 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1674 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1675 DCHECK(!receiver->IsAccessCheckNeeded());
1676
1677 switch (lookup->state()) {
1678 case LookupIterator::TRANSITION: {
1679 Handle<Map> transition = lookup->transition_map();
1680 // Currently not handled by CompileStoreTransition.
1681 if (!holder->HasFastProperties()) {
1682 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1683 break;
1684 }
1685
1686 DCHECK(lookup->IsCacheableTransition());
1687 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1688 return compiler.CompileStoreTransition(transition, lookup->name());
1689 }
1690
1691 case LookupIterator::INTERCEPTOR: {
1692 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1693 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1694 return compiler.CompileStoreInterceptor(lookup->name());
1695 }
1696
1697 case LookupIterator::ACCESSOR: {
1698 if (!holder->HasFastProperties()) {
1699 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1700 break;
1701 }
1702 Handle<Object> accessors = lookup->GetAccessors();
1703 if (accessors->IsExecutableAccessorInfo()) {
1704 Handle<ExecutableAccessorInfo> info =
1705 Handle<ExecutableAccessorInfo>::cast(accessors);
1706 if (v8::ToCData<Address>(info->setter()) == 0) {
1707 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1708 break;
1709 }
1710 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
1711 isolate(), info, receiver_type())) {
1712 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1713 break;
1714 }
1715 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1716 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1717 } else if (accessors->IsAccessorPair()) {
1718 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1719 isolate());
1720 if (!setter->IsJSFunction()) {
1721 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1722 break;
1723 }
1724 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1725 CallOptimization call_optimization(function);
1726 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1727 if (call_optimization.is_simple_api_call() &&
1728 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1729 return compiler.CompileStoreCallback(receiver, lookup->name(),
1730 call_optimization);
1731 }
1732 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
1733 Handle<JSFunction>::cast(setter));
1734 }
1735 // TODO(dcarney): Handle correctly.
1736 DCHECK(accessors->IsDeclaredAccessorInfo());
1737 TRACE_GENERIC_IC(isolate(), "StoreIC", "declared accessor info");
1738 break;
1739 }
1740
1741 case LookupIterator::DATA: {
1742 if (lookup->is_dictionary_holder()) {
1743 if (holder->IsGlobalObject()) {
1744 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1745 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
1746 StoreGlobalStub stub(isolate(), union_type->IsConstant(),
1747 receiver->IsJSGlobalProxy());
1748 Handle<Code> code = stub.GetCodeCopyFromTemplate(
1749 Handle<GlobalObject>::cast(holder), cell);
1750 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1751 HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code);
1752 return code;
1753 }
1754 DCHECK(holder.is_identical_to(receiver));
1755 return isolate()->builtins()->StoreIC_Normal();
1756 }
1757
1758 // -------------- Fields --------------
1759 if (lookup->property_details().type() == FIELD) {
1760 bool use_stub = true;
1761 if (lookup->representation().IsHeapObject()) {
1762 // Only use a generic stub if no types need to be tracked.
1763 Handle<HeapType> field_type = lookup->GetFieldType();
1764 HeapType::Iterator<Map> it = field_type->Classes();
1765 use_stub = it.Done();
1766 }
1767 if (use_stub) {
1768 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1769 lookup->representation());
1770 return stub.GetCode();
1771 }
1772 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1773 return compiler.CompileStoreField(lookup);
1774 }
1775
1776 // -------------- Constant properties --------------
1777 DCHECK(lookup->property_details().type() == CONSTANT);
1778 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1779 break;
1780 }
1781
1782 case LookupIterator::ACCESS_CHECK:
1783 case LookupIterator::JSPROXY:
1784 case LookupIterator::NOT_FOUND:
1785 UNREACHABLE();
1786 }
1787 return slow_stub();
1788}
1789
1790
1791Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1792 KeyedAccessStoreMode store_mode) {
1793 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1794 // via megamorphic stubs, since they don't have a map in their relocation info
1795 // and so the stubs can't be harvested for the object needed for a map check.
1796 if (target()->type() != Code::NORMAL) {
1797 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
1798 return generic_stub();
1799 }
1800
1801 Handle<Map> receiver_map(receiver->map(), isolate());
1802 MapHandleList target_receiver_maps;
1803 TargetMaps(&target_receiver_maps);
1804 if (target_receiver_maps.length() == 0) {
1805 Handle<Map> monomorphic_map =
1806 ComputeTransitionedMap(receiver_map, store_mode);
1807 store_mode = GetNonTransitioningStoreMode(store_mode);
1808 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1809 monomorphic_map, strict_mode(), store_mode);
1810 }
1811
1812 // There are several special cases where an IC that is MONOMORPHIC can still
1813 // transition to a different GetNonTransitioningStoreMode IC that handles a
1814 // superset of the original IC. Handle those here if the receiver map hasn't
1815 // changed or it has transitioned to a more general kind.
1816 KeyedAccessStoreMode old_store_mode =
1817 KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
1818 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1819 if (state() == MONOMORPHIC) {
1820 Handle<Map> transitioned_receiver_map = receiver_map;
1821 if (IsTransitionStoreMode(store_mode)) {
1822 transitioned_receiver_map =
1823 ComputeTransitionedMap(receiver_map, store_mode);
1824 }
1825 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1826 IsTransitionStoreMode(store_mode)) ||
1827 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1828 *transitioned_receiver_map)) {
1829 // If the "old" and "new" maps are in the same elements map family, or
1830 // if they at least come from the same origin for a transitioning store,
1831 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1832 store_mode = GetNonTransitioningStoreMode(store_mode);
1833 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1834 transitioned_receiver_map, strict_mode(), store_mode);
1835 } else if (*previous_receiver_map == receiver->map() &&
1836 old_store_mode == STANDARD_STORE &&
1837 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1838 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1839 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1840 // A "normal" IC that handles stores can switch to a version that can
1841 // grow at the end of the array, handle OOB accesses or copy COW arrays
1842 // and still stay MONOMORPHIC.
1843 return PropertyICCompiler::ComputeKeyedStoreMonomorphic(
1844 receiver_map, strict_mode(), store_mode);
1845 }
1846 }
1847
1848 DCHECK(state() != GENERIC);
1849
1850 bool map_added =
1851 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1852
1853 if (IsTransitionStoreMode(store_mode)) {
1854 Handle<Map> transitioned_receiver_map =
1855 ComputeTransitionedMap(receiver_map, store_mode);
1856 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1857 transitioned_receiver_map);
1858 }
1859
1860 if (!map_added) {
1861 // If the miss wasn't due to an unseen map, a polymorphic stub
1862 // won't help, use the generic stub.
1863 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
1864 return generic_stub();
1865 }
1866
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001867 // If the maximum number of receiver maps has been exceeded, use the
1868 // megamorphic version of the IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001869 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001870 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001871 }
1872
1873 // Make sure all polymorphic handlers have the same store mode, otherwise the
1874 // generic stub must be used.
1875 store_mode = GetNonTransitioningStoreMode(store_mode);
1876 if (old_store_mode != STANDARD_STORE) {
1877 if (store_mode == STANDARD_STORE) {
1878 store_mode = old_store_mode;
1879 } else if (store_mode != old_store_mode) {
1880 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
1881 return generic_stub();
1882 }
1883 }
1884
1885 // If the store mode isn't the standard mode, make sure that all polymorphic
1886 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1887 // use the generic stub.
1888 if (store_mode != STANDARD_STORE) {
1889 int external_arrays = 0;
1890 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1891 if (target_receiver_maps[i]->has_external_array_elements() ||
1892 target_receiver_maps[i]->has_fixed_typed_array_elements()) {
1893 external_arrays++;
1894 }
1895 }
1896 if (external_arrays != 0 &&
1897 external_arrays != target_receiver_maps.length()) {
1898 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1899 "unsupported combination of external and normal arrays");
1900 return generic_stub();
1901 }
1902 }
1903
1904 return PropertyICCompiler::ComputeKeyedStorePolymorphic(
1905 &target_receiver_maps, store_mode, strict_mode());
1906}
1907
1908
1909Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1910 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1911 switch (store_mode) {
1912 case STORE_TRANSITION_SMI_TO_OBJECT:
1913 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1914 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1915 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
1916 return Map::TransitionElementsTo(map, FAST_ELEMENTS);
1917 case STORE_TRANSITION_SMI_TO_DOUBLE:
1918 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
1919 return Map::TransitionElementsTo(map, FAST_DOUBLE_ELEMENTS);
1920 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1921 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1922 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1923 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1924 return Map::TransitionElementsTo(map, FAST_HOLEY_ELEMENTS);
1925 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1926 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1927 return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS);
1928 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1929 DCHECK(map->has_external_array_elements());
1930 // Fall through
1931 case STORE_NO_TRANSITION_HANDLE_COW:
1932 case STANDARD_STORE:
1933 case STORE_AND_GROW_NO_TRANSITION:
1934 return map;
1935 }
1936 UNREACHABLE();
1937 return MaybeHandle<Map>().ToHandleChecked();
1938}
1939
1940
1941bool IsOutOfBoundsAccess(Handle<JSObject> receiver, int index) {
1942 if (receiver->IsJSArray()) {
1943 return JSArray::cast(*receiver)->length()->IsSmi() &&
1944 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1945 }
1946 return index >= receiver->elements()->length();
1947}
1948
1949
1950KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1951 Handle<Object> key,
1952 Handle<Object> value) {
1953 Handle<Smi> smi_key = Object::ToSmi(isolate(), key).ToHandleChecked();
1954 int index = smi_key->value();
1955 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1956 // Don't consider this a growing store if the store would send the receiver to
1957 // dictionary mode.
1958 bool allow_growth = receiver->IsJSArray() && oob_access &&
1959 !receiver->WouldConvertToSlowElements(key);
1960 if (allow_growth) {
1961 // Handle growing array in stub if necessary.
1962 if (receiver->HasFastSmiElements()) {
1963 if (value->IsHeapNumber()) {
1964 if (receiver->HasFastHoleyElements()) {
1965 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1966 } else {
1967 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1968 }
1969 }
1970 if (value->IsHeapObject()) {
1971 if (receiver->HasFastHoleyElements()) {
1972 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1973 } else {
1974 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1975 }
1976 }
1977 } else if (receiver->HasFastDoubleElements()) {
1978 if (!value->IsSmi() && !value->IsHeapNumber()) {
1979 if (receiver->HasFastHoleyElements()) {
1980 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1981 } else {
1982 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1983 }
1984 }
1985 }
1986 return STORE_AND_GROW_NO_TRANSITION;
1987 } else {
1988 // Handle only in-bounds elements accesses.
1989 if (receiver->HasFastSmiElements()) {
1990 if (value->IsHeapNumber()) {
1991 if (receiver->HasFastHoleyElements()) {
1992 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1993 } else {
1994 return STORE_TRANSITION_SMI_TO_DOUBLE;
1995 }
1996 } else if (value->IsHeapObject()) {
1997 if (receiver->HasFastHoleyElements()) {
1998 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1999 } else {
2000 return STORE_TRANSITION_SMI_TO_OBJECT;
2001 }
2002 }
2003 } else if (receiver->HasFastDoubleElements()) {
2004 if (!value->IsSmi() && !value->IsHeapNumber()) {
2005 if (receiver->HasFastHoleyElements()) {
2006 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2007 } else {
2008 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
2009 }
2010 }
2011 }
2012 if (!FLAG_trace_external_array_abuse &&
2013 receiver->map()->has_external_array_elements() && oob_access) {
2014 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2015 }
2016 Heap* heap = receiver->GetHeap();
2017 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2018 return STORE_NO_TRANSITION_HANDLE_COW;
2019 } else {
2020 return STANDARD_STORE;
2021 }
2022 }
2023}
2024
2025
2026MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2027 Handle<Object> key,
2028 Handle<Object> value) {
2029 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2030 // might deprecate the current map again, if value does not fit.
2031 if (MigrateDeprecated(object)) {
2032 Handle<Object> result;
2033 ASSIGN_RETURN_ON_EXCEPTION(
2034 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2035 value, strict_mode()),
2036 Object);
2037 return result;
2038 }
2039
2040 // Check for non-string values that can be converted into an
2041 // internalized string directly or is representable as a smi.
2042 key = TryConvertKey(key, isolate());
2043
2044 Handle<Object> store_handle;
2045 Handle<Code> stub = generic_stub();
2046
2047 if (key->IsInternalizedString()) {
2048 ASSIGN_RETURN_ON_EXCEPTION(
2049 isolate(), store_handle,
2050 StoreIC::Store(object, Handle<String>::cast(key), value,
2051 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2052 Object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002053 if (!is_target_set()) {
2054 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2055 "unhandled internalized string key");
2056 TRACE_IC("StoreIC", key);
2057 set_target(*stub);
2058 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002059 return store_handle;
2060 }
2061
2062 bool use_ic =
2063 FLAG_use_ic && !object->IsStringWrapper() &&
2064 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2065 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2066 if (use_ic && !object->IsSmi()) {
2067 // Don't use ICs for maps of the objects in Array's prototype chain. We
2068 // expect to be able to trap element sets to objects with those maps in
2069 // the runtime to enable optimization of element hole access.
2070 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2071 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2072 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2073 use_ic = false;
2074 }
2075 }
2076
2077 if (use_ic) {
2078 DCHECK(!object->IsAccessCheckNeeded());
2079
2080 if (object->IsJSObject()) {
2081 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2082 bool key_is_smi_like = !Object::ToSmi(isolate(), key).is_null();
2083 if (receiver->elements()->map() ==
2084 isolate()->heap()->sloppy_arguments_elements_map()) {
2085 if (strict_mode() == SLOPPY) {
2086 stub = sloppy_arguments_stub();
2087 } else {
2088 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2089 }
2090 } else if (key_is_smi_like &&
2091 !(target().is_identical_to(sloppy_arguments_stub()))) {
2092 // We should go generic if receiver isn't a dictionary, but our
2093 // prototype chain does have dictionary elements. This ensures that
2094 // other non-dictionary receivers in the polymorphic case benefit
2095 // from fast path keyed stores.
2096 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
2097 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
2098 stub = StoreElementStub(receiver, store_mode);
2099 } else {
2100 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "dictionary prototype");
2101 }
2102 } else {
2103 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2104 }
2105 } else {
2106 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2107 }
2108 }
2109
2110 if (store_handle.is_null()) {
2111 ASSIGN_RETURN_ON_EXCEPTION(
2112 isolate(), store_handle,
2113 Runtime::SetObjectProperty(isolate(), object, key, value,
2114 strict_mode()),
2115 Object);
2116 }
2117
2118 DCHECK(!is_target_set());
2119 Code* generic = *generic_stub();
2120 if (*stub == generic) {
2121 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
2122 }
2123 if (*stub == *slow_stub()) {
2124 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub");
2125 }
2126 DCHECK(!stub.is_null());
2127 set_target(*stub);
2128 TRACE_IC("StoreIC", key);
2129
2130 return store_handle;
2131}
2132
2133
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002134// static
2135void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
2136 StrictMode strict_mode) {
2137 PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
2138}
2139
2140
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002141bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002142 const CallICState& callic_state) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002143 DCHECK(FLAG_use_ic && function->IsJSFunction());
2144
2145 // Are we the array function?
2146 Handle<JSFunction> array_function =
2147 Handle<JSFunction>(isolate()->native_context()->array_function());
2148 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
2149 // Alter the slot.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002150 CallICNexus* nexus = casted_nexus<CallICNexus>();
2151 nexus->ConfigureMonomorphicArray();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002153 CallIC_ArrayStub stub(isolate(), callic_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002154 set_target(*stub.GetCode());
2155 Handle<String> name;
2156 if (array_function->shared()->name()->IsString()) {
2157 name = Handle<String>(String::cast(array_function->shared()->name()),
2158 isolate());
2159 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002160 TRACE_IC("CallIC", name);
2161 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2162 MONOMORPHIC);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 return true;
2164 }
2165 return false;
2166}
2167
2168
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002169void CallIC::PatchMegamorphic(Handle<Object> function) {
2170 CallICState callic_state(target()->extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002171
2172 // We are going generic.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002173 CallICNexus* nexus = casted_nexus<CallICNexus>();
2174 nexus->ConfigureGeneric();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002175
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002176 CallICStub stub(isolate(), callic_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002177 Handle<Code> code = stub.GetCode();
2178 set_target(*code);
2179
2180 Handle<Object> name = isolate()->factory()->empty_string();
2181 if (function->IsJSFunction()) {
2182 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2183 name = handle(js_function->shared()->name(), isolate());
2184 }
2185
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002186 TRACE_IC("CallIC", name);
2187 OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
2188 GENERIC);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189}
2190
2191
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002192void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
2193 CallICState callic_state(target()->extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002194 Handle<Object> name = isolate()->factory()->empty_string();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002195 CallICNexus* nexus = casted_nexus<CallICNexus>();
2196 Object* feedback = nexus->GetFeedback();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002197
2198 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2199 DCHECK(!feedback->IsSmi());
2200
2201 if (feedback->IsJSFunction() || !function->IsJSFunction()) {
2202 // We are going generic.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002203 nexus->ConfigureGeneric();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002204 } else {
2205 // The feedback is either uninitialized or an allocation site.
2206 // It might be an allocation site because if we re-compile the full code
2207 // to add deoptimization support, we call with the default call-ic, and
2208 // merely need to patch the target to match the feedback.
2209 // TODO(mvstanton): the better approach is to dispense with patching
2210 // altogether, which is in progress.
2211 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) ||
2212 feedback->IsAllocationSite());
2213
2214 // Do we want to install a custom handler?
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002215 if (FLAG_use_ic && DoCustomHandler(receiver, function, callic_state)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002216 return;
2217 }
2218
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002219 nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002220 }
2221
2222 if (function->IsJSFunction()) {
2223 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2224 name = handle(js_function->shared()->name(), isolate());
2225 }
2226
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002227 IC::State new_state = nexus->StateFromFeedback();
2228 OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
2229 TRACE_IC("CallIC", name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002230}
2231
2232
2233#undef TRACE_IC
2234
2235
2236// ----------------------------------------------------------------------------
2237// Static IC stub generators.
2238//
2239
2240// Used from ic-<arch>.cc.
2241RUNTIME_FUNCTION(CallIC_Miss) {
2242 TimerEventScope<TimerEventIcMiss> timer(isolate);
2243 HandleScope scope(isolate);
2244 DCHECK(args.length() == 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002245 Handle<Object> receiver = args.at<Object>(0);
2246 Handle<Object> function = args.at<Object>(1);
2247 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
2248 Handle<Smi> slot = args.at<Smi>(3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002249 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2250 CallICNexus nexus(vector, vector_slot);
2251 CallIC ic(isolate, &nexus);
2252 ic.HandleMiss(receiver, function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002253 return *function;
2254}
2255
2256
2257RUNTIME_FUNCTION(CallIC_Customization_Miss) {
2258 TimerEventScope<TimerEventIcMiss> timer(isolate);
2259 HandleScope scope(isolate);
2260 DCHECK(args.length() == 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002261 Handle<Object> function = args.at<Object>(1);
2262 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
2263 Handle<Smi> slot = args.at<Smi>(3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002264 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2265 CallICNexus nexus(vector, vector_slot);
2266 // A miss on a custom call ic always results in going megamorphic.
2267 CallIC ic(isolate, &nexus);
2268 ic.PatchMegamorphic(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002269 return *function;
2270}
2271
2272
2273// Used from ic-<arch>.cc.
2274RUNTIME_FUNCTION(LoadIC_Miss) {
2275 TimerEventScope<TimerEventIcMiss> timer(isolate);
2276 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002277 Handle<Object> receiver = args.at<Object>(0);
2278 Handle<Name> key = args.at<Name>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002280
2281 if (FLAG_vector_ics) {
2282 DCHECK(args.length() == 4);
2283 Handle<Smi> slot = args.at<Smi>(2);
2284 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2285 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2286 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2287 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2288 // set up outside the IC, handle that here.
2289 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2290 LoadICNexus nexus(vector, vector_slot);
2291 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2292 ic.UpdateState(receiver, key);
2293 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2294 ic.Load(receiver, key));
2295 } else {
2296 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2297 KeyedLoadICNexus nexus(vector, vector_slot);
2298 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2299 ic.UpdateState(receiver, key);
2300 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2301 ic.Load(receiver, key));
2302 }
2303 } else {
2304 DCHECK(args.length() == 2);
2305 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2306 ic.UpdateState(receiver, key);
2307 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2308 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002309 return *result;
2310}
2311
2312
2313// Used from ic-<arch>.cc
2314RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
2315 TimerEventScope<TimerEventIcMiss> timer(isolate);
2316 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002317 Handle<Object> receiver = args.at<Object>(0);
2318 Handle<Object> key = args.at<Object>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002319 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002320
2321 if (FLAG_vector_ics) {
2322 DCHECK(args.length() == 4);
2323 Handle<Smi> slot = args.at<Smi>(2);
2324 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2325 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2326 KeyedLoadICNexus nexus(vector, vector_slot);
2327 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2328 ic.UpdateState(receiver, key);
2329 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2330 } else {
2331 DCHECK(args.length() == 2);
2332 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2333 ic.UpdateState(receiver, key);
2334 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2335 }
2336
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002337 return *result;
2338}
2339
2340
2341RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
2342 TimerEventScope<TimerEventIcMiss> timer(isolate);
2343 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002344 Handle<Object> receiver = args.at<Object>(0);
2345 Handle<Object> key = args.at<Object>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002346 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002347
2348 if (FLAG_vector_ics) {
2349 DCHECK(args.length() == 4);
2350 Handle<Smi> slot = args.at<Smi>(2);
2351 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2352 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2353 KeyedLoadICNexus nexus(vector, vector_slot);
2354 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2355 ic.UpdateState(receiver, key);
2356 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2357 } else {
2358 DCHECK(args.length() == 2);
2359 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2360 ic.UpdateState(receiver, key);
2361 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2362 }
2363
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002364 return *result;
2365}
2366
2367
2368// Used from ic-<arch>.cc.
2369RUNTIME_FUNCTION(StoreIC_Miss) {
2370 TimerEventScope<TimerEventIcMiss> timer(isolate);
2371 HandleScope scope(isolate);
2372 DCHECK(args.length() == 3);
2373 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2374 Handle<Object> receiver = args.at<Object>(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002375 Handle<Name> key = args.at<Name>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002376 ic.UpdateState(receiver, key);
2377 Handle<Object> result;
2378 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2379 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2380 return *result;
2381}
2382
2383
2384RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
2385 TimerEventScope<TimerEventIcMiss> timer(isolate);
2386 HandleScope scope(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002387 DCHECK(args.length() == 3 || args.length() == 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002388 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2389 Handle<Object> receiver = args.at<Object>(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002390 Handle<Name> key = args.at<Name>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002391 ic.UpdateState(receiver, key);
2392 Handle<Object> result;
2393 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2394 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2395 return *result;
2396}
2397
2398
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399// Used from ic-<arch>.cc.
2400RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
2401 TimerEventScope<TimerEventIcMiss> timer(isolate);
2402 HandleScope scope(isolate);
2403 DCHECK(args.length() == 3);
2404 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2405 Handle<Object> receiver = args.at<Object>(0);
2406 Handle<Object> key = args.at<Object>(1);
2407 ic.UpdateState(receiver, key);
2408 Handle<Object> result;
2409 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2410 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2411 return *result;
2412}
2413
2414
2415RUNTIME_FUNCTION(KeyedStoreIC_MissFromStubFailure) {
2416 TimerEventScope<TimerEventIcMiss> timer(isolate);
2417 HandleScope scope(isolate);
2418 DCHECK(args.length() == 3);
2419 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2420 Handle<Object> receiver = args.at<Object>(0);
2421 Handle<Object> key = args.at<Object>(1);
2422 ic.UpdateState(receiver, key);
2423 Handle<Object> result;
2424 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2425 isolate, result, ic.Store(receiver, key, args.at<Object>(2)));
2426 return *result;
2427}
2428
2429
2430RUNTIME_FUNCTION(StoreIC_Slow) {
2431 HandleScope scope(isolate);
2432 DCHECK(args.length() == 3);
2433 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2434 Handle<Object> object = args.at<Object>(0);
2435 Handle<Object> key = args.at<Object>(1);
2436 Handle<Object> value = args.at<Object>(2);
2437 StrictMode strict_mode = ic.strict_mode();
2438 Handle<Object> result;
2439 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2440 isolate, result,
2441 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
2442 return *result;
2443}
2444
2445
2446RUNTIME_FUNCTION(KeyedStoreIC_Slow) {
2447 HandleScope scope(isolate);
2448 DCHECK(args.length() == 3);
2449 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2450 Handle<Object> object = args.at<Object>(0);
2451 Handle<Object> key = args.at<Object>(1);
2452 Handle<Object> value = args.at<Object>(2);
2453 StrictMode strict_mode = ic.strict_mode();
2454 Handle<Object> result;
2455 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2456 isolate, result,
2457 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
2458 return *result;
2459}
2460
2461
2462RUNTIME_FUNCTION(ElementsTransitionAndStoreIC_Miss) {
2463 TimerEventScope<TimerEventIcMiss> timer(isolate);
2464 HandleScope scope(isolate);
2465 DCHECK(args.length() == 4);
2466 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2467 Handle<Object> value = args.at<Object>(0);
2468 Handle<Map> map = args.at<Map>(1);
2469 Handle<Object> key = args.at<Object>(2);
2470 Handle<Object> object = args.at<Object>(3);
2471 StrictMode strict_mode = ic.strict_mode();
2472 if (object->IsJSObject()) {
2473 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2474 map->elements_kind());
2475 }
2476 Handle<Object> result;
2477 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2478 isolate, result,
2479 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
2480 return *result;
2481}
2482
2483
2484MaybeHandle<Object> BinaryOpIC::Transition(
2485 Handle<AllocationSite> allocation_site, Handle<Object> left,
2486 Handle<Object> right) {
2487 BinaryOpICState state(isolate(), target()->extra_ic_state());
2488
2489 // Compute the actual result using the builtin for the binary operation.
2490 Object* builtin = isolate()->js_builtins_object()->javascript_builtin(
2491 TokenToJSBuiltin(state.op()));
2492 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate());
2493 Handle<Object> result;
2494 ASSIGN_RETURN_ON_EXCEPTION(
2495 isolate(), result, Execution::Call(isolate(), function, left, 1, &right),
2496 Object);
2497
2498 // Execution::Call can execute arbitrary JavaScript, hence potentially
2499 // update the state of this very IC, so we must update the stored state.
2500 UpdateTarget();
2501 // Compute the new state.
2502 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2503 state.Update(left, right, result);
2504
2505 // Check if we have a string operation here.
2506 Handle<Code> target;
2507 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2508 // Setup the allocation site on-demand.
2509 if (allocation_site.is_null()) {
2510 allocation_site = isolate()->factory()->NewAllocationSite();
2511 }
2512
2513 // Install the stub with an allocation site.
2514 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2515 target = stub.GetCodeCopyFromTemplate(allocation_site);
2516
2517 // Sanity check the trampoline stub.
2518 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2519 } else {
2520 // Install the generic stub.
2521 BinaryOpICStub stub(isolate(), state);
2522 target = stub.GetCode();
2523
2524 // Sanity check the generic stub.
2525 DCHECK_EQ(NULL, target->FindFirstAllocationSite());
2526 }
2527 set_target(*target);
2528
2529 if (FLAG_trace_ic) {
2530 OFStream os(stdout);
2531 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2532 << static_cast<void*>(*target) << " <- ";
2533 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2534 if (!allocation_site.is_null()) {
2535 os << " using allocation site " << static_cast<void*>(*allocation_site);
2536 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002537 os << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002538 }
2539
2540 // Patch the inlined smi code as necessary.
2541 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2542 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2543 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2544 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2545 }
2546
2547 return result;
2548}
2549
2550
2551RUNTIME_FUNCTION(BinaryOpIC_Miss) {
2552 TimerEventScope<TimerEventIcMiss> timer(isolate);
2553 HandleScope scope(isolate);
2554 DCHECK_EQ(2, args.length());
2555 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2556 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2557 BinaryOpIC ic(isolate);
2558 Handle<Object> result;
2559 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2560 isolate, result,
2561 ic.Transition(Handle<AllocationSite>::null(), left, right));
2562 return *result;
2563}
2564
2565
2566RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) {
2567 TimerEventScope<TimerEventIcMiss> timer(isolate);
2568 HandleScope scope(isolate);
2569 DCHECK_EQ(3, args.length());
2570 Handle<AllocationSite> allocation_site =
2571 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2572 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2573 Handle<Object> right =
2574 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2575 BinaryOpIC ic(isolate);
2576 Handle<Object> result;
2577 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2578 isolate, result, ic.Transition(allocation_site, left, right));
2579 return *result;
2580}
2581
2582
2583Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2584 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2585 CompareICState::UNINITIALIZED,
2586 CompareICState::UNINITIALIZED);
2587 Code* code = NULL;
2588 CHECK(stub.FindCodeInCache(&code));
2589 return code;
2590}
2591
2592
2593Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2594 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2595 CompareICState::UNINITIALIZED,
2596 CompareICState::UNINITIALIZED);
2597 return stub.GetCode();
2598}
2599
2600
2601Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2602 HandleScope scope(isolate());
2603 CompareICStub old_stub(target()->stub_key(), isolate());
2604 CompareICState::State new_left =
2605 CompareICState::NewInputState(old_stub.left(), x);
2606 CompareICState::State new_right =
2607 CompareICState::NewInputState(old_stub.right(), y);
2608 CompareICState::State state = CompareICState::TargetState(
2609 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2610 HasInlinedSmiCode(address()), x, y);
2611 CompareICStub stub(isolate(), op_, new_left, new_right, state);
2612 if (state == CompareICState::KNOWN_OBJECT) {
2613 stub.set_known_map(
2614 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
2615 }
2616 Handle<Code> new_target = stub.GetCode();
2617 set_target(*new_target);
2618
2619 if (FLAG_trace_ic) {
2620 PrintF("[CompareIC in ");
2621 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2622 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2623 CompareICState::GetStateName(old_stub.left()),
2624 CompareICState::GetStateName(old_stub.right()),
2625 CompareICState::GetStateName(old_stub.state()),
2626 CompareICState::GetStateName(new_left),
2627 CompareICState::GetStateName(new_right),
2628 CompareICState::GetStateName(state), Token::Name(op_),
2629 static_cast<void*>(*stub.GetCode()));
2630 }
2631
2632 // Activate inlined smi code.
2633 if (old_stub.state() == CompareICState::UNINITIALIZED) {
2634 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2635 }
2636
2637 return *new_target;
2638}
2639
2640
2641// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2642RUNTIME_FUNCTION(CompareIC_Miss) {
2643 TimerEventScope<TimerEventIcMiss> timer(isolate);
2644 HandleScope scope(isolate);
2645 DCHECK(args.length() == 3);
2646 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2647 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2648}
2649
2650
2651void CompareNilIC::Clear(Address address, Code* target,
2652 ConstantPoolArray* constant_pool) {
2653 if (IsCleared(target)) return;
2654 ExtraICState state = target->extra_ic_state();
2655
2656 CompareNilICStub stub(target->GetIsolate(), state,
2657 HydrogenCodeStub::UNINITIALIZED);
2658 stub.ClearState();
2659
2660 Code* code = NULL;
2661 CHECK(stub.FindCodeInCache(&code));
2662
2663 SetTargetAtAddress(address, code, constant_pool);
2664}
2665
2666
2667Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2668 Handle<Object> object) {
2669 if (object->IsNull() || object->IsUndefined()) {
2670 return handle(Smi::FromInt(true), isolate);
2671 }
2672 return handle(Smi::FromInt(object->IsUndetectableObject()), isolate);
2673}
2674
2675
2676Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2677 ExtraICState extra_ic_state = target()->extra_ic_state();
2678
2679 CompareNilICStub stub(isolate(), extra_ic_state);
2680
2681 // Extract the current supported types from the patched IC and calculate what
2682 // types must be supported as a result of the miss.
2683 bool already_monomorphic = stub.IsMonomorphic();
2684
2685 stub.UpdateStatus(object);
2686
2687 NilValue nil = stub.nil_value();
2688
2689 // Find or create the specialized stub to support the new set of types.
2690 Handle<Code> code;
2691 if (stub.IsMonomorphic()) {
2692 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2693 ? FirstTargetMap()
2694 : HeapObject::cast(*object)->map());
2695 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2696 } else {
2697 code = stub.GetCode();
2698 }
2699 set_target(*code);
2700 return DoCompareNilSlow(isolate(), nil, object);
2701}
2702
2703
2704RUNTIME_FUNCTION(CompareNilIC_Miss) {
2705 TimerEventScope<TimerEventIcMiss> timer(isolate);
2706 HandleScope scope(isolate);
2707 Handle<Object> object = args.at<Object>(0);
2708 CompareNilIC ic(isolate);
2709 return *ic.CompareNil(object);
2710}
2711
2712
2713RUNTIME_FUNCTION(Unreachable) {
2714 UNREACHABLE();
2715 CHECK(false);
2716 return isolate->heap()->undefined_value();
2717}
2718
2719
2720Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2721 switch (op) {
2722 default:
2723 UNREACHABLE();
2724 case Token::ADD:
2725 return Builtins::ADD;
2726 break;
2727 case Token::SUB:
2728 return Builtins::SUB;
2729 break;
2730 case Token::MUL:
2731 return Builtins::MUL;
2732 break;
2733 case Token::DIV:
2734 return Builtins::DIV;
2735 break;
2736 case Token::MOD:
2737 return Builtins::MOD;
2738 break;
2739 case Token::BIT_OR:
2740 return Builtins::BIT_OR;
2741 break;
2742 case Token::BIT_AND:
2743 return Builtins::BIT_AND;
2744 break;
2745 case Token::BIT_XOR:
2746 return Builtins::BIT_XOR;
2747 break;
2748 case Token::SAR:
2749 return Builtins::SAR;
2750 break;
2751 case Token::SHR:
2752 return Builtins::SHR;
2753 break;
2754 case Token::SHL:
2755 return Builtins::SHL;
2756 break;
2757 }
2758}
2759
2760
2761Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2762 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2763 bool to_boolean_value = stub.UpdateStatus(object);
2764 Handle<Code> code = stub.GetCode();
2765 set_target(*code);
2766 return handle(Smi::FromInt(to_boolean_value ? 1 : 0), isolate());
2767}
2768
2769
2770RUNTIME_FUNCTION(ToBooleanIC_Miss) {
2771 TimerEventScope<TimerEventIcMiss> timer(isolate);
2772 DCHECK(args.length() == 1);
2773 HandleScope scope(isolate);
2774 Handle<Object> object = args.at<Object>(0);
2775 ToBooleanIC ic(isolate);
2776 return *ic.ToBoolean(object);
2777}
2778
2779
2780RUNTIME_FUNCTION(StoreCallbackProperty) {
2781 Handle<JSObject> receiver = args.at<JSObject>(0);
2782 Handle<JSObject> holder = args.at<JSObject>(1);
2783 Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2);
2784 Handle<Name> name = args.at<Name>(3);
2785 Handle<Object> value = args.at<Object>(4);
2786 HandleScope scope(isolate);
2787
2788 DCHECK(callback->IsCompatibleReceiver(*receiver));
2789
2790 Address setter_address = v8::ToCData<Address>(callback->setter());
2791 v8::AccessorNameSetterCallback fun =
2792 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2793 DCHECK(fun != NULL);
2794
2795 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2796 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2797 *holder);
2798 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2799 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2800 return *value;
2801}
2802
2803
2804/**
2805 * Attempts to load a property with an interceptor (which must be present),
2806 * but doesn't search the prototype chain.
2807 *
2808 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2809 * provide any value for the given name.
2810 */
2811RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
2812 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002813 Handle<Name> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002814 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2815 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(
2816 NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex);
2817
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002818 if (name->IsSymbol() && !interceptor_info->can_intercept_symbols())
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002819 return isolate->heap()->no_interceptor_result_sentinel();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002820
2821 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002822 v8::GenericNamedPropertyGetterCallback getter =
2823 FUNCTION_CAST<v8::GenericNamedPropertyGetterCallback>(getter_address);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002824 DCHECK(getter != NULL);
2825
2826 Handle<JSObject> receiver =
2827 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2828 Handle<JSObject> holder =
2829 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2830 PropertyCallbackArguments callback_args(isolate, interceptor_info->data(),
2831 *receiver, *holder);
2832 {
2833 // Use the interceptor getter.
2834 HandleScope scope(isolate);
2835 v8::Handle<v8::Value> r =
2836 callback_args.Call(getter, v8::Utils::ToLocal(name));
2837 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2838 if (!r.IsEmpty()) {
2839 Handle<Object> result = v8::Utils::OpenHandle(*r);
2840 result->VerifyApiCallResultType();
2841 return *v8::Utils::OpenHandle(*r);
2842 }
2843 }
2844
2845 return isolate->heap()->no_interceptor_result_sentinel();
2846}
2847
2848
2849static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
2850 // If the load is non-contextual, just return the undefined result.
2851 // Note that both keyed and non-keyed loads may end up here.
2852 HandleScope scope(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002853 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002854 if (ic.contextual_mode() != CONTEXTUAL) {
2855 return isolate->heap()->undefined_value();
2856 }
2857
2858 // Throw a reference error.
2859 Handle<Name> name_handle(name);
2860 THROW_NEW_ERROR_RETURN_FAILURE(
2861 isolate, NewReferenceError("not_defined", HandleVector(&name_handle, 1)));
2862}
2863
2864
2865/**
2866 * Loads a property with an interceptor performing post interceptor
2867 * lookup if interceptor failed.
2868 */
2869RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
2870 HandleScope scope(isolate);
2871 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2872 Handle<Name> name =
2873 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2874 Handle<JSObject> receiver =
2875 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2876 Handle<JSObject> holder =
2877 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2878
2879 Handle<Object> result;
2880 LookupIterator it(receiver, name, holder);
2881 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2882 JSObject::GetProperty(&it));
2883
2884 if (it.IsFound()) return *result;
2885
2886 return ThrowReferenceError(isolate, Name::cast(args[0]));
2887}
2888
2889
2890RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
2891 HandleScope scope(isolate);
2892 DCHECK(args.length() == 3);
2893 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2894 Handle<JSObject> receiver = args.at<JSObject>(0);
2895 Handle<Name> name = args.at<Name>(1);
2896 Handle<Object> value = args.at<Object>(2);
2897#ifdef DEBUG
2898 PrototypeIterator iter(isolate, receiver,
2899 PrototypeIterator::START_AT_RECEIVER);
2900 bool found = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002901 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002902 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2903 if (current->IsJSObject() &&
2904 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2905 found = true;
2906 break;
2907 }
2908 }
2909 DCHECK(found);
2910#endif
2911 Handle<Object> result;
2912 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2913 isolate, result,
2914 JSObject::SetProperty(receiver, name, value, ic.strict_mode()));
2915 return *result;
2916}
2917
2918
2919RUNTIME_FUNCTION(LoadElementWithInterceptor) {
2920 HandleScope scope(isolate);
2921 Handle<JSObject> receiver = args.at<JSObject>(0);
2922 DCHECK(args.smi_at(1) >= 0);
2923 uint32_t index = args.smi_at(1);
2924 Handle<Object> result;
2925 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2926 isolate, result,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002927 JSObject::GetElementWithInterceptor(receiver, receiver, index, true));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002928 return *result;
2929}
2930
2931
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002932RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
2933 TimerEventScope<TimerEventIcMiss> timer(isolate);
2934 HandleScope scope(isolate);
2935 Handle<Object> receiver = args.at<Object>(0);
2936 Handle<Name> key = args.at<Name>(1);
2937 Handle<Object> result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002938
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002939 if (FLAG_vector_ics) {
2940 DCHECK(args.length() == 4);
2941 Handle<Smi> slot = args.at<Smi>(2);
2942 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2943 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
2944 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2945 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2946 // set up outside the IC, handle that here.
2947 if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
2948 LoadICNexus nexus(vector, vector_slot);
2949 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2950 ic.UpdateState(receiver, key);
2951 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2952 ic.Load(receiver, key));
2953 } else {
2954 DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
2955 KeyedLoadICNexus nexus(vector, vector_slot);
2956 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2957 ic.UpdateState(receiver, key);
2958 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2959 ic.Load(receiver, key));
2960 }
2961 } else {
2962 DCHECK(args.length() == 2);
2963 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
2964 ic.UpdateState(receiver, key);
2965 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2966 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002967
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002968 return *result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002969}
2970
2971
2972static const Address IC_utilities[] = {
2973#define ADDR(name) FUNCTION_ADDR(name),
2974 IC_UTIL_LIST(ADDR) NULL
2975#undef ADDR
2976};
2977
2978
2979Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; }
2980}
2981} // namespace v8::internal