blob: c5835e4f54e666f059523371bb688b354a0f1bcd [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/ic/ic.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
7#include "src/accessors.h"
8#include "src/api.h"
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/api-arguments.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/arguments.h"
11#include "src/base/bits.h"
Ben Murdochda12d292016-06-02 14:46:10 +010012#include "src/code-factory.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/codegen.h"
14#include "src/conversions.h"
15#include "src/execution.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010016#include "src/field-type.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/frames-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/ic/call-optimization.h"
19#include "src/ic/handler-compiler.h"
20#include "src/ic/ic-inl.h"
21#include "src/ic/ic-compiler.h"
22#include "src/ic/stub-cache.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023#include "src/isolate-inl.h"
24#include "src/macro-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025#include "src/prototype.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040026#include "src/runtime/runtime.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010027#include "src/runtime/runtime-utils.h"
28#include "src/tracing/trace-event.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029
30namespace v8 {
31namespace internal {
32
33char IC::TransitionMarkFromState(IC::State state) {
34 switch (state) {
35 case UNINITIALIZED:
36 return '0';
37 case PREMONOMORPHIC:
38 return '.';
39 case MONOMORPHIC:
40 return '1';
41 case PROTOTYPE_FAILURE:
42 return '^';
43 case POLYMORPHIC:
44 return 'P';
45 case MEGAMORPHIC:
46 return 'N';
47 case GENERIC:
48 return 'G';
49
50 // We never see the debugger states here, because the state is
51 // computed from the original code - not the patched code. Let
52 // these cases fall through to the unreachable code below.
53 case DEBUG_STUB:
54 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 }
56 UNREACHABLE();
57 return 0;
58}
59
60
61const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
62 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
63 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
64 return ".IGNORE_OOB";
65 }
66 if (IsGrowStoreMode(mode)) return ".GROW";
67 return "";
68}
69
70
71#ifdef DEBUG
72
73#define TRACE_GENERIC_IC(isolate, type, reason) \
74 do { \
75 if (FLAG_trace_ic) { \
76 PrintF("[%s patching generic stub in ", type); \
77 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
78 PrintF(" (%s)]\n", reason); \
79 } \
80 } while (false)
81
82#else
83
84#define TRACE_GENERIC_IC(isolate, type, reason) \
85 do { \
86 if (FLAG_trace_ic) { \
87 PrintF("[%s patching generic stub in ", type); \
88 PrintF("(see below) (%s)]\n", reason); \
89 } \
90 } while (false)
91
92#endif // DEBUG
93
94
95void IC::TraceIC(const char* type, Handle<Object> name) {
96 if (FLAG_trace_ic) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 if (AddressIsDeoptimizedCode()) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 State new_state =
99 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 TraceIC(type, name, state(), new_state);
101 }
102}
103
104
105void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
106 State new_state) {
107 if (FLAG_trace_ic) {
108 Code* new_target = raw_target();
109 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
110
111 // TODO(jkummerow): Add support for "apply". The logic is roughly:
112 // marker = [fp_ + kMarkerOffset];
113 // if marker is smi and marker.value == INTERNAL and
114 // the frame's code == builtin(Builtins::kFunctionApply):
115 // then print "apply from" and advance one frame
116
117 Object* maybe_function =
118 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
119 if (maybe_function->IsJSFunction()) {
120 JSFunction* function = JSFunction::cast(maybe_function);
121 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
122 stdout, true);
123 }
124
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 const char* modifier = "";
126 if (new_target->kind() == Code::KEYED_STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 KeyedAccessStoreMode mode =
128 casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
129 modifier = GetTransitionMarkModifier(mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 TransitionMarkFromState(new_state), modifier);
133#ifdef OBJECT_PRINT
134 OFStream os(stdout);
135 name->Print(os);
136#else
137 name->ShortPrint(stdout);
138#endif
139 PrintF("]\n");
140 }
141}
142
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400144#define TRACE_IC(type, name) TraceIC(type, name)
145
146
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 : isolate_(isolate),
149 target_set_(false),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 vector_set_(false),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400151 target_maps_set_(false),
152 nexus_(nexus) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 // To improve the performance of the (much used) IC code, we unfold a few
154 // levels of the stack frame iteration code. This yields a ~35% speedup when
155 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
156 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 Address* constant_pool = NULL;
158 if (FLAG_enable_embedded_constant_pool) {
159 constant_pool = reinterpret_cast<Address*>(
160 entry + ExitFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 }
162 Address* pc_address =
163 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
164 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
165 // If there's another JavaScript frame on the stack or a
166 // StubFailureTrampoline, we need to look one frame further down the stack to
167 // find the frame pointer and the return address stack slot.
168 if (depth == EXTRA_CALL_FRAME) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169 if (FLAG_enable_embedded_constant_pool) {
170 constant_pool = reinterpret_cast<Address*>(
171 fp + StandardFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 }
173 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
174 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
175 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
176 }
177#ifdef DEBUG
178 StackFrameIterator it(isolate);
179 for (int i = 0; i < depth + 1; i++) it.Advance();
180 StackFrame* frame = it.frame();
181 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
182#endif
183 fp_ = fp;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 if (FLAG_enable_embedded_constant_pool) {
185 constant_pool_address_ = constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 }
187 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
188 target_ = handle(raw_target(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 kind_ = target_->kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 state_ = UseVector() ? nexus->StateFromFeedback() : target_->ic_state();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 old_state_ = state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 extra_ic_state_ = target_->extra_ic_state();
193}
194
195
196SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
197 // Compute the JavaScript frame for the frame pointer of this IC
198 // structure. We need this to be able to find the function
199 // corresponding to the frame.
200 StackFrameIterator it(isolate());
201 while (it.frame()->fp() != this->fp()) it.Advance();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 if (FLAG_ignition && it.frame()->type() == StackFrame::STUB) {
203 // Advance over bytecode handler frame.
204 // TODO(rmcilroy): Remove this once bytecode handlers don't need a frame.
205 it.Advance();
206 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
208 // Find the function on the stack and both the active code for the
209 // function and the original code.
210 JSFunction* function = frame->function();
211 return function->shared();
212}
213
214
215Code* IC::GetCode() const {
216 HandleScope scope(isolate());
217 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
218 Code* code = shared->code();
219 return code;
220}
221
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223bool IC::AddressIsOptimizedCode() const {
224 Code* host =
225 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
226 return host->kind() == Code::OPTIMIZED_FUNCTION;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227}
228
229
230static void LookupForRead(LookupIterator* it) {
231 for (; it->IsFound(); it->Next()) {
232 switch (it->state()) {
233 case LookupIterator::NOT_FOUND:
234 case LookupIterator::TRANSITION:
235 UNREACHABLE();
236 case LookupIterator::JSPROXY:
237 return;
238 case LookupIterator::INTERCEPTOR: {
239 // If there is a getter, return; otherwise loop to perform the lookup.
240 Handle<JSObject> holder = it->GetHolder<JSObject>();
241 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
242 return;
243 }
244 break;
245 }
246 case LookupIterator::ACCESS_CHECK:
247 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
248 // access checks for global proxies.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 break;
251 }
252 return;
253 case LookupIterator::ACCESSOR:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 case LookupIterator::DATA:
256 return;
257 }
258 }
259}
260
261
262bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
263 Handle<String> name) {
264 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400265 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400267 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400269 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000270
271 // The current map wasn't handled yet. There's no reason to stay monomorphic,
272 // *unless* we're moving from a deprecated map to its replacement, or
273 // to a more general elements kind.
274 // TODO(verwaest): Check if the current map is actually what the old map
275 // would transition to.
276 if (maybe_handler_.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 if (!receiver_map()->IsJSObjectMap()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 Map* first_map = FirstTargetMap();
279 if (first_map == NULL) return false;
280 Handle<Map> old_map(first_map);
281 if (old_map->is_deprecated()) return true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
283 receiver_map()->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 }
285
286 CacheHolderFlag flag;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 if (receiver->IsJSGlobalObject()) {
301 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
303 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
304 if (!it.IsFound()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 return it.property_details().cell_type() == PropertyCellType::kConstant;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 }
307
308 return true;
309}
310
311
312bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
313 if (target()->is_keyed_stub()) {
314 // Determine whether the failure is due to a name failure.
315 if (!name->IsName()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400316 Name* stub_name =
317 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 if (*name != stub_name) return false;
319 }
320
321 return true;
322}
323
324
325void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 if (!name->IsString()) return;
328 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
329 if (receiver->IsUndefined() || receiver->IsNull()) return;
330
331 // Remove the target from the code cache if it became invalid
332 // because of changes in the prototype chain to avoid hitting it
333 // again.
334 if (TryRemoveInvalidPrototypeDependentStub(receiver,
335 Handle<String>::cast(name))) {
336 MarkPrototypeFailure(name);
337 return;
338 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339}
340
341
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
343 Handle<Object> object, Handle<Object> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346}
347
348
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 THROW_NEW_ERROR(
352 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353}
354
355
356static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
357 int* polymorphic_delta,
358 int* generic_delta) {
359 switch (old_state) {
360 case UNINITIALIZED:
361 case PREMONOMORPHIC:
362 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
363 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
364 *polymorphic_delta = 1;
365 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
366 *generic_delta = 1;
367 }
368 break;
369 case MONOMORPHIC:
370 case POLYMORPHIC:
371 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
372 *polymorphic_delta = -1;
373 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
374 *generic_delta = 1;
375 }
376 break;
377 case MEGAMORPHIC:
378 case GENERIC:
379 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
380 *generic_delta = -1;
381 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
382 *polymorphic_delta = 1;
383 }
384 break;
385 case PROTOTYPE_FAILURE:
386 case DEBUG_STUB:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 UNREACHABLE();
388 }
389}
390
391
392void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
393 State old_state, State new_state,
394 bool target_remains_ic_stub) {
395 Code* host =
396 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
397 if (host->kind() != Code::FUNCTION) return;
398
399 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
400 // Not all Code objects have TypeFeedbackInfo.
401 host->type_feedback_info()->IsTypeFeedbackInfo()) {
402 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
403 int generic_delta = 0; // "Generic" here includes megamorphic.
404 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
405 &generic_delta);
406 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
407 info->change_ic_with_type_info_count(polymorphic_delta);
408 info->change_ic_generic_count(generic_delta);
409 }
410 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
411 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
412 info->change_own_type_change_checksum();
413 }
414 host->set_profiler_ticks(0);
415 isolate->runtime_profiler()->NotifyICChanged();
416 // TODO(2029): When an optimized function is patched, it would
417 // be nice to propagate the corresponding type information to its
418 // unoptimized version for the benefit of later inlining.
419}
420
421
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400424 if (host->kind() != Code::FUNCTION) return;
425
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
427 info->change_own_type_change_checksum();
428 host->set_profiler_ticks(0);
429 isolate->runtime_profiler()->NotifyICChanged();
430 // TODO(2029): When an optimized function is patched, it would
431 // be nice to propagate the corresponding type information to its
432 // unoptimized version for the benefit of later inlining.
433}
434
435
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436void IC::PostPatching(Address address, Code* target, Code* old_target) {
437 // Type vector based ICs update these statistics at a different time because
438 // they don't always patch on state change.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400439 if (ICUseVector(target->kind())) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440
441 Isolate* isolate = target->GetHeap()->isolate();
442 State old_state = UNINITIALIZED;
443 State new_state = UNINITIALIZED;
444 bool target_remains_ic_stub = false;
445 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
446 old_state = old_target->ic_state();
447 new_state = target->ic_state();
448 target_remains_ic_stub = true;
449 }
450
451 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
452 target_remains_ic_stub);
453}
454
455
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 Code* target = GetTargetAtAddress(address, constant_pool);
458
459 // Don't clear debug break inline cache as it will remove the break point.
460 if (target->is_debug_stub()) return;
461
462 switch (target->kind()) {
463 case Code::LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 case Code::KEYED_LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 case Code::STORE_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 case Code::KEYED_STORE_IC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 case Code::COMPARE_IC:
469 return CompareIC::Clear(isolate, address, target, constant_pool);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400470 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 case Code::BINARY_OP_IC:
472 case Code::TO_BOOLEAN_IC:
473 // Clearing these is tricky and does not
474 // make any performance difference.
475 return;
476 default:
477 UNREACHABLE();
478 }
479}
480
481
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400482void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
483 if (IsCleared(nexus)) return;
484 // Make sure to also clear the map used in inline fast cases. If we
485 // do not clear these maps, cached code can keep objects alive
486 // through the embedded maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400487 nexus->ConfigurePremonomorphic();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400489}
490
491
492void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
493 // Determine our state.
494 Object* feedback = nexus->vector()->Get(nexus->slot());
495 State state = nexus->StateFromFeedback();
496
497 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
498 nexus->ConfigureUninitialized();
499 // The change in state must be processed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400501 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502}
503
504
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400505void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
506 if (IsCleared(nexus)) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400507 nexus->ConfigurePremonomorphic();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000508 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400509}
510
511
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 if (IsCleared(target)) return;
515 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
516 target->extra_ic_state());
517 SetTargetAtAddress(address, code, constant_pool);
518}
519
520
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
522 if (IsCleared(nexus)) return;
523 nexus->ConfigurePremonomorphic();
524 OnTypeFeedbackChanged(isolate, host);
525}
526
527
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000530 if (IsCleared(target)) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000531 Handle<Code> code = pre_monomorphic_stub(
532 isolate, StoreICState::GetLanguageMode(target->extra_ic_state()));
533 SetTargetAtAddress(address, *code, constant_pool);
534}
535
536
537void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
538 KeyedStoreICNexus* nexus) {
539 if (IsCleared(nexus)) return;
540 nexus->ConfigurePremonomorphic();
541 OnTypeFeedbackChanged(isolate, host);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542}
543
544
545void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
548 CompareICStub stub(target->stub_key(), isolate);
549 // Only clear CompareICs that can retain objects.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550 if (stub.state() != CompareICState::KNOWN_RECEIVER) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100551 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 constant_pool);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554}
555
556
557// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000558Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate,
559 ExtraICState extra_state) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 if (FLAG_compiled_keyed_generic_loads) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 return isolate->builtins()->KeyedLoadIC_Megamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564 }
565}
566
567
568static bool MigrateDeprecated(Handle<Object> object) {
569 if (!object->IsJSObject()) return false;
570 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
571 if (!receiver->map()->is_deprecated()) return false;
572 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
573 return true;
574}
575
Ben Murdoch097c5b22016-05-18 11:27:45 +0100576void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577 DCHECK(UseVector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578 if (new_state == PREMONOMORPHIC) {
579 nexus()->ConfigurePremonomorphic();
580 } else if (new_state == MEGAMORPHIC) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100581 if (kind() == Code::LOAD_IC || kind() == Code::STORE_IC) {
582 nexus()->ConfigureMegamorphic();
583 } else if (kind() == Code::KEYED_LOAD_IC) {
584 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
585 nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
586 } else {
587 DCHECK(kind() == Code::KEYED_STORE_IC);
588 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
589 nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
590 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400591 } else {
592 UNREACHABLE();
593 }
594
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000595 vector_set_ = true;
596 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400597}
598
599
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400601 Handle<Code> handler) {
602 DCHECK(UseVector());
603 if (kind() == Code::LOAD_IC) {
604 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 nexus->ConfigureMonomorphic(map, handler);
606 } else if (kind() == Code::KEYED_LOAD_IC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400607 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 nexus->ConfigureMonomorphic(name, map, handler);
609 } else if (kind() == Code::STORE_IC) {
610 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
611 nexus->ConfigureMonomorphic(map, handler);
612 } else {
613 DCHECK(kind() == Code::KEYED_STORE_IC);
614 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
615 nexus->ConfigureMonomorphic(name, map, handler);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400616 }
617
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618 vector_set_ = true;
619 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400620}
621
622
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400624 CodeHandleList* handlers) {
625 DCHECK(UseVector());
626 if (kind() == Code::LOAD_IC) {
627 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628 nexus->ConfigurePolymorphic(maps, handlers);
629 } else if (kind() == Code::KEYED_LOAD_IC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400630 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 nexus->ConfigurePolymorphic(name, maps, handlers);
632 } else if (kind() == Code::STORE_IC) {
633 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
634 nexus->ConfigurePolymorphic(maps, handlers);
635 } else {
636 DCHECK(kind() == Code::KEYED_STORE_IC);
637 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
638 nexus->ConfigurePolymorphic(name, maps, handlers);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400639 }
640
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641 vector_set_ = true;
642 OnTypeFeedbackChanged(isolate(), get_host());
643}
644
645
646void IC::ConfigureVectorState(MapHandleList* maps,
647 MapHandleList* transitioned_maps,
648 CodeHandleList* handlers) {
649 DCHECK(UseVector());
650 DCHECK(kind() == Code::KEYED_STORE_IC);
651 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
652 nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
653
654 vector_set_ = true;
655 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400656}
657
658
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000659MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
660 // If the object is undefined or null it's illegal to try to get any
661 // of its properties; throw a TypeError in that case.
662 if (object->IsUndefined() || object->IsNull()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664 }
665
666 // Check if the name is trivially convertible to an index and get
667 // the element or char if so.
668 uint32_t index;
669 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
670 // Rewrite to the generic keyed load stub.
671 if (FLAG_use_ic) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 DCHECK(UseVector());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100673 ConfigureVectorState(MEGAMORPHIC, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 TRACE_IC("LoadIC", name);
675 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
676 }
677 Handle<Object> result;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100678 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
679 Object::GetElement(isolate(), object, index),
680 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 return result;
682 }
683
684 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
685
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 if (object->IsJSGlobalObject() && name->IsString()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400687 // Look up in script context table.
688 Handle<String> str_name = Handle<String>::cast(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400690 Handle<ScriptContextTable> script_contexts(
691 global->native_context()->script_context_table());
692
693 ScriptContextTable::LookupResult lookup_result;
694 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 Handle<Object> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100696 FixedArray::get(*ScriptContextTable::GetContext(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000697 script_contexts, lookup_result.context_index),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100698 lookup_result.slot_index, isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 if (*result == *isolate()->factory()->the_hole_value()) {
700 // Do not install stubs and stay pre-monomorphic for
701 // uninitialized accesses.
702 return ReferenceError(name);
703 }
704
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400705 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
706 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
707 PatchCache(name, stub.GetCode());
708 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 return result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400710 }
711 }
712
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 // Named lookup in the object.
714 LookupIterator it(object, name);
715 LookupForRead(&it);
716
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717 if (it.IsFound() || !ShouldThrowReferenceError(object)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 // Update inline cache and stub cache.
719 if (use_ic) UpdateCaches(&it);
720
721 // Get the property.
722 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723
Ben Murdoch097c5b22016-05-18 11:27:45 +0100724 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
725 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726 if (it.IsFound()) {
727 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 } else if (!ShouldThrowReferenceError(object)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729 LOG(isolate(), SuspectReadEvent(*name, *object));
730 return result;
731 }
732 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733 return ReferenceError(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734}
735
736
737static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
738 Handle<Map> new_receiver_map) {
739 DCHECK(!new_receiver_map.is_null());
740 for (int current = 0; current < receiver_maps->length(); ++current) {
741 if (!receiver_maps->at(current).is_null() &&
742 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
743 return false;
744 }
745 }
746 receiver_maps->Add(new_receiver_map);
747 return true;
748}
749
750
751bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
752 if (!code->is_handler()) return false;
753 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 Handle<Map> map = receiver_map();
755 MapHandleList maps;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 CodeHandleList handlers;
757
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758 TargetMaps(&maps);
759 int number_of_maps = maps.length();
760 int deprecated_maps = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 int handler_to_overwrite = -1;
762
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763 for (int i = 0; i < number_of_maps; i++) {
764 Handle<Map> current_map = maps.at(i);
765 if (current_map->is_deprecated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000766 // Filter out deprecated maps to ensure their instances get migrated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000767 ++deprecated_maps;
768 } else if (map.is_identical_to(current_map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000769 // If the receiver type is already in the polymorphic IC, this indicates
770 // there was a prototoype chain failure. In that case, just overwrite the
771 // handler.
772 handler_to_overwrite = i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773 } else if (handler_to_overwrite == -1 &&
774 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000775 handler_to_overwrite = i;
776 }
777 }
778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 int number_of_valid_maps =
780 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 if (number_of_valid_maps >= 4) return false;
783 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400784 return false;
785 }
786 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000787 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400788 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 if (!target()->FindHandlers(&handlers, maps.length())) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400790 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000791
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792 number_of_valid_maps++;
793 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 Handle<Code> ic;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795 if (number_of_valid_maps == 1) {
796 ConfigureVectorState(name, receiver_map(), code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000797 } else {
798 if (handler_to_overwrite >= 0) {
799 handlers.Set(handler_to_overwrite, code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
801 maps.Set(handler_to_overwrite, map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802 }
803 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 maps.Add(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000805 handlers.Add(code);
806 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400807
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000808 ConfigureVectorState(name, &maps, &handlers);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000809 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400810
811 if (!UseVector()) set_target(*ic);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812 return true;
813}
814
815
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
817 DCHECK(handler->is_handler());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 ConfigureVectorState(name, receiver_map(), handler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819}
820
821
822void IC::CopyICToMegamorphicCache(Handle<Name> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 MapHandleList maps;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000824 CodeHandleList handlers;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 TargetMaps(&maps);
826 if (!target()->FindHandlers(&handlers, maps.length())) return;
827 for (int i = 0; i < maps.length(); i++) {
828 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 }
830}
831
832
833bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
834 if (source_map == NULL) return true;
835 if (target_map == NULL) return false;
836 ElementsKind target_elements_kind = target_map->elements_kind();
837 bool more_general_transition = IsMoreGeneralElementsKindTransition(
838 source_map->elements_kind(), target_elements_kind);
839 Map* transitioned_map =
840 more_general_transition
841 ? source_map->LookupElementsTransitionMap(target_elements_kind)
842 : NULL;
843
844 return transitioned_map == target_map;
845}
846
847
848void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
849 switch (state()) {
850 case UNINITIALIZED:
851 case PREMONOMORPHIC:
852 UpdateMonomorphicIC(code, name);
853 break;
854 case PROTOTYPE_FAILURE:
855 case MONOMORPHIC:
856 case POLYMORPHIC:
857 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
858 if (UpdatePolymorphicIC(name, code)) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400859 // For keyed stubs, we can't know whether old handlers were for the
860 // same key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 CopyICToMegamorphicCache(name);
862 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400863 if (UseVector()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100864 ConfigureVectorState(MEGAMORPHIC, name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400865 } else {
866 set_target(*megamorphic_stub());
867 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000868 // Fall through.
869 case MEGAMORPHIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 UpdateMegamorphicCache(*receiver_map(), *name, *code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400871 // Indicate that we've handled this case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000872 if (UseVector()) {
873 vector_set_ = true;
874 } else {
875 target_set_ = true;
876 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 break;
878 case DEBUG_STUB:
879 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400880 case GENERIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400882 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 }
884}
885
886
887Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
888 ExtraICState extra_state) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000889 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000890}
891
892
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400893Handle<Code> LoadIC::initialize_stub_in_optimized_code(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 Isolate* isolate, ExtraICState extra_state, State initialization_state) {
895 return LoadICStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400896}
897
898
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000899Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate,
900 ExtraICState extra_state) {
901 return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400902}
903
904
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
906 Isolate* isolate, State initialization_state, ExtraICState extra_state) {
907 if (initialization_state != MEGAMORPHIC) {
908 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400909 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100910 return isolate->builtins()->KeyedLoadIC_Megamorphic();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911}
912
913
914static Handle<Code> KeyedStoreICInitializeStubHelper(
915 Isolate* isolate, LanguageMode language_mode,
916 InlineCacheState initialization_state) {
917 switch (initialization_state) {
918 case UNINITIALIZED:
919 return is_strict(language_mode)
920 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
921 : isolate->builtins()->KeyedStoreIC_Initialize();
922 case PREMONOMORPHIC:
923 return is_strict(language_mode)
924 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
925 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
926 case MEGAMORPHIC:
927 return is_strict(language_mode)
928 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
929 : isolate->builtins()->KeyedStoreIC_Megamorphic();
930 default:
931 UNREACHABLE();
932 }
933 return Handle<Code>();
934}
935
936
937Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
938 LanguageMode language_mode,
939 State initialization_state) {
940 if (initialization_state != MEGAMORPHIC) {
941 VectorKeyedStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
942 return stub.GetCode();
943 }
944
945 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
946 initialization_state);
947}
948
949
950Handle<Code> KeyedStoreIC::initialize_stub_in_optimized_code(
951 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
952 if (initialization_state != MEGAMORPHIC) {
953 VectorKeyedStoreICStub stub(isolate, StoreICState(language_mode));
954 return stub.GetCode();
955 }
956
957 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
958 initialization_state);
959}
960
961
962Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
963 ExtraICState extra_state) {
964 LanguageMode mode = StoreICState::GetLanguageMode(extra_state);
965 return KeyedStoreICInitializeStubHelper(isolate, mode, MEGAMORPHIC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400966}
967
968
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969Handle<Code> LoadIC::megamorphic_stub() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000970 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
971 return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000972}
973
974
975Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
976 LoadFieldStub stub(isolate(), index);
977 return stub.GetCode();
978}
979
980
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000981bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
982 DCHECK(lookup->state() == LookupIterator::ACCESSOR);
983 Isolate* isolate = lookup->isolate();
984 Handle<Object> accessors = lookup->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100985 if (accessors->IsAccessorInfo()) {
986 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000987 if (info->getter() != NULL &&
Ben Murdoch097c5b22016-05-18 11:27:45 +0100988 !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989 return false;
990 }
991 } else if (accessors->IsAccessorPair()) {
992 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
993 isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100994 if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo())
995 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000996 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
997 Handle<Object> receiver = lookup->GetReceiver();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100998 if (holder->HasFastProperties()) {
999 if (getter->IsJSFunction()) {
1000 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1001 if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() &&
1002 is_sloppy(function->shared()->language_mode())) {
1003 // Calling sloppy non-builtins with a value as the receiver
1004 // requires boxing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001005 return false;
1006 }
1007 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001008 CallOptimization call_optimization(getter);
1009 if (call_optimization.is_simple_api_call() &&
1010 !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) {
1011 return false;
1012 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001013 }
1014 }
1015 return true;
1016}
1017
1018
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019void LoadIC::UpdateCaches(LookupIterator* lookup) {
1020 if (state() == UNINITIALIZED) {
1021 // This is the first time we execute this inline cache. Set the target to
1022 // the pre monomorphic stub to delay setting the monomorphic state.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001023 ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001024 TRACE_IC("LoadIC", lookup->name());
1025 return;
1026 }
1027
1028 Handle<Code> code;
1029 if (lookup->state() == LookupIterator::JSPROXY ||
1030 lookup->state() == LookupIterator::ACCESS_CHECK) {
1031 code = slow_stub();
1032 } else if (!lookup->IsFound()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001033 if (kind() == Code::LOAD_IC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001035 receiver_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1037 if (code.is_null()) code = slow_stub();
1038 } else {
1039 code = slow_stub();
1040 }
1041 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001042 if (lookup->state() == LookupIterator::ACCESSOR) {
1043 if (!IsCompatibleReceiver(lookup, receiver_map())) {
1044 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1045 code = slow_stub();
1046 }
1047 } else if (lookup->state() == LookupIterator::INTERCEPTOR) {
1048 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1049 // the original iterator will be used to fetch the value.
1050 LookupIterator it = *lookup;
1051 it.Next();
1052 LookupForRead(&it);
1053 if (it.state() == LookupIterator::ACCESSOR &&
1054 !IsCompatibleReceiver(&it, receiver_map())) {
1055 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1056 code = slow_stub();
1057 }
1058 }
1059 if (code.is_null()) code = ComputeHandler(lookup);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060 }
1061
1062 PatchCache(lookup->name(), code);
1063 TRACE_IC("LoadIC", lookup->name());
1064}
1065
1066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 isolate()->stub_cache()->Set(name, map, code);
1069}
1070
1071
1072Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1073 bool receiver_is_holder =
1074 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1075 CacheHolderFlag flag;
1076 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 receiver_map(), receiver_is_holder, isolate(), &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078
1079 Handle<Code> code = PropertyHandlerCompiler::Find(
1080 lookup->name(), stub_holder_map, kind(), flag,
1081 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1082 // Use the cached value if it exists, and if it is different from the
1083 // handler that just missed.
1084 if (!code.is_null()) {
1085 if (!maybe_handler_.is_null() &&
1086 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1087 return code;
1088 }
1089 if (maybe_handler_.is_null()) {
1090 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1091 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1092 // cache (which just missed) is different from the cached handler.
1093 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1094 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1095 Code* megamorphic_cached_code =
1096 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1097 if (megamorphic_cached_code != *code) return code;
1098 } else {
1099 return code;
1100 }
1101 }
1102 }
1103
1104 code = CompileHandler(lookup, value, flag);
1105 DCHECK(code->is_handler());
1106
1107 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1108 // code compiled for this map, otherwise it's already cached in the global
Ben Murdochda12d292016-06-02 14:46:10 +01001109 // code cache. We are also guarding against installing code with flags that
1110 // don't match the desired CacheHolderFlag computed above, which would lead to
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001111 // invalid lookups later.
1112 if (code->type() != Code::NORMAL &&
1113 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1114 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1115 }
1116
1117 return code;
1118}
1119
1120
1121Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1122 Handle<Object> unused,
1123 CacheHolderFlag cache_holder) {
1124 Handle<Object> receiver = lookup->GetReceiver();
1125 if (receiver->IsString() &&
1126 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1127 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1128 return SimpleFieldLoad(index);
1129 }
1130
1131 if (receiver->IsStringWrapper() &&
1132 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1133 StringLengthStub string_length_stub(isolate());
1134 return string_length_stub.GetCode();
1135 }
1136
1137 // Use specialized code for getting prototype of functions.
1138 if (receiver->IsJSFunction() &&
1139 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140 receiver->IsConstructor() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141 !Handle<JSFunction>::cast(receiver)
1142 ->map()
1143 ->has_non_instance_prototype()) {
1144 Handle<Code> stub;
1145 FunctionPrototypeStub function_prototype_stub(isolate());
1146 return function_prototype_stub.GetCode();
1147 }
1148
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 Handle<Map> map = receiver_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001150 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1151 bool receiver_is_holder = receiver.is_identical_to(holder);
1152 switch (lookup->state()) {
1153 case LookupIterator::INTERCEPTOR: {
1154 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1157 // the original iterator will be used to fetch the value.
1158 LookupIterator it = *lookup;
1159 it.Next();
1160 LookupForRead(&it);
1161 return compiler.CompileLoadInterceptor(&it);
1162 }
1163
1164 case LookupIterator::ACCESSOR: {
1165 // Use simple field loads for some well-known callback properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166 // The method will only return true for absolute truths based on the
1167 // receiver maps.
1168 int object_offset;
1169 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1170 &object_offset)) {
1171 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1172 return SimpleFieldLoad(index);
1173 }
1174 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
1175 &object_offset)) {
1176 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1177 ArrayBufferViewLoadFieldStub stub(isolate(), index);
1178 return stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179 }
1180
Ben Murdoch097c5b22016-05-18 11:27:45 +01001181 if (IsCompatibleReceiver(lookup, map)) {
1182 Handle<Object> accessors = lookup->GetAccessors();
1183 if (accessors->IsAccessorPair()) {
1184 if (!holder->HasFastProperties()) break;
1185 // When debugging we need to go the slow path to flood the accessor.
1186 if (GetSharedFunctionInfo()->HasDebugInfo()) break;
1187 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1188 isolate());
1189 CallOptimization call_optimization(getter);
1190 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1191 cache_holder);
1192 if (call_optimization.is_simple_api_call()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193 return compiler.CompileLoadCallback(
1194 lookup->name(), call_optimization, lookup->GetAccessorIndex());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001195 }
1196 int expected_arguments = Handle<JSFunction>::cast(getter)
1197 ->shared()
1198 ->internal_formal_parameter_count();
1199 return compiler.CompileLoadViaGetter(
1200 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1201 } else if (accessors->IsAccessorInfo()) {
1202 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1203 if (v8::ToCData<Address>(info->getter()) == 0) break;
1204 if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 // This case should be already handled in LoadIC::UpdateCaches.
1206 UNREACHABLE();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001207 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001209 if (!holder->HasFastProperties()) break;
Ben Murdochda12d292016-06-02 14:46:10 +01001210 if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001211 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1212 cache_holder);
1213 return compiler.CompileLoadCallback(lookup->name(), info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001216 break;
1217 }
1218
1219 case LookupIterator::DATA: {
1220 if (lookup->is_dictionary_holder()) {
1221 if (kind() != Code::LOAD_IC) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 if (holder->IsJSGlobalObject()) {
1223 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001224 cache_holder);
1225 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1226 Handle<Code> code = compiler.CompileLoadGlobal(
1227 cell, lookup->name(), lookup->IsConfigurable());
1228 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1229 CacheHolderFlag flag;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 Handle<Map> stub_holder_map =
1231 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001232 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1233 return code;
1234 }
1235 // There is only one shared stub for loading normalized
1236 // properties. It does not traverse the prototype chain, so the
1237 // property must be found in the object for the stub to be
1238 // applicable.
1239 if (!receiver_is_holder) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001240 return isolate()->builtins()->LoadIC_Normal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 }
1242
1243 // -------------- Fields --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001244 if (lookup->property_details().type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 FieldIndex field = lookup->GetFieldIndex();
1246 if (receiver_is_holder) {
1247 return SimpleFieldLoad(field);
1248 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001249 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001250 return compiler.CompileLoadField(lookup->name(), field);
1251 }
1252
1253 // -------------- Constant properties --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 if (receiver_is_holder) {
1256 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1257 return stub.GetCode();
1258 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001259 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 return compiler.CompileLoadConstant(lookup->name(),
1261 lookup->GetConstantIndex());
1262 }
1263
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1265 return slow_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001266 case LookupIterator::ACCESS_CHECK:
1267 case LookupIterator::JSPROXY:
1268 case LookupIterator::NOT_FOUND:
1269 case LookupIterator::TRANSITION:
1270 UNREACHABLE();
1271 }
1272
1273 return slow_stub();
1274}
1275
1276
1277static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1278 // This helper implements a few common fast cases for converting
1279 // non-smi keys of keyed loads/stores to a smi or a string.
1280 if (key->IsHeapNumber()) {
1281 double value = Handle<HeapNumber>::cast(key)->value();
1282 if (std::isnan(value)) {
1283 key = isolate->factory()->nan_string();
1284 } else {
1285 int int_value = FastD2I(value);
1286 if (value == int_value && Smi::IsValid(int_value)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287 key = handle(Smi::FromInt(int_value), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 }
1289 }
1290 } else if (key->IsUndefined()) {
1291 key = isolate->factory()->undefined_string();
1292 }
1293 return key;
1294}
1295
1296
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001297Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1298 Handle<Code> null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 Handle<Map> receiver_map(receiver->map(), isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01001300 DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001301 MapHandleList target_receiver_maps;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001302 TargetMaps(&target_receiver_maps);
1303
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001304 if (target_receiver_maps.length() == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 Handle<Code> handler =
1306 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1307 receiver_map, extra_ic_state());
1308 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1309 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001310 }
1311
Ben Murdochda12d292016-06-02 14:46:10 +01001312 for (int i = 0; i < target_receiver_maps.length(); i++) {
1313 if (!target_receiver_maps.at(i).is_null() &&
1314 target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
1315 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "JSValue");
1316 return megamorphic_stub();
1317 }
1318 }
1319
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001320 // The first time a receiver is seen that is a transitioned version of the
1321 // previous monomorphic receiver type, assume the new ElementsKind is the
1322 // monomorphic type. This benefits global arrays that only transition
1323 // once, and all call sites accessing them are faster if they remain
1324 // monomorphic. If this optimistic assumption is not true, the IC will
1325 // miss again and it will become polymorphic and support both the
1326 // untransitioned and transitioned maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001327 if (state() == MONOMORPHIC && !receiver->IsString() &&
1328 IsMoreGeneralElementsKindTransition(
1329 target_receiver_maps.at(0)->elements_kind(),
1330 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001331 Handle<Code> handler =
1332 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1333 receiver_map, extra_ic_state());
1334 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1335 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001336 }
1337
1338 DCHECK(state() != GENERIC);
1339
1340 // Determine the list of receiver maps that this call site has seen,
1341 // adding the map that was just encountered.
1342 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1343 // If the miss wasn't due to an unseen map, a polymorphic stub
1344 // won't help, use the generic stub.
1345 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001347 }
1348
1349 // If the maximum number of receiver maps has been exceeded, use the generic
1350 // version of the IC.
1351 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1352 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 }
1355
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356 CodeHandleList handlers(target_receiver_maps.length());
1357 ElementHandlerCompiler compiler(isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001358 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
1360 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361}
1362
1363
1364MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1365 Handle<Object> key) {
1366 if (MigrateDeprecated(object)) {
1367 Handle<Object> result;
1368 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001369 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 Object);
1371 return result;
1372 }
1373
1374 Handle<Object> load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376
1377 // Check for non-string values that can be converted into an
1378 // internalized string directly or is representable as a smi.
1379 key = TryConvertKey(key, isolate());
1380
1381 if (key->IsInternalizedString() || key->IsSymbol()) {
1382 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1383 LoadIC::Load(object, Handle<Name>::cast(key)),
1384 Object);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001385 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1386 !object->IsJSValue()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1388 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 }
1391 }
1392
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 DCHECK(UseVector());
1394 if (!is_vector_set() || stub.is_null()) {
1395 Code* generic = *megamorphic_stub();
1396 if (!stub.is_null() && *stub == generic) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001397 ConfigureVectorState(MEGAMORPHIC, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001398 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001399 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401 TRACE_IC("LoadIC", key);
1402 }
1403
1404 if (!load_handle.is_null()) return load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001405
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 Handle<Object> result;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001407 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1408 Runtime::GetObjectProperty(isolate(), object, key),
1409 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001410 return result;
1411}
1412
1413
1414bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1415 JSReceiver::StoreFromKeyed store_mode) {
1416 // Disable ICs for non-JSObjects for now.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001417 Handle<Object> object = it->GetReceiver();
1418 if (!object->IsJSObject()) return false;
1419 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1420 DCHECK(!receiver->map()->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001421
1422 for (; it->IsFound(); it->Next()) {
1423 switch (it->state()) {
1424 case LookupIterator::NOT_FOUND:
1425 case LookupIterator::TRANSITION:
1426 UNREACHABLE();
1427 case LookupIterator::JSPROXY:
1428 return false;
1429 case LookupIterator::INTERCEPTOR: {
1430 Handle<JSObject> holder = it->GetHolder<JSObject>();
1431 InterceptorInfo* info = holder->GetNamedInterceptor();
1432 if (it->HolderIsReceiverOrHiddenPrototype()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001433 return !info->non_masking() && receiver.is_identical_to(holder) &&
1434 !info->setter()->IsUndefined();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 } else if (!info->getter()->IsUndefined() ||
1436 !info->query()->IsUndefined()) {
1437 return false;
1438 }
1439 break;
1440 }
1441 case LookupIterator::ACCESS_CHECK:
1442 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1443 break;
1444 case LookupIterator::ACCESSOR:
1445 return !it->IsReadOnly();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1447 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448 case LookupIterator::DATA: {
1449 if (it->IsReadOnly()) return false;
1450 Handle<JSObject> holder = it->GetHolder<JSObject>();
1451 if (receiver.is_identical_to(holder)) {
1452 it->PrepareForDataProperty(value);
1453 // The previous receiver map might just have been deprecated,
1454 // so reload it.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 return true;
1457 }
1458
1459 // Receiver != holder.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460 if (receiver->IsJSGlobalProxy()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001461 PrototypeIterator iter(it->isolate(), receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001462 return it->GetHolder<Object>().is_identical_to(
1463 PrototypeIterator::GetCurrent(iter));
1464 }
1465
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001466 if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1467
Ben Murdoch097c5b22016-05-18 11:27:45 +01001468 if (it->ExtendingNonExtensible(receiver)) return false;
1469 it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 return it->IsCacheableTransition();
1471 }
1472 }
1473 }
1474
Ben Murdoch097c5b22016-05-18 11:27:45 +01001475 receiver = it->GetStoreTarget();
1476 if (it->ExtendingNonExtensible(receiver)) return false;
1477 it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 return it->IsCacheableTransition();
1479}
1480
1481
1482MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1483 Handle<Object> value,
1484 JSReceiver::StoreFromKeyed store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 // Check if the name is trivially convertible to an index and set the element.
1486 uint32_t index;
1487 if (kind() == Code::KEYED_STORE_IC && name->AsArrayIndex(&index)) {
1488 // Rewrite to the generic keyed store stub.
1489 if (FLAG_use_ic) {
1490 if (UseVector()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001491 ConfigureVectorState(MEGAMORPHIC, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492 } else if (!AddressIsDeoptimizedCode()) {
1493 set_target(*megamorphic_stub());
1494 }
1495 TRACE_IC("StoreIC", name);
1496 TRACE_GENERIC_IC(isolate(), "StoreIC", "name as array index");
1497 }
1498 Handle<Object> result;
1499 ASSIGN_RETURN_ON_EXCEPTION(
1500 isolate(), result,
1501 Object::SetElement(isolate(), object, index, value, language_mode()),
1502 Object);
1503 return result;
1504 }
1505
1506 if (object->IsJSGlobalObject() && name->IsString()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001507 // Look up in script context table.
1508 Handle<String> str_name = Handle<String>::cast(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001510 Handle<ScriptContextTable> script_contexts(
1511 global->native_context()->script_context_table());
1512
1513 ScriptContextTable::LookupResult lookup_result;
1514 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1515 Handle<Context> script_context = ScriptContextTable::GetContext(
1516 script_contexts, lookup_result.context_index);
1517 if (lookup_result.mode == CONST) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 return TypeError(MessageTemplate::kConstAssign, object, name);
1519 }
1520
1521 Handle<Object> previous_value =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001522 FixedArray::get(*script_context, lookup_result.slot_index, isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523
1524 if (*previous_value == *isolate()->factory()->the_hole_value()) {
1525 // Do not install stubs and stay pre-monomorphic for
1526 // uninitialized accesses.
1527 return ReferenceError(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001528 }
1529
1530 if (FLAG_use_ic &&
1531 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1532 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1533 PatchCache(name, stub.GetCode());
1534 }
1535
1536 script_context->set(lookup_result.slot_index, *value);
1537 return value;
1538 }
1539 }
1540
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1542 // might deprecate the current map again, if value does not fit.
1543 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1544 Handle<Object> result;
1545 ASSIGN_RETURN_ON_EXCEPTION(
1546 isolate(), result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001547 Object::SetProperty(object, name, value, language_mode()), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548 return result;
1549 }
1550
1551 // If the object is undefined or null it's illegal to try to set any
1552 // properties on it; throw a TypeError in that case.
1553 if (object->IsUndefined() || object->IsNull()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 }
1556
1557 // Observed objects are always modified through the runtime.
1558 if (object->IsHeapObject() &&
1559 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1560 Handle<Object> result;
1561 ASSIGN_RETURN_ON_EXCEPTION(
1562 isolate(), result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001563 Object::SetProperty(object, name, value, language_mode(), store_mode),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 Object);
1565 return result;
1566 }
1567
1568 LookupIterator it(object, name);
1569 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1570
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001571 MAYBE_RETURN_NULL(
1572 Object::SetProperty(&it, value, language_mode(), store_mode));
1573 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001574}
1575
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001576Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001577 ConvertReceiverMode mode,
1578 TailCallMode tail_call_mode) {
1579 CallICTrampolineStub stub(isolate, CallICState(argc, mode, tail_call_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001580 Handle<Code> code = stub.GetCode();
1581 return code;
1582}
1583
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001584Handle<Code> CallIC::initialize_stub_in_optimized_code(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001585 Isolate* isolate, int argc, ConvertReceiverMode mode,
1586 TailCallMode tail_call_mode) {
1587 CallICStub stub(isolate, CallICState(argc, mode, tail_call_mode));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001588 Handle<Code> code = stub.GetCode();
1589 return code;
1590}
1591
1592
1593static Handle<Code> StoreICInitializeStubHelper(
1594 Isolate* isolate, ExtraICState extra_state,
1595 InlineCacheState initialization_state) {
1596 Handle<Code> ic = PropertyICCompiler::ComputeStore(
1597 isolate, initialization_state, extra_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001598 return ic;
1599}
1600
1601
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1603 LanguageMode language_mode,
1604 State initialization_state) {
1605 DCHECK(initialization_state == UNINITIALIZED ||
1606 initialization_state == PREMONOMORPHIC ||
1607 initialization_state == MEGAMORPHIC);
1608 VectorStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
1609 return stub.GetCode();
1610}
1611
1612
1613Handle<Code> StoreIC::initialize_stub_in_optimized_code(
1614 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
1615 DCHECK(initialization_state == UNINITIALIZED ||
1616 initialization_state == PREMONOMORPHIC ||
1617 initialization_state == MEGAMORPHIC);
1618 if (initialization_state != MEGAMORPHIC) {
1619 VectorStoreICStub stub(isolate, StoreICState(language_mode));
1620 return stub.GetCode();
1621 }
1622
1623 return StoreICInitializeStubHelper(
1624 isolate, ComputeExtraICState(language_mode), initialization_state);
1625}
1626
1627
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001628Handle<Code> StoreIC::megamorphic_stub() {
1629 if (kind() == Code::STORE_IC) {
1630 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1631 extra_ic_state());
1632 } else {
1633 DCHECK(kind() == Code::KEYED_STORE_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 if (is_strict(language_mode())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001635 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001636 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001637 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001638 }
1639 }
1640}
1641
1642
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001643Handle<Code> StoreIC::slow_stub() const {
1644 if (kind() == Code::STORE_IC) {
1645 return isolate()->builtins()->StoreIC_Slow();
1646 } else {
1647 DCHECK(kind() == Code::KEYED_STORE_IC);
1648 return isolate()->builtins()->KeyedStoreIC_Slow();
1649 }
1650}
1651
1652
1653Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001654 LanguageMode language_mode) {
1655 ExtraICState state = ComputeExtraICState(language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001656 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1657}
1658
1659
1660void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1661 JSReceiver::StoreFromKeyed store_mode) {
1662 if (state() == UNINITIALIZED) {
1663 // This is the first time we execute this inline cache. Set the target to
1664 // the pre monomorphic stub to delay setting the monomorphic state.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001665 ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 TRACE_IC("StoreIC", lookup->name());
1667 return;
1668 }
1669
1670 bool use_ic = LookupForWrite(lookup, value, store_mode);
1671 if (!use_ic) {
1672 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1673 }
1674 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1675
1676 PatchCache(lookup->name(), code);
1677 TRACE_IC("StoreIC", lookup->name());
1678}
1679
1680
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001681static Handle<Code> PropertyCellStoreHandler(
1682 Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
1683 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1684 auto constant_type = Nothing<PropertyCellConstantType>();
1685 if (type == PropertyCellType::kConstantType) {
1686 constant_type = Just(cell->GetConstantType());
1687 }
1688 StoreGlobalStub stub(isolate, type, constant_type,
1689 receiver->IsJSGlobalProxy());
1690 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1691 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1692 HeapObject::UpdateMapCodeCache(receiver, name, code);
1693 return code;
1694}
1695
1696
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1698 Handle<Object> value,
1699 CacheHolderFlag cache_holder) {
1700 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1701
1702 // This is currently guaranteed by checks in StoreIC::Store.
1703 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1704 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001705 DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001706
1707 switch (lookup->state()) {
1708 case LookupIterator::TRANSITION: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001709 auto store_target = lookup->GetStoreTarget();
1710 if (store_target->IsJSGlobalObject()) {
1711 // TODO(dcarney): this currently just deopts. Use the transition cell.
1712 auto cell = isolate()->factory()->NewPropertyCell();
1713 cell->set_value(*value);
1714 auto code = PropertyCellStoreHandler(
1715 isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
1716 lookup->name(), cell, PropertyCellType::kConstant);
1717 cell->set_value(isolate()->heap()->the_hole_value());
1718 return code;
1719 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 Handle<Map> transition = lookup->transition_map();
1721 // Currently not handled by CompileStoreTransition.
1722 if (!holder->HasFastProperties()) {
1723 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1724 break;
1725 }
1726
1727 DCHECK(lookup->IsCacheableTransition());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001728 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 return compiler.CompileStoreTransition(transition, lookup->name());
1730 }
1731
1732 case LookupIterator::INTERCEPTOR: {
1733 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
Ben Murdochda12d292016-06-02 14:46:10 +01001734 return CodeFactory::StoreInterceptor(isolate()).code();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 }
1736
1737 case LookupIterator::ACCESSOR: {
1738 if (!holder->HasFastProperties()) {
1739 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1740 break;
1741 }
1742 Handle<Object> accessors = lookup->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001743 if (accessors->IsAccessorInfo()) {
1744 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001745 if (v8::ToCData<Address>(info->setter()) == 0) {
1746 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1747 break;
1748 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001749 if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1750 !lookup->HolderIsReceiverOrHiddenPrototype()) {
1751 TRACE_GENERIC_IC(isolate(), "StoreIC",
1752 "special data property in prototype chain");
1753 break;
1754 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001755 if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1756 receiver_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001757 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1758 break;
1759 }
Ben Murdochda12d292016-06-02 14:46:10 +01001760 if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001761 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001762 return compiler.CompileStoreCallback(receiver, lookup->name(), info,
1763 language_mode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001764 } else if (accessors->IsAccessorPair()) {
1765 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1766 isolate());
1767 if (!setter->IsJSFunction()) {
1768 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1769 break;
1770 }
1771 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1772 CallOptimization call_optimization(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001773 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001774 if (call_optimization.is_simple_api_call() &&
1775 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1776 return compiler.CompileStoreCallback(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001777 call_optimization,
1778 lookup->GetAccessorIndex());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001779 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001780 int expected_arguments =
1781 function->shared()->internal_formal_parameter_count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001782 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001783 lookup->GetAccessorIndex(),
1784 expected_arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001786 break;
1787 }
1788
1789 case LookupIterator::DATA: {
1790 if (lookup->is_dictionary_holder()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001791 if (holder->IsJSGlobalObject()) {
1792 DCHECK(holder.is_identical_to(receiver) ||
1793 receiver->map()->prototype() == *holder);
1794 auto cell = lookup->GetPropertyCell();
1795 auto updated_type = PropertyCell::UpdatedType(
1796 cell, value, lookup->property_details());
1797 auto code = PropertyCellStoreHandler(
1798 isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
1799 lookup->name(), cell, updated_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001800 return code;
1801 }
1802 DCHECK(holder.is_identical_to(receiver));
1803 return isolate()->builtins()->StoreIC_Normal();
1804 }
1805
1806 // -------------- Fields --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001807 if (lookup->property_details().type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001808 bool use_stub = true;
1809 if (lookup->representation().IsHeapObject()) {
1810 // Only use a generic stub if no types need to be tracked.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001811 Handle<FieldType> field_type = lookup->GetFieldType();
1812 use_stub = !field_type->IsClass();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001813 }
1814 if (use_stub) {
1815 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1816 lookup->representation());
1817 return stub.GetCode();
1818 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001819 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001820 return compiler.CompileStoreField(lookup);
1821 }
1822
1823 // -------------- Constant properties --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001824 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001825 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1826 break;
1827 }
1828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001829 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001830 case LookupIterator::ACCESS_CHECK:
1831 case LookupIterator::JSPROXY:
1832 case LookupIterator::NOT_FOUND:
1833 UNREACHABLE();
1834 }
1835 return slow_stub();
1836}
1837
1838
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840 KeyedAccessStoreMode store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841 Handle<Code> null_handle;
1842 // Don't handle megamorphic property accesses for INTERCEPTORS or
1843 // ACCESSOR_CONSTANT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 // via megamorphic stubs, since they don't have a map in their relocation info
1845 // and so the stubs can't be harvested for the object needed for a map check.
1846 if (target()->type() != Code::NORMAL) {
1847 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001848 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001849 }
1850
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001851 MapHandleList target_receiver_maps;
1852 TargetMaps(&target_receiver_maps);
1853 if (target_receiver_maps.length() == 0) {
1854 Handle<Map> monomorphic_map =
1855 ComputeTransitionedMap(receiver_map, store_mode);
1856 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001857 Handle<Code> handler =
1858 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1859 monomorphic_map, language_mode(), store_mode);
1860 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler);
1861 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001862 }
1863
1864 // There are several special cases where an IC that is MONOMORPHIC can still
1865 // transition to a different GetNonTransitioningStoreMode IC that handles a
1866 // superset of the original IC. Handle those here if the receiver map hasn't
1867 // changed or it has transitioned to a more general kind.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001868 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001869 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1870 if (state() == MONOMORPHIC) {
1871 Handle<Map> transitioned_receiver_map = receiver_map;
1872 if (IsTransitionStoreMode(store_mode)) {
1873 transitioned_receiver_map =
1874 ComputeTransitionedMap(receiver_map, store_mode);
1875 }
1876 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1877 IsTransitionStoreMode(store_mode)) ||
1878 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1879 *transitioned_receiver_map)) {
1880 // If the "old" and "new" maps are in the same elements map family, or
1881 // if they at least come from the same origin for a transitioning store,
1882 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1883 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001884 Handle<Code> handler =
1885 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1886 transitioned_receiver_map, language_mode(), store_mode);
1887 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map,
1888 handler);
1889 return null_handle;
1890 } else if (receiver_map.is_identical_to(previous_receiver_map) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001891 old_store_mode == STANDARD_STORE &&
1892 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1893 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1894 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1895 // A "normal" IC that handles stores can switch to a version that can
1896 // grow at the end of the array, handle OOB accesses or copy COW arrays
1897 // and still stay MONOMORPHIC.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001898 Handle<Code> handler =
1899 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1900 receiver_map, language_mode(), store_mode);
1901 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1902 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001903 }
1904 }
1905
1906 DCHECK(state() != GENERIC);
1907
1908 bool map_added =
1909 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1910
1911 if (IsTransitionStoreMode(store_mode)) {
1912 Handle<Map> transitioned_receiver_map =
1913 ComputeTransitionedMap(receiver_map, store_mode);
1914 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1915 transitioned_receiver_map);
1916 }
1917
1918 if (!map_added) {
1919 // If the miss wasn't due to an unseen map, a polymorphic stub
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920 // won't help, use the megamorphic stub which can handle everything.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001922 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001923 }
1924
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001925 // If the maximum number of receiver maps has been exceeded, use the
1926 // megamorphic version of the IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001927 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001928 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 }
1930
1931 // Make sure all polymorphic handlers have the same store mode, otherwise the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001932 // megamorphic stub must be used.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 store_mode = GetNonTransitioningStoreMode(store_mode);
1934 if (old_store_mode != STANDARD_STORE) {
1935 if (store_mode == STANDARD_STORE) {
1936 store_mode = old_store_mode;
1937 } else if (store_mode != old_store_mode) {
1938 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001939 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001940 }
1941 }
1942
1943 // If the store mode isn't the standard mode, make sure that all polymorphic
1944 // receivers are either external arrays, or all "normal" arrays. Otherwise,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001945 // use the megamorphic stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001946 if (store_mode != STANDARD_STORE) {
1947 int external_arrays = 0;
1948 for (int i = 0; i < target_receiver_maps.length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001949 if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001950 external_arrays++;
1951 }
1952 }
1953 if (external_arrays != 0 &&
1954 external_arrays != target_receiver_maps.length()) {
1955 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1956 "unsupported combination of external and normal arrays");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001957 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001958 }
1959 }
1960
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001961 MapHandleList transitioned_maps(target_receiver_maps.length());
1962 CodeHandleList handlers(target_receiver_maps.length());
1963 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
1964 &target_receiver_maps, &transitioned_maps, &handlers, store_mode,
1965 language_mode());
1966 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
1967 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968}
1969
1970
1971Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1972 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1973 switch (store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001974 case STORE_TRANSITION_TO_OBJECT:
1975 case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1976 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1977 ? FAST_HOLEY_ELEMENTS
1978 : FAST_ELEMENTS;
1979 return Map::TransitionElementsTo(map, kind);
1980 }
1981 case STORE_TRANSITION_TO_DOUBLE:
1982 case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1983 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1984 ? FAST_HOLEY_DOUBLE_ELEMENTS
1985 : FAST_DOUBLE_ELEMENTS;
1986 return Map::TransitionElementsTo(map, kind);
1987 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001988 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001989 DCHECK(map->has_fixed_typed_array_elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001990 // Fall through
1991 case STORE_NO_TRANSITION_HANDLE_COW:
1992 case STANDARD_STORE:
1993 case STORE_AND_GROW_NO_TRANSITION:
1994 return map;
1995 }
1996 UNREACHABLE();
1997 return MaybeHandle<Map>().ToHandleChecked();
1998}
1999
2000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
2002 uint32_t length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 if (receiver->IsJSArray()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002004 JSArray::cast(*receiver)->length()->ToArrayLength(&length);
2005 } else {
2006 length = static_cast<uint32_t>(receiver->elements()->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002007 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 return index >= length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009}
2010
2011
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2013 uint32_t index, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002014 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2015 // Don't consider this a growing store if the store would send the receiver to
2016 // dictionary mode.
2017 bool allow_growth = receiver->IsJSArray() && oob_access &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002018 !receiver->WouldConvertToSlowElements(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002019 if (allow_growth) {
2020 // Handle growing array in stub if necessary.
2021 if (receiver->HasFastSmiElements()) {
2022 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002023 return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002024 }
2025 if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002026 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027 }
2028 } else if (receiver->HasFastDoubleElements()) {
2029 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031 }
2032 }
2033 return STORE_AND_GROW_NO_TRANSITION;
2034 } else {
2035 // Handle only in-bounds elements accesses.
2036 if (receiver->HasFastSmiElements()) {
2037 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002038 return STORE_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002039 } else if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002040 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002041 }
2042 } else if (receiver->HasFastDoubleElements()) {
2043 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002044 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002045 }
2046 }
2047 if (!FLAG_trace_external_array_abuse &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002048 receiver->map()->has_fixed_typed_array_elements() && oob_access) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2050 }
2051 Heap* heap = receiver->GetHeap();
2052 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2053 return STORE_NO_TRANSITION_HANDLE_COW;
2054 } else {
2055 return STANDARD_STORE;
2056 }
2057 }
2058}
2059
2060
2061MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2062 Handle<Object> key,
2063 Handle<Object> value) {
2064 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2065 // might deprecate the current map again, if value does not fit.
2066 if (MigrateDeprecated(object)) {
2067 Handle<Object> result;
2068 ASSIGN_RETURN_ON_EXCEPTION(
2069 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002070 value, language_mode()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 Object);
2072 return result;
2073 }
2074
2075 // Check for non-string values that can be converted into an
2076 // internalized string directly or is representable as a smi.
2077 key = TryConvertKey(key, isolate());
2078
2079 Handle<Object> store_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002080 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002081
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002082 uint32_t index;
2083 if ((key->IsInternalizedString() &&
2084 !String::cast(*key)->AsArrayIndex(&index)) ||
2085 key->IsSymbol()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002086 ASSIGN_RETURN_ON_EXCEPTION(
2087 isolate(), store_handle,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002088 StoreIC::Store(object, Handle<Name>::cast(key), value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2090 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002091 if (!is_vector_set()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002092 ConfigureVectorState(MEGAMORPHIC, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002093 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2094 "unhandled internalized string key");
2095 TRACE_IC("StoreIC", key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002096 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002097 return store_handle;
2098 }
2099
2100 bool use_ic =
2101 FLAG_use_ic && !object->IsStringWrapper() &&
2102 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2103 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2104 if (use_ic && !object->IsSmi()) {
2105 // Don't use ICs for maps of the objects in Array's prototype chain. We
2106 // expect to be able to trap element sets to objects with those maps in
2107 // the runtime to enable optimization of element hole access.
2108 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2109 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2110 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2111 use_ic = false;
2112 }
2113 }
2114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002115 Handle<Map> old_receiver_map;
2116 bool sloppy_arguments_elements = false;
2117 bool key_is_valid_index = false;
2118 KeyedAccessStoreMode store_mode = STANDARD_STORE;
2119 if (use_ic && object->IsJSObject()) {
2120 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2121 old_receiver_map = handle(receiver->map(), isolate());
2122 sloppy_arguments_elements =
2123 !is_sloppy(language_mode()) &&
2124 receiver->elements()->map() ==
2125 isolate()->heap()->sloppy_arguments_elements_map();
2126 if (!sloppy_arguments_elements) {
2127 key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
2128 if (key_is_valid_index) {
2129 uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2130 store_mode = GetStoreMode(receiver, index, value);
2131 }
2132 }
2133 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002135 DCHECK(store_handle.is_null());
2136 ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2137 Runtime::SetObjectProperty(isolate(), object, key,
2138 value, language_mode()),
2139 Object);
2140
2141 if (use_ic) {
2142 if (!old_receiver_map.is_null()) {
2143 if (sloppy_arguments_elements) {
2144 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2145 } else if (key_is_valid_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146 // We should go generic if receiver isn't a dictionary, but our
2147 // prototype chain does have dictionary elements. This ensures that
2148 // other non-dictionary receivers in the polymorphic case benefit
2149 // from fast path keyed stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002150 if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2151 stub = StoreElementStub(old_receiver_map, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002152 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002153 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2154 "dictionary or proxy prototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002155 }
2156 } else {
2157 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2158 }
2159 } else {
2160 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2161 }
2162 }
2163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002164 if (!is_vector_set() || stub.is_null()) {
2165 Code* megamorphic = *megamorphic_stub();
2166 if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002167 ConfigureVectorState(MEGAMORPHIC, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002168 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2169 *stub == megamorphic ? "set generic" : "slow stub");
2170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002171 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002172 TRACE_IC("StoreIC", key);
2173
2174 return store_handle;
2175}
2176
2177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002178void CallIC::HandleMiss(Handle<Object> function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002179 Handle<Object> name = isolate()->factory()->empty_string();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002180 CallICNexus* nexus = casted_nexus<CallICNexus>();
2181 Object* feedback = nexus->GetFeedback();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002182
2183 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2184 DCHECK(!feedback->IsSmi());
2185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002186 if (feedback->IsWeakCell() || !function->IsJSFunction() ||
2187 feedback->IsAllocationSite()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002188 // We are going generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002189 nexus->ConfigureMegamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002190 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002191 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
2192 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002193
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002194 Handle<JSFunction> array_function =
2195 Handle<JSFunction>(isolate()->native_context()->array_function());
2196 if (array_function.is_identical_to(js_function)) {
2197 // Alter the slot.
2198 nexus->ConfigureMonomorphicArray();
2199 } else if (js_function->context()->native_context() !=
2200 *isolate()->native_context()) {
2201 // Don't collect cross-native context feedback for the CallIC.
2202 // TODO(bmeurer): We should collect the SharedFunctionInfo as
2203 // feedback in this case instead.
2204 nexus->ConfigureMegamorphic();
2205 } else {
2206 nexus->ConfigureMonomorphic(js_function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002207 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002208 }
2209
2210 if (function->IsJSFunction()) {
2211 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2212 name = handle(js_function->shared()->name(), isolate());
2213 }
2214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002215 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002216 TRACE_IC("CallIC", name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217}
2218
2219
2220#undef TRACE_IC
2221
2222
2223// ----------------------------------------------------------------------------
2224// Static IC stub generators.
2225//
2226
2227// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002228RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002229 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002230 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002231 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002232 DCHECK(args.length() == 3);
2233 Handle<Object> function = args.at<Object>(0);
2234 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2235 Handle<Smi> slot = args.at<Smi>(2);
2236 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002237 CallICNexus nexus(vector, vector_slot);
2238 CallIC ic(isolate, &nexus);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002239 ic.HandleMiss(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002240 return *function;
2241}
2242
2243
2244// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002245RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002246 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002247 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002248 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002249 Handle<Object> receiver = args.at<Object>(0);
2250 Handle<Name> key = args.at<Name>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002251 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002253 DCHECK(args.length() == 4);
2254 Handle<Smi> slot = args.at<Smi>(2);
2255 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2256 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2257 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2258 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2259 // set up outside the IC, handle that here.
2260 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
2261 LoadICNexus nexus(vector, vector_slot);
2262 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2263 ic.UpdateState(receiver, key);
2264 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002265 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002266 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
2267 vector->GetKind(vector_slot));
2268 KeyedLoadICNexus nexus(vector, vector_slot);
2269 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002270 ic.UpdateState(receiver, key);
2271 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2272 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273 return *result;
2274}
2275
2276
2277// Used from ic-<arch>.cc
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002278RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002280 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002281 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002282 Handle<Object> receiver = args.at<Object>(0);
2283 Handle<Object> key = args.at<Object>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002284 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002285
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002286 DCHECK(args.length() == 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002287 Handle<Smi> slot = args.at<Smi>(2);
2288 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2289 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2290 KeyedLoadICNexus nexus(vector, vector_slot);
2291 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2292 ic.UpdateState(receiver, key);
2293 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2294 return *result;
2295}
2296
2297
2298RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
2299 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002300 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002301 HandleScope scope(isolate);
2302 Handle<Object> receiver = args.at<Object>(0);
2303 Handle<Object> key = args.at<Object>(1);
2304 Handle<Object> result;
2305
2306 DCHECK(args.length() == 4);
2307 Handle<Smi> slot = args.at<Smi>(2);
2308 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2309 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2310 KeyedLoadICNexus nexus(vector, vector_slot);
2311 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2312 ic.UpdateState(receiver, key);
2313 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2314
2315 return *result;
2316}
2317
2318
2319// Used from ic-<arch>.cc.
2320RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2321 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002322 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002323 HandleScope scope(isolate);
2324 Handle<Object> receiver = args.at<Object>(0);
2325 Handle<Name> key = args.at<Name>(1);
2326 Handle<Object> value = args.at<Object>(2);
2327 Handle<Object> result;
2328
2329 DCHECK(args.length() == 5 || args.length() == 6);
2330 Handle<Smi> slot = args.at<Smi>(3);
2331 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2332 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2333 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2334 StoreICNexus nexus(vector, vector_slot);
2335 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2336 ic.UpdateState(receiver, key);
2337 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2338 ic.Store(receiver, key, value));
2339 } else {
2340 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2341 vector->GetKind(vector_slot));
2342 KeyedStoreICNexus nexus(vector, vector_slot);
2343 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2344 ic.UpdateState(receiver, key);
2345 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2346 ic.Store(receiver, key, value));
2347 }
2348 return *result;
2349}
2350
2351
2352RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
2353 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002354 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002355 HandleScope scope(isolate);
2356 Handle<Object> receiver = args.at<Object>(0);
2357 Handle<Name> key = args.at<Name>(1);
2358 Handle<Object> value = args.at<Object>(2);
2359 Handle<Object> result;
2360
2361 int length = args.length();
2362 DCHECK(length == 5 || length == 6);
2363 // We might have slot and vector, for a normal miss (slot(3), vector(4)).
2364 // Or, map and vector for a transitioning store miss (map(3), vector(4)).
2365 // In this case, we need to recover the slot from a virtual register.
2366 // If length == 6, then a map is included (map(3), slot(4), vector(5)).
2367 Handle<Smi> slot;
2368 Handle<TypeFeedbackVector> vector;
2369 if (length == 5) {
2370 if (args.at<Object>(3)->IsMap()) {
2371 vector = args.at<TypeFeedbackVector>(4);
2372 slot = handle(
2373 *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()),
2374 isolate);
2375 } else {
2376 vector = args.at<TypeFeedbackVector>(4);
2377 slot = args.at<Smi>(3);
2378 }
2379 } else {
2380 vector = args.at<TypeFeedbackVector>(5);
2381 slot = args.at<Smi>(4);
2382 }
2383
2384 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2385 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2386 StoreICNexus nexus(vector, vector_slot);
2387 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2388 ic.UpdateState(receiver, key);
2389 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2390 ic.Store(receiver, key, value));
2391 } else {
2392 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2393 vector->GetKind(vector_slot));
2394 KeyedStoreICNexus nexus(vector, vector_slot);
2395 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2396 ic.UpdateState(receiver, key);
2397 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2398 ic.Store(receiver, key, value));
2399 }
2400 return *result;
2401}
2402
2403
2404// Used from ic-<arch>.cc.
2405RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2406 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002407 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002408 HandleScope scope(isolate);
2409 Handle<Object> receiver = args.at<Object>(0);
2410 Handle<Object> key = args.at<Object>(1);
2411 Handle<Object> value = args.at<Object>(2);
2412 Handle<Object> result;
2413
2414 DCHECK(args.length() == 5);
2415 Handle<Smi> slot = args.at<Smi>(3);
2416 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2417 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2418 KeyedStoreICNexus nexus(vector, vector_slot);
2419 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2420 ic.UpdateState(receiver, key);
2421 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2422 ic.Store(receiver, key, value));
2423 return *result;
2424}
2425
2426
2427RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) {
2428 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002429 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002430 HandleScope scope(isolate);
2431 Handle<Object> receiver = args.at<Object>(0);
2432 Handle<Object> key = args.at<Object>(1);
2433 Handle<Object> value = args.at<Object>(2);
2434 Handle<Object> result;
2435
2436 DCHECK(args.length() == 5);
2437 Handle<Smi> slot = args.at<Smi>(3);
2438 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2439 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2440 KeyedStoreICNexus nexus(vector, vector_slot);
2441 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2442 ic.UpdateState(receiver, key);
2443 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2444 ic.Store(receiver, key, value));
2445 return *result;
2446}
2447
2448
2449RUNTIME_FUNCTION(Runtime_StoreIC_Slow) {
2450 HandleScope scope(isolate);
2451 DCHECK(args.length() == 5);
2452 Handle<Object> object = args.at<Object>(0);
2453 Handle<Object> key = args.at<Object>(1);
2454 Handle<Object> value = args.at<Object>(2);
2455 LanguageMode language_mode;
2456 StoreICNexus nexus(isolate);
2457 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2458 language_mode = ic.language_mode();
2459 Handle<Object> result;
2460 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2461 isolate, result,
2462 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2463 return *result;
2464}
2465
2466
2467RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2468 HandleScope scope(isolate);
2469 DCHECK(args.length() == 5);
2470 Handle<Object> object = args.at<Object>(0);
2471 Handle<Object> key = args.at<Object>(1);
2472 Handle<Object> value = args.at<Object>(2);
2473 LanguageMode language_mode;
2474 KeyedStoreICNexus nexus(isolate);
2475 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2476 language_mode = ic.language_mode();
2477 Handle<Object> result;
2478 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2479 isolate, result,
2480 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2481 return *result;
2482}
2483
2484
2485RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2486 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002487 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002488 HandleScope scope(isolate);
2489 // Length == 5 or 6, depending on whether the vector slot
2490 // is passed in a virtual register or not.
2491 DCHECK(args.length() == 5 || args.length() == 6);
2492 Handle<Object> object = args.at<Object>(0);
2493 Handle<Object> key = args.at<Object>(1);
2494 Handle<Object> value = args.at<Object>(2);
2495 Handle<Map> map = args.at<Map>(3);
2496 LanguageMode language_mode;
2497 KeyedStoreICNexus nexus(isolate);
2498 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2499 language_mode = ic.language_mode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002500 if (object->IsJSObject()) {
2501 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2502 map->elements_kind());
2503 }
2504 Handle<Object> result;
2505 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2506 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002507 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002508 return *result;
2509}
2510
2511
2512MaybeHandle<Object> BinaryOpIC::Transition(
2513 Handle<AllocationSite> allocation_site, Handle<Object> left,
2514 Handle<Object> right) {
2515 BinaryOpICState state(isolate(), target()->extra_ic_state());
2516
2517 // Compute the actual result using the builtin for the binary operation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002518 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002519 switch (state.op()) {
2520 default:
2521 UNREACHABLE();
2522 case Token::ADD:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002523 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2524 Object::Add(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002525 break;
2526 case Token::SUB:
2527 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002528 isolate(), result, Object::Subtract(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002529 break;
2530 case Token::MUL:
2531 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002532 isolate(), result, Object::Multiply(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002533 break;
2534 case Token::DIV:
2535 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002536 isolate(), result, Object::Divide(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002537 break;
2538 case Token::MOD:
2539 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002540 isolate(), result, Object::Modulus(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002541 break;
2542 case Token::BIT_OR:
2543 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002544 isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002545 break;
2546 case Token::BIT_AND:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002547 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2548 Object::BitwiseAnd(isolate(), left, right),
2549 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002550 break;
2551 case Token::BIT_XOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002552 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2553 Object::BitwiseXor(isolate(), left, right),
2554 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002555 break;
2556 case Token::SAR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002557 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2558 Object::ShiftRight(isolate(), left, right),
2559 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002560 break;
2561 case Token::SHR:
2562 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002563 isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002564 Object);
2565 break;
2566 case Token::SHL:
2567 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002568 isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002569 break;
2570 }
2571
2572 // Do not try to update the target if the code was marked for lazy
2573 // deoptimization. (Since we do not relocate addresses in these
2574 // code objects, an attempt to access the target could fail.)
2575 if (AddressIsDeoptimizedCode()) {
2576 return result;
2577 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002578
2579 // Execution::Call can execute arbitrary JavaScript, hence potentially
2580 // update the state of this very IC, so we must update the stored state.
2581 UpdateTarget();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002582
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002583 // Compute the new state.
2584 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2585 state.Update(left, right, result);
2586
2587 // Check if we have a string operation here.
2588 Handle<Code> target;
2589 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2590 // Setup the allocation site on-demand.
2591 if (allocation_site.is_null()) {
2592 allocation_site = isolate()->factory()->NewAllocationSite();
2593 }
2594
2595 // Install the stub with an allocation site.
2596 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2597 target = stub.GetCodeCopyFromTemplate(allocation_site);
2598
2599 // Sanity check the trampoline stub.
2600 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2601 } else {
2602 // Install the generic stub.
2603 BinaryOpICStub stub(isolate(), state);
2604 target = stub.GetCode();
2605
2606 // Sanity check the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002607 DCHECK_NULL(target->FindFirstAllocationSite());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002608 }
2609 set_target(*target);
2610
2611 if (FLAG_trace_ic) {
2612 OFStream os(stdout);
2613 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2614 << static_cast<void*>(*target) << " <- ";
2615 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2616 if (!allocation_site.is_null()) {
2617 os << " using allocation site " << static_cast<void*>(*allocation_site);
2618 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002619 os << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002620 }
2621
2622 // Patch the inlined smi code as necessary.
2623 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002624 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002627 }
2628
2629 return result;
2630}
2631
2632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002633RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002634 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002635 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002636 HandleScope scope(isolate);
2637 DCHECK_EQ(2, args.length());
2638 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2639 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2640 BinaryOpIC ic(isolate);
2641 Handle<Object> result;
2642 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2643 isolate, result,
2644 ic.Transition(Handle<AllocationSite>::null(), left, right));
2645 return *result;
2646}
2647
2648
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002649RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002650 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002651 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002652 HandleScope scope(isolate);
2653 DCHECK_EQ(3, args.length());
2654 Handle<AllocationSite> allocation_site =
2655 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2656 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2657 Handle<Object> right =
2658 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2659 BinaryOpIC ic(isolate);
2660 Handle<Object> result;
2661 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2662 isolate, result, ic.Transition(allocation_site, left, right));
2663 return *result;
2664}
2665
Ben Murdoch097c5b22016-05-18 11:27:45 +01002666Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2667 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002668 CompareICState::UNINITIALIZED,
2669 CompareICState::UNINITIALIZED);
2670 Code* code = NULL;
2671 CHECK(stub.FindCodeInCache(&code));
2672 return code;
2673}
2674
Ben Murdoch097c5b22016-05-18 11:27:45 +01002675Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
2676 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002677 CompareICState::UNINITIALIZED,
2678 CompareICState::UNINITIALIZED);
2679 return stub.GetCode();
2680}
2681
2682
2683Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2684 HandleScope scope(isolate());
2685 CompareICStub old_stub(target()->stub_key(), isolate());
2686 CompareICState::State new_left =
2687 CompareICState::NewInputState(old_stub.left(), x);
2688 CompareICState::State new_right =
2689 CompareICState::NewInputState(old_stub.right(), y);
2690 CompareICState::State state = CompareICState::TargetState(
2691 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2692 HasInlinedSmiCode(address()), x, y);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002693 CompareICStub stub(isolate(), op_, new_left, new_right, state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002694 if (state == CompareICState::KNOWN_RECEIVER) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002695 stub.set_known_map(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002696 Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002697 }
2698 Handle<Code> new_target = stub.GetCode();
2699 set_target(*new_target);
2700
2701 if (FLAG_trace_ic) {
2702 PrintF("[CompareIC in ");
2703 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2704 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2705 CompareICState::GetStateName(old_stub.left()),
2706 CompareICState::GetStateName(old_stub.right()),
2707 CompareICState::GetStateName(old_stub.state()),
2708 CompareICState::GetStateName(new_left),
2709 CompareICState::GetStateName(new_right),
2710 CompareICState::GetStateName(state), Token::Name(op_),
2711 static_cast<void*>(*stub.GetCode()));
2712 }
2713
2714 // Activate inlined smi code.
2715 if (old_stub.state() == CompareICState::UNINITIALIZED) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002716 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002717 }
2718
2719 return *new_target;
2720}
2721
2722
2723// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002724RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002725 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002726 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002727 HandleScope scope(isolate);
2728 DCHECK(args.length() == 3);
2729 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2730 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2731}
2732
2733
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002734RUNTIME_FUNCTION(Runtime_Unreachable) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002735 UNREACHABLE();
2736 CHECK(false);
2737 return isolate->heap()->undefined_value();
2738}
2739
2740
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002741Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
Ben Murdochda12d292016-06-02 14:46:10 +01002742 ToBooleanICStub stub(isolate(), target()->extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002743 bool to_boolean_value = stub.UpdateStatus(object);
2744 Handle<Code> code = stub.GetCode();
2745 set_target(*code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002746 return isolate()->factory()->ToBoolean(to_boolean_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002747}
2748
2749
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002750RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002751 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002752 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002753 DCHECK(args.length() == 1);
2754 HandleScope scope(isolate);
2755 Handle<Object> object = args.at<Object>(0);
2756 ToBooleanIC ic(isolate);
2757 return *ic.ToBoolean(object);
2758}
2759
2760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002761RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002762 Handle<JSObject> receiver = args.at<JSObject>(0);
2763 Handle<JSObject> holder = args.at<JSObject>(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002764 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002765 Handle<Name> name = args.at<Name>(3);
2766 Handle<Object> value = args.at<Object>(4);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002767 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002768 HandleScope scope(isolate);
2769
Ben Murdoch097c5b22016-05-18 11:27:45 +01002770 Handle<AccessorInfo> callback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002771 callback_or_cell->IsWeakCell()
Ben Murdoch097c5b22016-05-18 11:27:45 +01002772 ? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
2773 : AccessorInfo::cast(*callback_or_cell));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002774
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002775 DCHECK(callback->IsCompatibleReceiver(*receiver));
2776
2777 Address setter_address = v8::ToCData<Address>(callback->setter());
2778 v8::AccessorNameSetterCallback fun =
2779 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2780 DCHECK(fun != NULL);
2781
Ben Murdoch097c5b22016-05-18 11:27:45 +01002782 Object::ShouldThrow should_throw =
2783 is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002784 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002785 *holder, should_throw);
Ben Murdochda12d292016-06-02 14:46:10 +01002786 custom_args.Call(fun, name, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002787 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2788 return *value;
2789}
2790
2791
2792/**
2793 * Attempts to load a property with an interceptor (which must be present),
2794 * but doesn't search the prototype chain.
2795 *
2796 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2797 * provide any value for the given name.
2798 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002799RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002800 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002801 Handle<Name> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002802 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Ben Murdochda12d292016-06-02 14:46:10 +01002803 Handle<Object> receiver =
2804 args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002805 Handle<JSObject> holder =
2806 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002807 HandleScope scope(isolate);
Ben Murdochda12d292016-06-02 14:46:10 +01002808
2809 if (!receiver->IsJSReceiver()) {
2810 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2811 isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2812 }
2813
2814 InterceptorInfo* interceptor = holder->GetNamedInterceptor();
2815 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2816 *holder, Object::DONT_THROW);
2817
2818 v8::GenericNamedPropertyGetterCallback getter =
2819 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
2820 interceptor->getter());
2821 Handle<Object> result = arguments.Call(getter, name);
2822
2823 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2824
2825 if (!result.is_null()) return *result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002826 return isolate->heap()->no_interceptor_result_sentinel();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002827}
2828
2829
2830/**
2831 * Loads a property with an interceptor performing post interceptor
2832 * lookup if interceptor failed.
2833 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002834RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002835 HandleScope scope(isolate);
2836 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2837 Handle<Name> name =
2838 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Ben Murdochda12d292016-06-02 14:46:10 +01002839 Handle<Object> receiver =
2840 args.at<Object>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002841 Handle<JSObject> holder =
2842 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2843
Ben Murdochda12d292016-06-02 14:46:10 +01002844 if (!receiver->IsJSReceiver()) {
2845 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2846 isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2847 }
2848
2849 InterceptorInfo* interceptor = holder->GetNamedInterceptor();
2850 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2851 *holder, Object::DONT_THROW);
2852
2853 v8::GenericNamedPropertyGetterCallback getter =
2854 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
2855 interceptor->getter());
2856 Handle<Object> result = arguments.Call(getter, name);
2857
2858 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2859
2860 if (!result.is_null()) return *result;
2861
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002862 LookupIterator it(receiver, name, holder);
Ben Murdochda12d292016-06-02 14:46:10 +01002863 // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2864 while (it.state() != LookupIterator::INTERCEPTOR ||
2865 !it.GetHolder<JSObject>().is_identical_to(holder)) {
2866 DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2867 it.Next();
2868 }
2869 // Skip past the interceptor.
2870 it.Next();
2871 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872
2873 if (it.IsFound()) return *result;
2874
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002875 LoadICNexus nexus(isolate);
2876 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2877 if (!ic.ShouldThrowReferenceError(it.GetReceiver())) {
2878 return isolate->heap()->undefined_value();
2879 }
2880
2881 // Throw a reference error.
2882 THROW_NEW_ERROR_RETURN_FAILURE(
2883 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002884}
2885
2886
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002887RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 HandleScope scope(isolate);
2889 DCHECK(args.length() == 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002890 StoreICNexus nexus(isolate);
2891 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002892 Handle<JSObject> receiver = args.at<JSObject>(0);
2893 Handle<Name> name = args.at<Name>(1);
2894 Handle<Object> value = args.at<Object>(2);
Ben Murdochda12d292016-06-02 14:46:10 +01002895
2896 DCHECK(receiver->HasNamedInterceptor());
2897 InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
2898 DCHECK(!interceptor->non_masking());
2899 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2900 *receiver, Object::DONT_THROW);
2901
2902 v8::GenericNamedPropertySetterCallback setter =
2903 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
2904 interceptor->setter());
2905 Handle<Object> result = arguments.Call(setter, name, value);
2906 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2907 if (!result.is_null()) return *value;
2908
2909 LookupIterator it(receiver, name, receiver);
2910 // Skip past any access check on the receiver.
2911 if (it.state() == LookupIterator::ACCESS_CHECK) {
2912 DCHECK(it.HasAccess());
2913 it.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002914 }
Ben Murdochda12d292016-06-02 14:46:10 +01002915 // Skip past the interceptor on the receiver.
2916 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2917 it.Next();
2918
2919 MAYBE_RETURN(Object::SetProperty(&it, value, ic.language_mode(),
2920 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
2921 isolate->heap()->exception());
2922 return *value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002923}
2924
2925
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002926RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2927 // TODO(verwaest): This should probably get the holder and receiver as input.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002928 HandleScope scope(isolate);
2929 Handle<JSObject> receiver = args.at<JSObject>(0);
2930 DCHECK(args.smi_at(1) >= 0);
2931 uint32_t index = args.smi_at(1);
Ben Murdochda12d292016-06-02 14:46:10 +01002932
2933 InterceptorInfo* interceptor = receiver->GetIndexedInterceptor();
2934 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2935 *receiver, Object::DONT_THROW);
2936
2937 v8::IndexedPropertyGetterCallback getter =
2938 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
2939 Handle<Object> result = arguments.Call(getter, index);
2940
2941 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2942
2943 if (result.is_null()) {
2944 LookupIterator it(isolate, receiver, index, receiver);
2945 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2946 it.Next();
2947 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2948 Object::GetProperty(&it));
2949 }
2950
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002951 return *result;
2952}
2953
2954
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002955RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002956 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002957 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002958 HandleScope scope(isolate);
2959 Handle<Object> receiver = args.at<Object>(0);
2960 Handle<Name> key = args.at<Name>(1);
2961 Handle<Object> result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002962
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002963 DCHECK(args.length() == 4);
2964 Handle<Smi> slot = args.at<Smi>(2);
2965 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2966 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2967 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2968 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2969 // set up outside the IC, handle that here.
2970 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
2971 LoadICNexus nexus(vector, vector_slot);
2972 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2973 ic.UpdateState(receiver, key);
2974 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002975 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002976 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
2977 vector->GetKind(vector_slot));
2978 KeyedLoadICNexus nexus(vector, vector_slot);
2979 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002980 ic.UpdateState(receiver, key);
2981 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2982 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002983
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002984 return *result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002985}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002986} // namespace internal
2987} // namespace v8