blob: c0b3e49338a49921cb335504f829aa9096cde0bc [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"
9#include "src/arguments.h"
10#include "src/base/bits.h"
11#include "src/codegen.h"
12#include "src/conversions.h"
13#include "src/execution.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010014#include "src/field-type.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "src/frames-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016#include "src/ic/call-optimization.h"
17#include "src/ic/handler-compiler.h"
18#include "src/ic/ic-inl.h"
19#include "src/ic/ic-compiler.h"
20#include "src/ic/stub-cache.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021#include "src/isolate-inl.h"
22#include "src/macro-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023#include "src/prototype.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024#include "src/runtime/runtime.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010025#include "src/runtime/runtime-utils.h"
26#include "src/tracing/trace-event.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027
28namespace v8 {
29namespace internal {
30
31char IC::TransitionMarkFromState(IC::State state) {
32 switch (state) {
33 case UNINITIALIZED:
34 return '0';
35 case PREMONOMORPHIC:
36 return '.';
37 case MONOMORPHIC:
38 return '1';
39 case PROTOTYPE_FAILURE:
40 return '^';
41 case POLYMORPHIC:
42 return 'P';
43 case MEGAMORPHIC:
44 return 'N';
45 case GENERIC:
46 return 'G';
47
48 // We never see the debugger states here, because the state is
49 // computed from the original code - not the patched code. Let
50 // these cases fall through to the unreachable code below.
51 case DEBUG_STUB:
52 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053 }
54 UNREACHABLE();
55 return 0;
56}
57
58
59const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
60 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
61 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
62 return ".IGNORE_OOB";
63 }
64 if (IsGrowStoreMode(mode)) return ".GROW";
65 return "";
66}
67
68
69#ifdef DEBUG
70
71#define TRACE_GENERIC_IC(isolate, type, reason) \
72 do { \
73 if (FLAG_trace_ic) { \
74 PrintF("[%s patching generic stub in ", type); \
75 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
76 PrintF(" (%s)]\n", reason); \
77 } \
78 } while (false)
79
80#else
81
82#define TRACE_GENERIC_IC(isolate, type, reason) \
83 do { \
84 if (FLAG_trace_ic) { \
85 PrintF("[%s patching generic stub in ", type); \
86 PrintF("(see below) (%s)]\n", reason); \
87 } \
88 } while (false)
89
90#endif // DEBUG
91
92
93void IC::TraceIC(const char* type, Handle<Object> name) {
94 if (FLAG_trace_ic) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 if (AddressIsDeoptimizedCode()) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040096 State new_state =
97 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 TraceIC(type, name, state(), new_state);
99 }
100}
101
102
103void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
104 State new_state) {
105 if (FLAG_trace_ic) {
106 Code* new_target = raw_target();
107 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
108
109 // TODO(jkummerow): Add support for "apply". The logic is roughly:
110 // marker = [fp_ + kMarkerOffset];
111 // if marker is smi and marker.value == INTERNAL and
112 // the frame's code == builtin(Builtins::kFunctionApply):
113 // then print "apply from" and advance one frame
114
115 Object* maybe_function =
116 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
117 if (maybe_function->IsJSFunction()) {
118 JSFunction* function = JSFunction::cast(maybe_function);
119 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
120 stdout, true);
121 }
122
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 const char* modifier = "";
124 if (new_target->kind() == Code::KEYED_STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 KeyedAccessStoreMode mode =
126 casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
127 modifier = GetTransitionMarkModifier(mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 TransitionMarkFromState(new_state), modifier);
131#ifdef OBJECT_PRINT
132 OFStream os(stdout);
133 name->Print(os);
134#else
135 name->ShortPrint(stdout);
136#endif
137 PrintF("]\n");
138 }
139}
140
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400142#define TRACE_IC(type, name) TraceIC(type, name)
143
144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146 : isolate_(isolate),
147 target_set_(false),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 vector_set_(false),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400149 target_maps_set_(false),
150 nexus_(nexus) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 // To improve the performance of the (much used) IC code, we unfold a few
152 // levels of the stack frame iteration code. This yields a ~35% speedup when
153 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
154 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 Address* constant_pool = NULL;
156 if (FLAG_enable_embedded_constant_pool) {
157 constant_pool = reinterpret_cast<Address*>(
158 entry + ExitFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 }
160 Address* pc_address =
161 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
162 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
163 // If there's another JavaScript frame on the stack or a
164 // StubFailureTrampoline, we need to look one frame further down the stack to
165 // find the frame pointer and the return address stack slot.
166 if (depth == EXTRA_CALL_FRAME) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167 if (FLAG_enable_embedded_constant_pool) {
168 constant_pool = reinterpret_cast<Address*>(
169 fp + StandardFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 }
171 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
172 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
173 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
174 }
175#ifdef DEBUG
176 StackFrameIterator it(isolate);
177 for (int i = 0; i < depth + 1; i++) it.Advance();
178 StackFrame* frame = it.frame();
179 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
180#endif
181 fp_ = fp;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 if (FLAG_enable_embedded_constant_pool) {
183 constant_pool_address_ = constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 }
185 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
186 target_ = handle(raw_target(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 kind_ = target_->kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 state_ = UseVector() ? nexus->StateFromFeedback() : target_->ic_state();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 old_state_ = state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 extra_ic_state_ = target_->extra_ic_state();
191}
192
193
194SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
195 // Compute the JavaScript frame for the frame pointer of this IC
196 // structure. We need this to be able to find the function
197 // corresponding to the frame.
198 StackFrameIterator it(isolate());
199 while (it.frame()->fp() != this->fp()) it.Advance();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 if (FLAG_ignition && it.frame()->type() == StackFrame::STUB) {
201 // Advance over bytecode handler frame.
202 // TODO(rmcilroy): Remove this once bytecode handlers don't need a frame.
203 it.Advance();
204 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
206 // Find the function on the stack and both the active code for the
207 // function and the original code.
208 JSFunction* function = frame->function();
209 return function->shared();
210}
211
212
213Code* IC::GetCode() const {
214 HandleScope scope(isolate());
215 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
216 Code* code = shared->code();
217 return code;
218}
219
220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221bool IC::AddressIsOptimizedCode() const {
222 Code* host =
223 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
224 return host->kind() == Code::OPTIMIZED_FUNCTION;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225}
226
227
228static void LookupForRead(LookupIterator* it) {
229 for (; it->IsFound(); it->Next()) {
230 switch (it->state()) {
231 case LookupIterator::NOT_FOUND:
232 case LookupIterator::TRANSITION:
233 UNREACHABLE();
234 case LookupIterator::JSPROXY:
235 return;
236 case LookupIterator::INTERCEPTOR: {
237 // If there is a getter, return; otherwise loop to perform the lookup.
238 Handle<JSObject> holder = it->GetHolder<JSObject>();
239 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
240 return;
241 }
242 break;
243 }
244 case LookupIterator::ACCESS_CHECK:
245 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
246 // access checks for global proxies.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 break;
249 }
250 return;
251 case LookupIterator::ACCESSOR:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253 case LookupIterator::DATA:
254 return;
255 }
256 }
257}
258
259
260bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
261 Handle<String> name) {
262 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400265 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400267 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268
269 // The current map wasn't handled yet. There's no reason to stay monomorphic,
270 // *unless* we're moving from a deprecated map to its replacement, or
271 // to a more general elements kind.
272 // TODO(verwaest): Check if the current map is actually what the old map
273 // would transition to.
274 if (maybe_handler_.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 if (!receiver_map()->IsJSObjectMap()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 Map* first_map = FirstTargetMap();
277 if (first_map == NULL) return false;
278 Handle<Map> old_map(first_map);
279 if (old_map->is_deprecated()) return true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
281 receiver_map()->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 }
283
284 CacheHolderFlag flag;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286
287 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
288 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
289 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
290
291 if (state() == MONOMORPHIC) {
292 int index = ic_holder_map->IndexInCodeCache(*name, *target());
293 if (index >= 0) {
294 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
295 }
296 }
297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 if (receiver->IsJSGlobalObject()) {
299 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000300 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
301 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
302 if (!it.IsFound()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 return it.property_details().cell_type() == PropertyCellType::kConstant;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 }
305
306 return true;
307}
308
309
310bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
311 if (target()->is_keyed_stub()) {
312 // Determine whether the failure is due to a name failure.
313 if (!name->IsName()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400314 Name* stub_name =
315 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 if (*name != stub_name) return false;
317 }
318
319 return true;
320}
321
322
323void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 if (!name->IsString()) return;
326 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
327 if (receiver->IsUndefined() || receiver->IsNull()) return;
328
329 // Remove the target from the code cache if it became invalid
330 // because of changes in the prototype chain to avoid hitting it
331 // again.
332 if (TryRemoveInvalidPrototypeDependentStub(receiver,
333 Handle<String>::cast(name))) {
334 MarkPrototypeFailure(name);
335 return;
336 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337}
338
339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
341 Handle<Object> object, Handle<Object> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344}
345
346
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 THROW_NEW_ERROR(
350 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351}
352
353
354static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
355 int* polymorphic_delta,
356 int* generic_delta) {
357 switch (old_state) {
358 case UNINITIALIZED:
359 case PREMONOMORPHIC:
360 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
361 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
362 *polymorphic_delta = 1;
363 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
364 *generic_delta = 1;
365 }
366 break;
367 case MONOMORPHIC:
368 case POLYMORPHIC:
369 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
370 *polymorphic_delta = -1;
371 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
372 *generic_delta = 1;
373 }
374 break;
375 case MEGAMORPHIC:
376 case GENERIC:
377 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
378 *generic_delta = -1;
379 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
380 *polymorphic_delta = 1;
381 }
382 break;
383 case PROTOTYPE_FAILURE:
384 case DEBUG_STUB:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 UNREACHABLE();
386 }
387}
388
389
390void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
391 State old_state, State new_state,
392 bool target_remains_ic_stub) {
393 Code* host =
394 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
395 if (host->kind() != Code::FUNCTION) return;
396
397 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
398 // Not all Code objects have TypeFeedbackInfo.
399 host->type_feedback_info()->IsTypeFeedbackInfo()) {
400 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
401 int generic_delta = 0; // "Generic" here includes megamorphic.
402 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
403 &generic_delta);
404 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
405 info->change_ic_with_type_info_count(polymorphic_delta);
406 info->change_ic_generic_count(generic_delta);
407 }
408 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
409 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
410 info->change_own_type_change_checksum();
411 }
412 host->set_profiler_ticks(0);
413 isolate->runtime_profiler()->NotifyICChanged();
414 // TODO(2029): When an optimized function is patched, it would
415 // be nice to propagate the corresponding type information to its
416 // unoptimized version for the benefit of later inlining.
417}
418
419
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400420// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422 if (host->kind() != Code::FUNCTION) return;
423
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400424 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
425 info->change_own_type_change_checksum();
426 host->set_profiler_ticks(0);
427 isolate->runtime_profiler()->NotifyICChanged();
428 // TODO(2029): When an optimized function is patched, it would
429 // be nice to propagate the corresponding type information to its
430 // unoptimized version for the benefit of later inlining.
431}
432
433
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434void IC::PostPatching(Address address, Code* target, Code* old_target) {
435 // Type vector based ICs update these statistics at a different time because
436 // they don't always patch on state change.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437 if (ICUseVector(target->kind())) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438
439 Isolate* isolate = target->GetHeap()->isolate();
440 State old_state = UNINITIALIZED;
441 State new_state = UNINITIALIZED;
442 bool target_remains_ic_stub = false;
443 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
444 old_state = old_target->ic_state();
445 new_state = target->ic_state();
446 target_remains_ic_stub = true;
447 }
448
449 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
450 target_remains_ic_stub);
451}
452
453
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000455 Code* target = GetTargetAtAddress(address, constant_pool);
456
457 // Don't clear debug break inline cache as it will remove the break point.
458 if (target->is_debug_stub()) return;
459
460 switch (target->kind()) {
461 case Code::LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 case Code::KEYED_LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 case Code::STORE_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 case Code::KEYED_STORE_IC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 case Code::COMPARE_IC:
467 return CompareIC::Clear(isolate, address, target, constant_pool);
468 case Code::COMPARE_NIL_IC:
469 return CompareNilIC::Clear(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
1109 // code
1110 // cache. We are also guarding against installing code with flags that don't
1111 // match the desired CacheHolderFlag computed above, which would lead to
1112 // invalid lookups later.
1113 if (code->type() != Code::NORMAL &&
1114 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1115 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1116 }
1117
1118 return code;
1119}
1120
1121
1122Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1123 Handle<Object> unused,
1124 CacheHolderFlag cache_holder) {
1125 Handle<Object> receiver = lookup->GetReceiver();
1126 if (receiver->IsString() &&
1127 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1128 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1129 return SimpleFieldLoad(index);
1130 }
1131
1132 if (receiver->IsStringWrapper() &&
1133 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1134 StringLengthStub string_length_stub(isolate());
1135 return string_length_stub.GetCode();
1136 }
1137
1138 // Use specialized code for getting prototype of functions.
1139 if (receiver->IsJSFunction() &&
1140 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001141 receiver->IsConstructor() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 !Handle<JSFunction>::cast(receiver)
1143 ->map()
1144 ->has_non_instance_prototype()) {
1145 Handle<Code> stub;
1146 FunctionPrototypeStub function_prototype_stub(isolate());
1147 return function_prototype_stub.GetCode();
1148 }
1149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001150 Handle<Map> map = receiver_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1152 bool receiver_is_holder = receiver.is_identical_to(holder);
1153 switch (lookup->state()) {
1154 case LookupIterator::INTERCEPTOR: {
1155 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1158 // the original iterator will be used to fetch the value.
1159 LookupIterator it = *lookup;
1160 it.Next();
1161 LookupForRead(&it);
1162 return compiler.CompileLoadInterceptor(&it);
1163 }
1164
1165 case LookupIterator::ACCESSOR: {
1166 // Use simple field loads for some well-known callback properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167 // The method will only return true for absolute truths based on the
1168 // receiver maps.
1169 int object_offset;
1170 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1171 &object_offset)) {
1172 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1173 return SimpleFieldLoad(index);
1174 }
1175 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
1176 &object_offset)) {
1177 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1178 ArrayBufferViewLoadFieldStub stub(isolate(), index);
1179 return stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001180 }
1181
Ben Murdoch097c5b22016-05-18 11:27:45 +01001182 if (IsCompatibleReceiver(lookup, map)) {
1183 Handle<Object> accessors = lookup->GetAccessors();
1184 if (accessors->IsAccessorPair()) {
1185 if (!holder->HasFastProperties()) break;
1186 // When debugging we need to go the slow path to flood the accessor.
1187 if (GetSharedFunctionInfo()->HasDebugInfo()) break;
1188 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1189 isolate());
1190 CallOptimization call_optimization(getter);
1191 NamedLoadHandlerCompiler compiler(isolate(), map, holder,
1192 cache_holder);
1193 if (call_optimization.is_simple_api_call()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001194 return compiler.CompileLoadCallback(
1195 lookup->name(), call_optimization, lookup->GetAccessorIndex());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001196 }
1197 int expected_arguments = Handle<JSFunction>::cast(getter)
1198 ->shared()
1199 ->internal_formal_parameter_count();
1200 return compiler.CompileLoadViaGetter(
1201 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1202 } else if (accessors->IsAccessorInfo()) {
1203 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1204 if (v8::ToCData<Address>(info->getter()) == 0) break;
1205 if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206 // This case should be already handled in LoadIC::UpdateCaches.
1207 UNREACHABLE();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001208 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001210 if (!holder->HasFastProperties()) break;
1211 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());
1300 MapHandleList target_receiver_maps;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001301 TargetMaps(&target_receiver_maps);
1302
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
1312 // The first time a receiver is seen that is a transitioned version of the
1313 // previous monomorphic receiver type, assume the new ElementsKind is the
1314 // monomorphic type. This benefits global arrays that only transition
1315 // once, and all call sites accessing them are faster if they remain
1316 // monomorphic. If this optimistic assumption is not true, the IC will
1317 // miss again and it will become polymorphic and support both the
1318 // untransitioned and transitioned maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001319 if (state() == MONOMORPHIC && !receiver->IsString() &&
1320 IsMoreGeneralElementsKindTransition(
1321 target_receiver_maps.at(0)->elements_kind(),
1322 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001323 Handle<Code> handler =
1324 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1325 receiver_map, extra_ic_state());
1326 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1327 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 }
1329
1330 DCHECK(state() != GENERIC);
1331
1332 // Determine the list of receiver maps that this call site has seen,
1333 // adding the map that was just encountered.
1334 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1335 // If the miss wasn't due to an unseen map, a polymorphic stub
1336 // won't help, use the generic stub.
1337 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001338 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 }
1340
1341 // If the maximum number of receiver maps has been exceeded, use the generic
1342 // version of the IC.
1343 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1344 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001346 }
1347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001348 CodeHandleList handlers(target_receiver_maps.length());
1349 ElementHandlerCompiler compiler(isolate());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001350 compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
1352 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353}
1354
1355
1356MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1357 Handle<Object> key) {
1358 if (MigrateDeprecated(object)) {
1359 Handle<Object> result;
1360 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001361 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362 Object);
1363 return result;
1364 }
1365
1366 Handle<Object> load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001367 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368
1369 // Check for non-string values that can be converted into an
1370 // internalized string directly or is representable as a smi.
1371 key = TryConvertKey(key, isolate());
1372
1373 if (key->IsInternalizedString() || key->IsSymbol()) {
1374 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1375 LoadIC::Load(object, Handle<Name>::cast(key)),
1376 Object);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001377 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1378 !object->IsJSValue()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001379 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1380 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001382 }
1383 }
1384
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 DCHECK(UseVector());
1386 if (!is_vector_set() || stub.is_null()) {
1387 Code* generic = *megamorphic_stub();
1388 if (!stub.is_null() && *stub == generic) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001389 ConfigureVectorState(MEGAMORPHIC, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 TRACE_IC("LoadIC", key);
1394 }
1395
1396 if (!load_handle.is_null()) return load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 Handle<Object> result;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001399 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1400 Runtime::GetObjectProperty(isolate(), object, key),
1401 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001402 return result;
1403}
1404
1405
1406bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1407 JSReceiver::StoreFromKeyed store_mode) {
1408 // Disable ICs for non-JSObjects for now.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001409 Handle<Object> object = it->GetReceiver();
1410 if (!object->IsJSObject()) return false;
1411 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1412 DCHECK(!receiver->map()->is_deprecated());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413
1414 for (; it->IsFound(); it->Next()) {
1415 switch (it->state()) {
1416 case LookupIterator::NOT_FOUND:
1417 case LookupIterator::TRANSITION:
1418 UNREACHABLE();
1419 case LookupIterator::JSPROXY:
1420 return false;
1421 case LookupIterator::INTERCEPTOR: {
1422 Handle<JSObject> holder = it->GetHolder<JSObject>();
1423 InterceptorInfo* info = holder->GetNamedInterceptor();
1424 if (it->HolderIsReceiverOrHiddenPrototype()) {
1425 if (!info->setter()->IsUndefined()) return true;
1426 } else if (!info->getter()->IsUndefined() ||
1427 !info->query()->IsUndefined()) {
1428 return false;
1429 }
1430 break;
1431 }
1432 case LookupIterator::ACCESS_CHECK:
1433 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1434 break;
1435 case LookupIterator::ACCESSOR:
1436 return !it->IsReadOnly();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001437 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1438 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001439 case LookupIterator::DATA: {
1440 if (it->IsReadOnly()) return false;
1441 Handle<JSObject> holder = it->GetHolder<JSObject>();
1442 if (receiver.is_identical_to(holder)) {
1443 it->PrepareForDataProperty(value);
1444 // The previous receiver map might just have been deprecated,
1445 // so reload it.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 return true;
1448 }
1449
1450 // Receiver != holder.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451 if (receiver->IsJSGlobalProxy()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001452 PrototypeIterator iter(it->isolate(), receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001453 return it->GetHolder<Object>().is_identical_to(
1454 PrototypeIterator::GetCurrent(iter));
1455 }
1456
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457 if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1458
Ben Murdoch097c5b22016-05-18 11:27:45 +01001459 if (it->ExtendingNonExtensible(receiver)) return false;
1460 it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001461 return it->IsCacheableTransition();
1462 }
1463 }
1464 }
1465
Ben Murdoch097c5b22016-05-18 11:27:45 +01001466 receiver = it->GetStoreTarget();
1467 if (it->ExtendingNonExtensible(receiver)) return false;
1468 it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469 return it->IsCacheableTransition();
1470}
1471
1472
1473MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1474 Handle<Object> value,
1475 JSReceiver::StoreFromKeyed store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 // Check if the name is trivially convertible to an index and set the element.
1477 uint32_t index;
1478 if (kind() == Code::KEYED_STORE_IC && name->AsArrayIndex(&index)) {
1479 // Rewrite to the generic keyed store stub.
1480 if (FLAG_use_ic) {
1481 if (UseVector()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001482 ConfigureVectorState(MEGAMORPHIC, name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 } else if (!AddressIsDeoptimizedCode()) {
1484 set_target(*megamorphic_stub());
1485 }
1486 TRACE_IC("StoreIC", name);
1487 TRACE_GENERIC_IC(isolate(), "StoreIC", "name as array index");
1488 }
1489 Handle<Object> result;
1490 ASSIGN_RETURN_ON_EXCEPTION(
1491 isolate(), result,
1492 Object::SetElement(isolate(), object, index, value, language_mode()),
1493 Object);
1494 return result;
1495 }
1496
1497 if (object->IsJSGlobalObject() && name->IsString()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001498 // Look up in script context table.
1499 Handle<String> str_name = Handle<String>::cast(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001501 Handle<ScriptContextTable> script_contexts(
1502 global->native_context()->script_context_table());
1503
1504 ScriptContextTable::LookupResult lookup_result;
1505 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1506 Handle<Context> script_context = ScriptContextTable::GetContext(
1507 script_contexts, lookup_result.context_index);
1508 if (lookup_result.mode == CONST) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509 return TypeError(MessageTemplate::kConstAssign, object, name);
1510 }
1511
1512 Handle<Object> previous_value =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001513 FixedArray::get(*script_context, lookup_result.slot_index, isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514
1515 if (*previous_value == *isolate()->factory()->the_hole_value()) {
1516 // Do not install stubs and stay pre-monomorphic for
1517 // uninitialized accesses.
1518 return ReferenceError(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001519 }
1520
1521 if (FLAG_use_ic &&
1522 StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1523 StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1524 PatchCache(name, stub.GetCode());
1525 }
1526
1527 script_context->set(lookup_result.slot_index, *value);
1528 return value;
1529 }
1530 }
1531
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1533 // might deprecate the current map again, if value does not fit.
1534 if (MigrateDeprecated(object) || object->IsJSProxy()) {
1535 Handle<Object> result;
1536 ASSIGN_RETURN_ON_EXCEPTION(
1537 isolate(), result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001538 Object::SetProperty(object, name, value, language_mode()), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001539 return result;
1540 }
1541
1542 // If the object is undefined or null it's illegal to try to set any
1543 // properties on it; throw a TypeError in that case.
1544 if (object->IsUndefined() || object->IsNull()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546 }
1547
1548 // Observed objects are always modified through the runtime.
1549 if (object->IsHeapObject() &&
1550 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1551 Handle<Object> result;
1552 ASSIGN_RETURN_ON_EXCEPTION(
1553 isolate(), result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 Object::SetProperty(object, name, value, language_mode(), store_mode),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 Object);
1556 return result;
1557 }
1558
1559 LookupIterator it(object, name);
1560 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001562 MAYBE_RETURN_NULL(
1563 Object::SetProperty(&it, value, language_mode(), store_mode));
1564 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001565}
1566
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001568 ConvertReceiverMode mode,
1569 TailCallMode tail_call_mode) {
1570 CallICTrampolineStub stub(isolate, CallICState(argc, mode, tail_call_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 Handle<Code> code = stub.GetCode();
1572 return code;
1573}
1574
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575Handle<Code> CallIC::initialize_stub_in_optimized_code(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001576 Isolate* isolate, int argc, ConvertReceiverMode mode,
1577 TailCallMode tail_call_mode) {
1578 CallICStub stub(isolate, CallICState(argc, mode, tail_call_mode));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001579 Handle<Code> code = stub.GetCode();
1580 return code;
1581}
1582
1583
1584static Handle<Code> StoreICInitializeStubHelper(
1585 Isolate* isolate, ExtraICState extra_state,
1586 InlineCacheState initialization_state) {
1587 Handle<Code> ic = PropertyICCompiler::ComputeStore(
1588 isolate, initialization_state, extra_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 return ic;
1590}
1591
1592
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001593Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
1594 LanguageMode language_mode,
1595 State initialization_state) {
1596 DCHECK(initialization_state == UNINITIALIZED ||
1597 initialization_state == PREMONOMORPHIC ||
1598 initialization_state == MEGAMORPHIC);
1599 VectorStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
1600 return stub.GetCode();
1601}
1602
1603
1604Handle<Code> StoreIC::initialize_stub_in_optimized_code(
1605 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
1606 DCHECK(initialization_state == UNINITIALIZED ||
1607 initialization_state == PREMONOMORPHIC ||
1608 initialization_state == MEGAMORPHIC);
1609 if (initialization_state != MEGAMORPHIC) {
1610 VectorStoreICStub stub(isolate, StoreICState(language_mode));
1611 return stub.GetCode();
1612 }
1613
1614 return StoreICInitializeStubHelper(
1615 isolate, ComputeExtraICState(language_mode), initialization_state);
1616}
1617
1618
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001619Handle<Code> StoreIC::megamorphic_stub() {
1620 if (kind() == Code::STORE_IC) {
1621 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC,
1622 extra_ic_state());
1623 } else {
1624 DCHECK(kind() == Code::KEYED_STORE_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001625 if (is_strict(language_mode())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001626 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001628 return isolate()->builtins()->KeyedStoreIC_Megamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001629 }
1630 }
1631}
1632
1633
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001634Handle<Code> StoreIC::slow_stub() const {
1635 if (kind() == Code::STORE_IC) {
1636 return isolate()->builtins()->StoreIC_Slow();
1637 } else {
1638 DCHECK(kind() == Code::KEYED_STORE_IC);
1639 return isolate()->builtins()->KeyedStoreIC_Slow();
1640 }
1641}
1642
1643
1644Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 LanguageMode language_mode) {
1646 ExtraICState state = ComputeExtraICState(language_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001647 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1648}
1649
1650
1651void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1652 JSReceiver::StoreFromKeyed store_mode) {
1653 if (state() == UNINITIALIZED) {
1654 // This is the first time we execute this inline cache. Set the target to
1655 // the pre monomorphic stub to delay setting the monomorphic state.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001656 ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001657 TRACE_IC("StoreIC", lookup->name());
1658 return;
1659 }
1660
1661 bool use_ic = LookupForWrite(lookup, value, store_mode);
1662 if (!use_ic) {
1663 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
1664 }
1665 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
1666
1667 PatchCache(lookup->name(), code);
1668 TRACE_IC("StoreIC", lookup->name());
1669}
1670
1671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672static Handle<Code> PropertyCellStoreHandler(
1673 Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
1674 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
1675 auto constant_type = Nothing<PropertyCellConstantType>();
1676 if (type == PropertyCellType::kConstantType) {
1677 constant_type = Just(cell->GetConstantType());
1678 }
1679 StoreGlobalStub stub(isolate, type, constant_type,
1680 receiver->IsJSGlobalProxy());
1681 auto code = stub.GetCodeCopyFromTemplate(holder, cell);
1682 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1683 HeapObject::UpdateMapCodeCache(receiver, name, code);
1684 return code;
1685}
1686
1687
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001688Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1689 Handle<Object> value,
1690 CacheHolderFlag cache_holder) {
1691 DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1692
1693 // This is currently guaranteed by checks in StoreIC::Store.
1694 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1695 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001696 DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001697
1698 switch (lookup->state()) {
1699 case LookupIterator::TRANSITION: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001700 auto store_target = lookup->GetStoreTarget();
1701 if (store_target->IsJSGlobalObject()) {
1702 // TODO(dcarney): this currently just deopts. Use the transition cell.
1703 auto cell = isolate()->factory()->NewPropertyCell();
1704 cell->set_value(*value);
1705 auto code = PropertyCellStoreHandler(
1706 isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
1707 lookup->name(), cell, PropertyCellType::kConstant);
1708 cell->set_value(isolate()->heap()->the_hole_value());
1709 return code;
1710 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001711 Handle<Map> transition = lookup->transition_map();
1712 // Currently not handled by CompileStoreTransition.
1713 if (!holder->HasFastProperties()) {
1714 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1715 break;
1716 }
1717
1718 DCHECK(lookup->IsCacheableTransition());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001719 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 return compiler.CompileStoreTransition(transition, lookup->name());
1721 }
1722
1723 case LookupIterator::INTERCEPTOR: {
1724 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001725 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001726 return compiler.CompileStoreInterceptor(lookup->name());
1727 }
1728
1729 case LookupIterator::ACCESSOR: {
1730 if (!holder->HasFastProperties()) {
1731 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1732 break;
1733 }
1734 Handle<Object> accessors = lookup->GetAccessors();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001735 if (accessors->IsAccessorInfo()) {
1736 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 if (v8::ToCData<Address>(info->setter()) == 0) {
1738 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1739 break;
1740 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001741 if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1742 !lookup->HolderIsReceiverOrHiddenPrototype()) {
1743 TRACE_GENERIC_IC(isolate(), "StoreIC",
1744 "special data property in prototype chain");
1745 break;
1746 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001747 if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1748 receiver_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001749 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1750 break;
1751 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001753 return compiler.CompileStoreCallback(receiver, lookup->name(), info,
1754 language_mode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001755 } else if (accessors->IsAccessorPair()) {
1756 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1757 isolate());
1758 if (!setter->IsJSFunction()) {
1759 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1760 break;
1761 }
1762 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1763 CallOptimization call_optimization(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001764 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001765 if (call_optimization.is_simple_api_call() &&
1766 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1767 return compiler.CompileStoreCallback(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001768 call_optimization,
1769 lookup->GetAccessorIndex());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001770 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001771 int expected_arguments =
1772 function->shared()->internal_formal_parameter_count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001774 lookup->GetAccessorIndex(),
1775 expected_arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777 break;
1778 }
1779
1780 case LookupIterator::DATA: {
1781 if (lookup->is_dictionary_holder()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001782 if (holder->IsJSGlobalObject()) {
1783 DCHECK(holder.is_identical_to(receiver) ||
1784 receiver->map()->prototype() == *holder);
1785 auto cell = lookup->GetPropertyCell();
1786 auto updated_type = PropertyCell::UpdatedType(
1787 cell, value, lookup->property_details());
1788 auto code = PropertyCellStoreHandler(
1789 isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
1790 lookup->name(), cell, updated_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001791 return code;
1792 }
1793 DCHECK(holder.is_identical_to(receiver));
1794 return isolate()->builtins()->StoreIC_Normal();
1795 }
1796
1797 // -------------- Fields --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001798 if (lookup->property_details().type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001799 bool use_stub = true;
1800 if (lookup->representation().IsHeapObject()) {
1801 // Only use a generic stub if no types need to be tracked.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001802 Handle<FieldType> field_type = lookup->GetFieldType();
1803 use_stub = !field_type->IsClass();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001804 }
1805 if (use_stub) {
1806 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1807 lookup->representation());
1808 return stub.GetCode();
1809 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001810 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001811 return compiler.CompileStoreField(lookup);
1812 }
1813
1814 // -------------- Constant properties --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001815 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001816 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1817 break;
1818 }
1819
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001821 case LookupIterator::ACCESS_CHECK:
1822 case LookupIterator::JSPROXY:
1823 case LookupIterator::NOT_FOUND:
1824 UNREACHABLE();
1825 }
1826 return slow_stub();
1827}
1828
1829
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001830Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831 KeyedAccessStoreMode store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832 Handle<Code> null_handle;
1833 // Don't handle megamorphic property accesses for INTERCEPTORS or
1834 // ACCESSOR_CONSTANT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 // via megamorphic stubs, since they don't have a map in their relocation info
1836 // and so the stubs can't be harvested for the object needed for a map check.
1837 if (target()->type() != Code::NORMAL) {
1838 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840 }
1841
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 MapHandleList target_receiver_maps;
1843 TargetMaps(&target_receiver_maps);
1844 if (target_receiver_maps.length() == 0) {
1845 Handle<Map> monomorphic_map =
1846 ComputeTransitionedMap(receiver_map, store_mode);
1847 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001848 Handle<Code> handler =
1849 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1850 monomorphic_map, language_mode(), store_mode);
1851 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler);
1852 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001853 }
1854
1855 // There are several special cases where an IC that is MONOMORPHIC can still
1856 // transition to a different GetNonTransitioningStoreMode IC that handles a
1857 // superset of the original IC. Handle those here if the receiver map hasn't
1858 // changed or it has transitioned to a more general kind.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001859 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001860 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1861 if (state() == MONOMORPHIC) {
1862 Handle<Map> transitioned_receiver_map = receiver_map;
1863 if (IsTransitionStoreMode(store_mode)) {
1864 transitioned_receiver_map =
1865 ComputeTransitionedMap(receiver_map, store_mode);
1866 }
1867 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1868 IsTransitionStoreMode(store_mode)) ||
1869 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1870 *transitioned_receiver_map)) {
1871 // If the "old" and "new" maps are in the same elements map family, or
1872 // if they at least come from the same origin for a transitioning store,
1873 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1874 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001875 Handle<Code> handler =
1876 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1877 transitioned_receiver_map, language_mode(), store_mode);
1878 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map,
1879 handler);
1880 return null_handle;
1881 } else if (receiver_map.is_identical_to(previous_receiver_map) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 old_store_mode == STANDARD_STORE &&
1883 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1884 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1885 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1886 // A "normal" IC that handles stores can switch to a version that can
1887 // grow at the end of the array, handle OOB accesses or copy COW arrays
1888 // and still stay MONOMORPHIC.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889 Handle<Code> handler =
1890 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1891 receiver_map, language_mode(), store_mode);
1892 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1893 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001894 }
1895 }
1896
1897 DCHECK(state() != GENERIC);
1898
1899 bool map_added =
1900 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1901
1902 if (IsTransitionStoreMode(store_mode)) {
1903 Handle<Map> transitioned_receiver_map =
1904 ComputeTransitionedMap(receiver_map, store_mode);
1905 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1906 transitioned_receiver_map);
1907 }
1908
1909 if (!map_added) {
1910 // If the miss wasn't due to an unseen map, a polymorphic stub
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001911 // won't help, use the megamorphic stub which can handle everything.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001912 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001913 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914 }
1915
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001916 // If the maximum number of receiver maps has been exceeded, use the
1917 // megamorphic version of the IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001919 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 }
1921
1922 // Make sure all polymorphic handlers have the same store mode, otherwise the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001923 // megamorphic stub must be used.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001924 store_mode = GetNonTransitioningStoreMode(store_mode);
1925 if (old_store_mode != STANDARD_STORE) {
1926 if (store_mode == STANDARD_STORE) {
1927 store_mode = old_store_mode;
1928 } else if (store_mode != old_store_mode) {
1929 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001930 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001931 }
1932 }
1933
1934 // If the store mode isn't the standard mode, make sure that all polymorphic
1935 // receivers are either external arrays, or all "normal" arrays. Otherwise,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001936 // use the megamorphic stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937 if (store_mode != STANDARD_STORE) {
1938 int external_arrays = 0;
1939 for (int i = 0; i < target_receiver_maps.length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001940 if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001941 external_arrays++;
1942 }
1943 }
1944 if (external_arrays != 0 &&
1945 external_arrays != target_receiver_maps.length()) {
1946 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1947 "unsupported combination of external and normal arrays");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001948 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001949 }
1950 }
1951
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952 MapHandleList transitioned_maps(target_receiver_maps.length());
1953 CodeHandleList handlers(target_receiver_maps.length());
1954 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
1955 &target_receiver_maps, &transitioned_maps, &handlers, store_mode,
1956 language_mode());
1957 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
1958 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959}
1960
1961
1962Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1963 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1964 switch (store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001965 case STORE_TRANSITION_TO_OBJECT:
1966 case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1967 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1968 ? FAST_HOLEY_ELEMENTS
1969 : FAST_ELEMENTS;
1970 return Map::TransitionElementsTo(map, kind);
1971 }
1972 case STORE_TRANSITION_TO_DOUBLE:
1973 case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1974 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1975 ? FAST_HOLEY_DOUBLE_ELEMENTS
1976 : FAST_DOUBLE_ELEMENTS;
1977 return Map::TransitionElementsTo(map, kind);
1978 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001979 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001980 DCHECK(map->has_fixed_typed_array_elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981 // Fall through
1982 case STORE_NO_TRANSITION_HANDLE_COW:
1983 case STANDARD_STORE:
1984 case STORE_AND_GROW_NO_TRANSITION:
1985 return map;
1986 }
1987 UNREACHABLE();
1988 return MaybeHandle<Map>().ToHandleChecked();
1989}
1990
1991
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001992bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
1993 uint32_t length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001994 if (receiver->IsJSArray()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1996 } else {
1997 length = static_cast<uint32_t>(receiver->elements()->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001998 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001999 return index >= length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000}
2001
2002
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002003static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2004 uint32_t index, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002005 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2006 // Don't consider this a growing store if the store would send the receiver to
2007 // dictionary mode.
2008 bool allow_growth = receiver->IsJSArray() && oob_access &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002009 !receiver->WouldConvertToSlowElements(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002010 if (allow_growth) {
2011 // Handle growing array in stub if necessary.
2012 if (receiver->HasFastSmiElements()) {
2013 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002014 return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015 }
2016 if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002017 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002018 }
2019 } else if (receiver->HasFastDoubleElements()) {
2020 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002021 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002022 }
2023 }
2024 return STORE_AND_GROW_NO_TRANSITION;
2025 } else {
2026 // Handle only in-bounds elements accesses.
2027 if (receiver->HasFastSmiElements()) {
2028 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002029 return STORE_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002030 } else if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002031 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002032 }
2033 } else if (receiver->HasFastDoubleElements()) {
2034 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002035 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002036 }
2037 }
2038 if (!FLAG_trace_external_array_abuse &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002039 receiver->map()->has_fixed_typed_array_elements() && oob_access) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002040 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2041 }
2042 Heap* heap = receiver->GetHeap();
2043 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2044 return STORE_NO_TRANSITION_HANDLE_COW;
2045 } else {
2046 return STANDARD_STORE;
2047 }
2048 }
2049}
2050
2051
2052MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2053 Handle<Object> key,
2054 Handle<Object> value) {
2055 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2056 // might deprecate the current map again, if value does not fit.
2057 if (MigrateDeprecated(object)) {
2058 Handle<Object> result;
2059 ASSIGN_RETURN_ON_EXCEPTION(
2060 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002061 value, language_mode()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 Object);
2063 return result;
2064 }
2065
2066 // Check for non-string values that can be converted into an
2067 // internalized string directly or is representable as a smi.
2068 key = TryConvertKey(key, isolate());
2069
2070 Handle<Object> store_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002071 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002072
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002073 uint32_t index;
2074 if ((key->IsInternalizedString() &&
2075 !String::cast(*key)->AsArrayIndex(&index)) ||
2076 key->IsSymbol()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002077 ASSIGN_RETURN_ON_EXCEPTION(
2078 isolate(), store_handle,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002079 StoreIC::Store(object, Handle<Name>::cast(key), value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002080 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2081 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002082 if (!is_vector_set()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002083 ConfigureVectorState(MEGAMORPHIC, key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002084 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2085 "unhandled internalized string key");
2086 TRACE_IC("StoreIC", key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002087 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002088 return store_handle;
2089 }
2090
2091 bool use_ic =
2092 FLAG_use_ic && !object->IsStringWrapper() &&
2093 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2094 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2095 if (use_ic && !object->IsSmi()) {
2096 // Don't use ICs for maps of the objects in Array's prototype chain. We
2097 // expect to be able to trap element sets to objects with those maps in
2098 // the runtime to enable optimization of element hole access.
2099 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2100 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2101 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2102 use_ic = false;
2103 }
2104 }
2105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002106 Handle<Map> old_receiver_map;
2107 bool sloppy_arguments_elements = false;
2108 bool key_is_valid_index = false;
2109 KeyedAccessStoreMode store_mode = STANDARD_STORE;
2110 if (use_ic && object->IsJSObject()) {
2111 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2112 old_receiver_map = handle(receiver->map(), isolate());
2113 sloppy_arguments_elements =
2114 !is_sloppy(language_mode()) &&
2115 receiver->elements()->map() ==
2116 isolate()->heap()->sloppy_arguments_elements_map();
2117 if (!sloppy_arguments_elements) {
2118 key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
2119 if (key_is_valid_index) {
2120 uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2121 store_mode = GetStoreMode(receiver, index, value);
2122 }
2123 }
2124 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002126 DCHECK(store_handle.is_null());
2127 ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2128 Runtime::SetObjectProperty(isolate(), object, key,
2129 value, language_mode()),
2130 Object);
2131
2132 if (use_ic) {
2133 if (!old_receiver_map.is_null()) {
2134 if (sloppy_arguments_elements) {
2135 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2136 } else if (key_is_valid_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002137 // We should go generic if receiver isn't a dictionary, but our
2138 // prototype chain does have dictionary elements. This ensures that
2139 // other non-dictionary receivers in the polymorphic case benefit
2140 // from fast path keyed stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002141 if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2142 stub = StoreElementStub(old_receiver_map, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002143 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2145 "dictionary or proxy prototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146 }
2147 } else {
2148 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2149 }
2150 } else {
2151 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2152 }
2153 }
2154
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002155 if (!is_vector_set() || stub.is_null()) {
2156 Code* megamorphic = *megamorphic_stub();
2157 if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002158 ConfigureVectorState(MEGAMORPHIC, key);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002159 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2160 *stub == megamorphic ? "set generic" : "slow stub");
2161 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002162 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 TRACE_IC("StoreIC", key);
2164
2165 return store_handle;
2166}
2167
2168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002169void CallIC::HandleMiss(Handle<Object> function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002170 Handle<Object> name = isolate()->factory()->empty_string();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002171 CallICNexus* nexus = casted_nexus<CallICNexus>();
2172 Object* feedback = nexus->GetFeedback();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002173
2174 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2175 DCHECK(!feedback->IsSmi());
2176
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002177 if (feedback->IsWeakCell() || !function->IsJSFunction() ||
2178 feedback->IsAllocationSite()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002179 // We are going generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002180 nexus->ConfigureMegamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002181 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002182 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
2183 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002184
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002185 Handle<JSFunction> array_function =
2186 Handle<JSFunction>(isolate()->native_context()->array_function());
2187 if (array_function.is_identical_to(js_function)) {
2188 // Alter the slot.
2189 nexus->ConfigureMonomorphicArray();
2190 } else if (js_function->context()->native_context() !=
2191 *isolate()->native_context()) {
2192 // Don't collect cross-native context feedback for the CallIC.
2193 // TODO(bmeurer): We should collect the SharedFunctionInfo as
2194 // feedback in this case instead.
2195 nexus->ConfigureMegamorphic();
2196 } else {
2197 nexus->ConfigureMonomorphic(js_function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002198 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002199 }
2200
2201 if (function->IsJSFunction()) {
2202 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2203 name = handle(js_function->shared()->name(), isolate());
2204 }
2205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002206 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002207 TRACE_IC("CallIC", name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002208}
2209
2210
2211#undef TRACE_IC
2212
2213
2214// ----------------------------------------------------------------------------
2215// Static IC stub generators.
2216//
2217
2218// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002219RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002220 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002221 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002223 DCHECK(args.length() == 3);
2224 Handle<Object> function = args.at<Object>(0);
2225 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2226 Handle<Smi> slot = args.at<Smi>(2);
2227 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002228 CallICNexus nexus(vector, vector_slot);
2229 CallIC ic(isolate, &nexus);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002230 ic.HandleMiss(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002231 return *function;
2232}
2233
2234
2235// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002236RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002237 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002238 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002239 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002240 Handle<Object> receiver = args.at<Object>(0);
2241 Handle<Name> key = args.at<Name>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002242 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002244 DCHECK(args.length() == 4);
2245 Handle<Smi> slot = args.at<Smi>(2);
2246 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2247 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2248 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2249 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2250 // set up outside the IC, handle that here.
2251 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
2252 LoadICNexus nexus(vector, vector_slot);
2253 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2254 ic.UpdateState(receiver, key);
2255 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002256 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002257 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
2258 vector->GetKind(vector_slot));
2259 KeyedLoadICNexus nexus(vector, vector_slot);
2260 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002261 ic.UpdateState(receiver, key);
2262 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2263 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002264 return *result;
2265}
2266
2267
2268// Used from ic-<arch>.cc
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002269RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002270 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002271 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002272 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273 Handle<Object> receiver = args.at<Object>(0);
2274 Handle<Object> key = args.at<Object>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002275 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002277 DCHECK(args.length() == 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002278 Handle<Smi> slot = args.at<Smi>(2);
2279 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2280 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2281 KeyedLoadICNexus nexus(vector, vector_slot);
2282 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2283 ic.UpdateState(receiver, key);
2284 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2285 return *result;
2286}
2287
2288
2289RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
2290 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002291 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002292 HandleScope scope(isolate);
2293 Handle<Object> receiver = args.at<Object>(0);
2294 Handle<Object> key = args.at<Object>(1);
2295 Handle<Object> result;
2296
2297 DCHECK(args.length() == 4);
2298 Handle<Smi> slot = args.at<Smi>(2);
2299 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2300 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2301 KeyedLoadICNexus nexus(vector, vector_slot);
2302 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2303 ic.UpdateState(receiver, key);
2304 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2305
2306 return *result;
2307}
2308
2309
2310// Used from ic-<arch>.cc.
2311RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2312 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002313 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002314 HandleScope scope(isolate);
2315 Handle<Object> receiver = args.at<Object>(0);
2316 Handle<Name> key = args.at<Name>(1);
2317 Handle<Object> value = args.at<Object>(2);
2318 Handle<Object> result;
2319
2320 DCHECK(args.length() == 5 || args.length() == 6);
2321 Handle<Smi> slot = args.at<Smi>(3);
2322 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2323 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2324 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2325 StoreICNexus nexus(vector, vector_slot);
2326 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2327 ic.UpdateState(receiver, key);
2328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2329 ic.Store(receiver, key, value));
2330 } else {
2331 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2332 vector->GetKind(vector_slot));
2333 KeyedStoreICNexus nexus(vector, vector_slot);
2334 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2335 ic.UpdateState(receiver, key);
2336 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2337 ic.Store(receiver, key, value));
2338 }
2339 return *result;
2340}
2341
2342
2343RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
2344 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002345 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002346 HandleScope scope(isolate);
2347 Handle<Object> receiver = args.at<Object>(0);
2348 Handle<Name> key = args.at<Name>(1);
2349 Handle<Object> value = args.at<Object>(2);
2350 Handle<Object> result;
2351
2352 int length = args.length();
2353 DCHECK(length == 5 || length == 6);
2354 // We might have slot and vector, for a normal miss (slot(3), vector(4)).
2355 // Or, map and vector for a transitioning store miss (map(3), vector(4)).
2356 // In this case, we need to recover the slot from a virtual register.
2357 // If length == 6, then a map is included (map(3), slot(4), vector(5)).
2358 Handle<Smi> slot;
2359 Handle<TypeFeedbackVector> vector;
2360 if (length == 5) {
2361 if (args.at<Object>(3)->IsMap()) {
2362 vector = args.at<TypeFeedbackVector>(4);
2363 slot = handle(
2364 *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()),
2365 isolate);
2366 } else {
2367 vector = args.at<TypeFeedbackVector>(4);
2368 slot = args.at<Smi>(3);
2369 }
2370 } else {
2371 vector = args.at<TypeFeedbackVector>(5);
2372 slot = args.at<Smi>(4);
2373 }
2374
2375 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2376 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2377 StoreICNexus nexus(vector, vector_slot);
2378 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2379 ic.UpdateState(receiver, key);
2380 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2381 ic.Store(receiver, key, value));
2382 } else {
2383 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2384 vector->GetKind(vector_slot));
2385 KeyedStoreICNexus nexus(vector, vector_slot);
2386 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2387 ic.UpdateState(receiver, key);
2388 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2389 ic.Store(receiver, key, value));
2390 }
2391 return *result;
2392}
2393
2394
2395// Used from ic-<arch>.cc.
2396RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2397 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002398 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002399 HandleScope scope(isolate);
2400 Handle<Object> receiver = args.at<Object>(0);
2401 Handle<Object> key = args.at<Object>(1);
2402 Handle<Object> value = args.at<Object>(2);
2403 Handle<Object> result;
2404
2405 DCHECK(args.length() == 5);
2406 Handle<Smi> slot = args.at<Smi>(3);
2407 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2408 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2409 KeyedStoreICNexus nexus(vector, vector_slot);
2410 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2411 ic.UpdateState(receiver, key);
2412 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2413 ic.Store(receiver, key, value));
2414 return *result;
2415}
2416
2417
2418RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) {
2419 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002420 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002421 HandleScope scope(isolate);
2422 Handle<Object> receiver = args.at<Object>(0);
2423 Handle<Object> key = args.at<Object>(1);
2424 Handle<Object> value = args.at<Object>(2);
2425 Handle<Object> result;
2426
2427 DCHECK(args.length() == 5);
2428 Handle<Smi> slot = args.at<Smi>(3);
2429 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2430 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2431 KeyedStoreICNexus nexus(vector, vector_slot);
2432 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2433 ic.UpdateState(receiver, key);
2434 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2435 ic.Store(receiver, key, value));
2436 return *result;
2437}
2438
2439
2440RUNTIME_FUNCTION(Runtime_StoreIC_Slow) {
2441 HandleScope scope(isolate);
2442 DCHECK(args.length() == 5);
2443 Handle<Object> object = args.at<Object>(0);
2444 Handle<Object> key = args.at<Object>(1);
2445 Handle<Object> value = args.at<Object>(2);
2446 LanguageMode language_mode;
2447 StoreICNexus nexus(isolate);
2448 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2449 language_mode = ic.language_mode();
2450 Handle<Object> result;
2451 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2452 isolate, result,
2453 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2454 return *result;
2455}
2456
2457
2458RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2459 HandleScope scope(isolate);
2460 DCHECK(args.length() == 5);
2461 Handle<Object> object = args.at<Object>(0);
2462 Handle<Object> key = args.at<Object>(1);
2463 Handle<Object> value = args.at<Object>(2);
2464 LanguageMode language_mode;
2465 KeyedStoreICNexus nexus(isolate);
2466 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2467 language_mode = ic.language_mode();
2468 Handle<Object> result;
2469 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2470 isolate, result,
2471 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2472 return *result;
2473}
2474
2475
2476RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2477 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002478 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002479 HandleScope scope(isolate);
2480 // Length == 5 or 6, depending on whether the vector slot
2481 // is passed in a virtual register or not.
2482 DCHECK(args.length() == 5 || args.length() == 6);
2483 Handle<Object> object = args.at<Object>(0);
2484 Handle<Object> key = args.at<Object>(1);
2485 Handle<Object> value = args.at<Object>(2);
2486 Handle<Map> map = args.at<Map>(3);
2487 LanguageMode language_mode;
2488 KeyedStoreICNexus nexus(isolate);
2489 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2490 language_mode = ic.language_mode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002491 if (object->IsJSObject()) {
2492 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2493 map->elements_kind());
2494 }
2495 Handle<Object> result;
2496 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2497 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002499 return *result;
2500}
2501
2502
2503MaybeHandle<Object> BinaryOpIC::Transition(
2504 Handle<AllocationSite> allocation_site, Handle<Object> left,
2505 Handle<Object> right) {
2506 BinaryOpICState state(isolate(), target()->extra_ic_state());
2507
2508 // Compute the actual result using the builtin for the binary operation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002509 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002510 switch (state.op()) {
2511 default:
2512 UNREACHABLE();
2513 case Token::ADD:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002514 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2515 Object::Add(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002516 break;
2517 case Token::SUB:
2518 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002519 isolate(), result, Object::Subtract(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002520 break;
2521 case Token::MUL:
2522 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002523 isolate(), result, Object::Multiply(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002524 break;
2525 case Token::DIV:
2526 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002527 isolate(), result, Object::Divide(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002528 break;
2529 case Token::MOD:
2530 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002531 isolate(), result, Object::Modulus(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002532 break;
2533 case Token::BIT_OR:
2534 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002535 isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002536 break;
2537 case Token::BIT_AND:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002538 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2539 Object::BitwiseAnd(isolate(), left, right),
2540 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002541 break;
2542 case Token::BIT_XOR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002543 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2544 Object::BitwiseXor(isolate(), left, right),
2545 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002546 break;
2547 case Token::SAR:
Ben Murdoch097c5b22016-05-18 11:27:45 +01002548 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2549 Object::ShiftRight(isolate(), left, right),
2550 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002551 break;
2552 case Token::SHR:
2553 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002554 isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002555 Object);
2556 break;
2557 case Token::SHL:
2558 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002559 isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002560 break;
2561 }
2562
2563 // Do not try to update the target if the code was marked for lazy
2564 // deoptimization. (Since we do not relocate addresses in these
2565 // code objects, an attempt to access the target could fail.)
2566 if (AddressIsDeoptimizedCode()) {
2567 return result;
2568 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002569
2570 // Execution::Call can execute arbitrary JavaScript, hence potentially
2571 // update the state of this very IC, so we must update the stored state.
2572 UpdateTarget();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002573
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002574 // Compute the new state.
2575 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2576 state.Update(left, right, result);
2577
2578 // Check if we have a string operation here.
2579 Handle<Code> target;
2580 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2581 // Setup the allocation site on-demand.
2582 if (allocation_site.is_null()) {
2583 allocation_site = isolate()->factory()->NewAllocationSite();
2584 }
2585
2586 // Install the stub with an allocation site.
2587 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2588 target = stub.GetCodeCopyFromTemplate(allocation_site);
2589
2590 // Sanity check the trampoline stub.
2591 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2592 } else {
2593 // Install the generic stub.
2594 BinaryOpICStub stub(isolate(), state);
2595 target = stub.GetCode();
2596
2597 // Sanity check the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002598 DCHECK_NULL(target->FindFirstAllocationSite());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002599 }
2600 set_target(*target);
2601
2602 if (FLAG_trace_ic) {
2603 OFStream os(stdout);
2604 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2605 << static_cast<void*>(*target) << " <- ";
2606 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2607 if (!allocation_site.is_null()) {
2608 os << " using allocation site " << static_cast<void*>(*allocation_site);
2609 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002610 os << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002611 }
2612
2613 // Patch the inlined smi code as necessary.
2614 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002615 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002617 PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002618 }
2619
2620 return result;
2621}
2622
2623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002624RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002626 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002627 HandleScope scope(isolate);
2628 DCHECK_EQ(2, args.length());
2629 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
2630 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
2631 BinaryOpIC ic(isolate);
2632 Handle<Object> result;
2633 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2634 isolate, result,
2635 ic.Transition(Handle<AllocationSite>::null(), left, right));
2636 return *result;
2637}
2638
2639
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002640RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002641 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002642 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002643 HandleScope scope(isolate);
2644 DCHECK_EQ(3, args.length());
2645 Handle<AllocationSite> allocation_site =
2646 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2647 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2648 Handle<Object> right =
2649 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2650 BinaryOpIC ic(isolate);
2651 Handle<Object> result;
2652 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2653 isolate, result, ic.Transition(allocation_site, left, right));
2654 return *result;
2655}
2656
Ben Murdoch097c5b22016-05-18 11:27:45 +01002657Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2658 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002659 CompareICState::UNINITIALIZED,
2660 CompareICState::UNINITIALIZED);
2661 Code* code = NULL;
2662 CHECK(stub.FindCodeInCache(&code));
2663 return code;
2664}
2665
Ben Murdoch097c5b22016-05-18 11:27:45 +01002666Handle<Code> CompareIC::GetUninitialized(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 return stub.GetCode();
2671}
2672
2673
2674Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2675 HandleScope scope(isolate());
2676 CompareICStub old_stub(target()->stub_key(), isolate());
2677 CompareICState::State new_left =
2678 CompareICState::NewInputState(old_stub.left(), x);
2679 CompareICState::State new_right =
2680 CompareICState::NewInputState(old_stub.right(), y);
2681 CompareICState::State state = CompareICState::TargetState(
2682 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2683 HasInlinedSmiCode(address()), x, y);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002684 CompareICStub stub(isolate(), op_, new_left, new_right, state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002685 if (state == CompareICState::KNOWN_RECEIVER) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002686 stub.set_known_map(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002687 Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002688 }
2689 Handle<Code> new_target = stub.GetCode();
2690 set_target(*new_target);
2691
2692 if (FLAG_trace_ic) {
2693 PrintF("[CompareIC in ");
2694 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2695 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2696 CompareICState::GetStateName(old_stub.left()),
2697 CompareICState::GetStateName(old_stub.right()),
2698 CompareICState::GetStateName(old_stub.state()),
2699 CompareICState::GetStateName(new_left),
2700 CompareICState::GetStateName(new_right),
2701 CompareICState::GetStateName(state), Token::Name(op_),
2702 static_cast<void*>(*stub.GetCode()));
2703 }
2704
2705 // Activate inlined smi code.
2706 if (old_stub.state() == CompareICState::UNINITIALIZED) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002707 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002708 }
2709
2710 return *new_target;
2711}
2712
2713
2714// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002715RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002716 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002717 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002718 HandleScope scope(isolate);
2719 DCHECK(args.length() == 3);
2720 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2721 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2722}
2723
2724
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002725void CompareNilIC::Clear(Address address, Code* target, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002726 if (IsCleared(target)) return;
2727 ExtraICState state = target->extra_ic_state();
2728
2729 CompareNilICStub stub(target->GetIsolate(), state,
2730 HydrogenCodeStub::UNINITIALIZED);
2731 stub.ClearState();
2732
2733 Code* code = NULL;
2734 CHECK(stub.FindCodeInCache(&code));
2735
2736 SetTargetAtAddress(address, code, constant_pool);
2737}
2738
2739
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002740Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2741 ExtraICState extra_ic_state = target()->extra_ic_state();
2742
2743 CompareNilICStub stub(isolate(), extra_ic_state);
2744
2745 // Extract the current supported types from the patched IC and calculate what
2746 // types must be supported as a result of the miss.
2747 bool already_monomorphic = stub.IsMonomorphic();
2748
2749 stub.UpdateStatus(object);
2750
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002751 // Find or create the specialized stub to support the new set of types.
2752 Handle<Code> code;
2753 if (stub.IsMonomorphic()) {
2754 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2755 ? FirstTargetMap()
2756 : HeapObject::cast(*object)->map());
2757 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2758 } else {
2759 code = stub.GetCode();
2760 }
2761 set_target(*code);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002762 return isolate()->factory()->ToBoolean(object->IsUndetectableObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002763}
2764
2765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002766RUNTIME_FUNCTION(Runtime_CompareNilIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002767 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002768 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002769 HandleScope scope(isolate);
2770 Handle<Object> object = args.at<Object>(0);
2771 CompareNilIC ic(isolate);
2772 return *ic.CompareNil(object);
2773}
2774
2775
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002776RUNTIME_FUNCTION(Runtime_Unreachable) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002777 UNREACHABLE();
2778 CHECK(false);
2779 return isolate->heap()->undefined_value();
2780}
2781
2782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002783Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2784 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2785 bool to_boolean_value = stub.UpdateStatus(object);
2786 Handle<Code> code = stub.GetCode();
2787 set_target(*code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002788 return isolate()->factory()->ToBoolean(to_boolean_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002789}
2790
2791
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002792RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002793 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002794 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002795 DCHECK(args.length() == 1);
2796 HandleScope scope(isolate);
2797 Handle<Object> object = args.at<Object>(0);
2798 ToBooleanIC ic(isolate);
2799 return *ic.ToBoolean(object);
2800}
2801
2802
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002803RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002804 Handle<JSObject> receiver = args.at<JSObject>(0);
2805 Handle<JSObject> holder = args.at<JSObject>(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002806 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002807 Handle<Name> name = args.at<Name>(3);
2808 Handle<Object> value = args.at<Object>(4);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002809 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002810 HandleScope scope(isolate);
2811
Ben Murdoch097c5b22016-05-18 11:27:45 +01002812 Handle<AccessorInfo> callback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002813 callback_or_cell->IsWeakCell()
Ben Murdoch097c5b22016-05-18 11:27:45 +01002814 ? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
2815 : AccessorInfo::cast(*callback_or_cell));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002816
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002817 DCHECK(callback->IsCompatibleReceiver(*receiver));
2818
2819 Address setter_address = v8::ToCData<Address>(callback->setter());
2820 v8::AccessorNameSetterCallback fun =
2821 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2822 DCHECK(fun != NULL);
2823
2824 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002825 Object::ShouldThrow should_throw =
2826 is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002827 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002828 *holder, should_throw);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2830 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2831 return *value;
2832}
2833
2834
2835/**
2836 * Attempts to load a property with an interceptor (which must be present),
2837 * but doesn't search the prototype chain.
2838 *
2839 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2840 * provide any value for the given name.
2841 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002843 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002844 Handle<Name> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002845 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002846 Handle<JSObject> receiver =
2847 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2848 Handle<JSObject> holder =
2849 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002850 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002851 LookupIterator it(receiver, name, holder, LookupIterator::OWN);
2852 bool done;
2853 Handle<Object> result;
2854 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2855 isolate, result, JSObject::GetPropertyWithInterceptor(&it, &done));
2856 if (done) return *result;
2857 return isolate->heap()->no_interceptor_result_sentinel();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002858}
2859
2860
2861/**
2862 * Loads a property with an interceptor performing post interceptor
2863 * lookup if interceptor failed.
2864 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002865RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002866 HandleScope scope(isolate);
2867 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2868 Handle<Name> name =
2869 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2870 Handle<JSObject> receiver =
2871 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2872 Handle<JSObject> holder =
2873 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2874
2875 Handle<Object> result;
2876 LookupIterator it(receiver, name, holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002877 // TODO(conradw): Investigate strong mode semantics for this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002878 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2879 JSObject::GetProperty(&it));
2880
2881 if (it.IsFound()) return *result;
2882
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002883 // Return the undefined result if the reference error should not be thrown.
2884 // Note that both keyed and non-keyed loads may end up here.
2885 LoadICNexus nexus(isolate);
2886 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2887 if (!ic.ShouldThrowReferenceError(it.GetReceiver())) {
2888 return isolate->heap()->undefined_value();
2889 }
2890
2891 // Throw a reference error.
2892 THROW_NEW_ERROR_RETURN_FAILURE(
2893 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894}
2895
2896
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002897RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002898 HandleScope scope(isolate);
2899 DCHECK(args.length() == 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002900 StoreICNexus nexus(isolate);
2901 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002902 Handle<JSObject> receiver = args.at<JSObject>(0);
2903 Handle<Name> name = args.at<Name>(1);
2904 Handle<Object> value = args.at<Object>(2);
2905#ifdef DEBUG
2906 PrototypeIterator iter(isolate, receiver,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002907 PrototypeIterator::START_AT_RECEIVER,
2908 PrototypeIterator::END_AT_NON_HIDDEN);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002909 bool found = false;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002910 for (; !iter.IsAtEnd(); iter.Advance()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002911 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2912 if (current->IsJSObject() &&
2913 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2914 found = true;
2915 break;
2916 }
2917 }
2918 DCHECK(found);
2919#endif
2920 Handle<Object> result;
2921 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2922 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002923 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 return *result;
2925}
2926
2927
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002928RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2929 // TODO(verwaest): This should probably get the holder and receiver as input.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002930 HandleScope scope(isolate);
2931 Handle<JSObject> receiver = args.at<JSObject>(0);
2932 DCHECK(args.smi_at(1) >= 0);
2933 uint32_t index = args.smi_at(1);
2934 Handle<Object> result;
2935 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002936 isolate, result, Object::GetElement(isolate, receiver, index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002937 return *result;
2938}
2939
2940
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002941RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002942 TimerEventScope<TimerEventIcMiss> timer(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002943 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8"), "V8.IcMiss");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002944 HandleScope scope(isolate);
2945 Handle<Object> receiver = args.at<Object>(0);
2946 Handle<Name> key = args.at<Name>(1);
2947 Handle<Object> result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002948
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002949 DCHECK(args.length() == 4);
2950 Handle<Smi> slot = args.at<Smi>(2);
2951 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2952 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2953 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2954 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2955 // set up outside the IC, handle that here.
2956 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
2957 LoadICNexus nexus(vector, vector_slot);
2958 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2959 ic.UpdateState(receiver, key);
2960 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002961 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002962 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
2963 vector->GetKind(vector_slot));
2964 KeyedLoadICNexus nexus(vector, vector_slot);
2965 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002966 ic.UpdateState(receiver, key);
2967 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2968 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002969
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002970 return *result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002971}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002972} // namespace internal
2973} // namespace v8