blob: 73ac666a41c991bfef72c6996cda50787d4a1703 [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 Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/frames-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/ic/call-optimization.h"
16#include "src/ic/handler-compiler.h"
17#include "src/ic/ic-inl.h"
18#include "src/ic/ic-compiler.h"
19#include "src/ic/stub-cache.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020#include "src/isolate-inl.h"
21#include "src/macro-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022#include "src/prototype.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024
25namespace v8 {
26namespace internal {
27
28char IC::TransitionMarkFromState(IC::State state) {
29 switch (state) {
30 case UNINITIALIZED:
31 return '0';
32 case PREMONOMORPHIC:
33 return '.';
34 case MONOMORPHIC:
35 return '1';
36 case PROTOTYPE_FAILURE:
37 return '^';
38 case POLYMORPHIC:
39 return 'P';
40 case MEGAMORPHIC:
41 return 'N';
42 case GENERIC:
43 return 'G';
44
45 // We never see the debugger states here, because the state is
46 // computed from the original code - not the patched code. Let
47 // these cases fall through to the unreachable code below.
48 case DEBUG_STUB:
49 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050 }
51 UNREACHABLE();
52 return 0;
53}
54
55
56const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
57 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
58 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
59 return ".IGNORE_OOB";
60 }
61 if (IsGrowStoreMode(mode)) return ".GROW";
62 return "";
63}
64
65
66#ifdef DEBUG
67
68#define TRACE_GENERIC_IC(isolate, type, reason) \
69 do { \
70 if (FLAG_trace_ic) { \
71 PrintF("[%s patching generic stub in ", type); \
72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
73 PrintF(" (%s)]\n", reason); \
74 } \
75 } while (false)
76
77#else
78
79#define TRACE_GENERIC_IC(isolate, type, reason) \
80 do { \
81 if (FLAG_trace_ic) { \
82 PrintF("[%s patching generic stub in ", type); \
83 PrintF("(see below) (%s)]\n", reason); \
84 } \
85 } while (false)
86
87#endif // DEBUG
88
89
90void IC::TraceIC(const char* type, Handle<Object> name) {
91 if (FLAG_trace_ic) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 if (AddressIsDeoptimizedCode()) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 State new_state =
94 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095 TraceIC(type, name, state(), new_state);
96 }
97}
98
99
100void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
101 State new_state) {
102 if (FLAG_trace_ic) {
103 Code* new_target = raw_target();
104 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
105
106 // TODO(jkummerow): Add support for "apply". The logic is roughly:
107 // marker = [fp_ + kMarkerOffset];
108 // if marker is smi and marker.value == INTERNAL and
109 // the frame's code == builtin(Builtins::kFunctionApply):
110 // then print "apply from" and advance one frame
111
112 Object* maybe_function =
113 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
114 if (maybe_function->IsJSFunction()) {
115 JSFunction* function = JSFunction::cast(maybe_function);
116 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(),
117 stdout, true);
118 }
119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 const char* modifier = "";
121 if (new_target->kind() == Code::KEYED_STORE_IC) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 KeyedAccessStoreMode mode =
123 casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
124 modifier = GetTransitionMarkModifier(mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 TransitionMarkFromState(new_state), modifier);
128#ifdef OBJECT_PRINT
129 OFStream os(stdout);
130 name->Print(os);
131#else
132 name->ShortPrint(stdout);
133#endif
134 PrintF("]\n");
135 }
136}
137
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139#define TRACE_IC(type, name) TraceIC(type, name)
140
141
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400143 : isolate_(isolate),
144 target_set_(false),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 vector_set_(false),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146 target_maps_set_(false),
147 nexus_(nexus) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 // To improve the performance of the (much used) IC code, we unfold a few
149 // levels of the stack frame iteration code. This yields a ~35% speedup when
150 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
151 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 Address* constant_pool = NULL;
153 if (FLAG_enable_embedded_constant_pool) {
154 constant_pool = reinterpret_cast<Address*>(
155 entry + ExitFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 }
157 Address* pc_address =
158 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
159 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
160 // If there's another JavaScript frame on the stack or a
161 // StubFailureTrampoline, we need to look one frame further down the stack to
162 // find the frame pointer and the return address stack slot.
163 if (depth == EXTRA_CALL_FRAME) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164 if (FLAG_enable_embedded_constant_pool) {
165 constant_pool = reinterpret_cast<Address*>(
166 fp + StandardFrameConstants::kConstantPoolOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 }
168 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
169 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
170 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
171 }
172#ifdef DEBUG
173 StackFrameIterator it(isolate);
174 for (int i = 0; i < depth + 1; i++) it.Advance();
175 StackFrame* frame = it.frame();
176 DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
177#endif
178 fp_ = fp;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 if (FLAG_enable_embedded_constant_pool) {
180 constant_pool_address_ = constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 }
182 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
183 target_ = handle(raw_target(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 kind_ = target_->kind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185 state_ = UseVector() ? nexus->StateFromFeedback() : target_->ic_state();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186 old_state_ = state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 extra_ic_state_ = target_->extra_ic_state();
188}
189
190
191SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
192 // Compute the JavaScript frame for the frame pointer of this IC
193 // structure. We need this to be able to find the function
194 // corresponding to the frame.
195 StackFrameIterator it(isolate());
196 while (it.frame()->fp() != this->fp()) it.Advance();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 if (FLAG_ignition && it.frame()->type() == StackFrame::STUB) {
198 // Advance over bytecode handler frame.
199 // TODO(rmcilroy): Remove this once bytecode handlers don't need a frame.
200 it.Advance();
201 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
203 // Find the function on the stack and both the active code for the
204 // function and the original code.
205 JSFunction* function = frame->function();
206 return function->shared();
207}
208
209
210Code* IC::GetCode() const {
211 HandleScope scope(isolate());
212 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
213 Code* code = shared->code();
214 return code;
215}
216
217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218bool IC::AddressIsOptimizedCode() const {
219 Code* host =
220 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code;
221 return host->kind() == Code::OPTIMIZED_FUNCTION;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222}
223
224
225static void LookupForRead(LookupIterator* it) {
226 for (; it->IsFound(); it->Next()) {
227 switch (it->state()) {
228 case LookupIterator::NOT_FOUND:
229 case LookupIterator::TRANSITION:
230 UNREACHABLE();
231 case LookupIterator::JSPROXY:
232 return;
233 case LookupIterator::INTERCEPTOR: {
234 // If there is a getter, return; otherwise loop to perform the lookup.
235 Handle<JSObject> holder = it->GetHolder<JSObject>();
236 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
237 return;
238 }
239 break;
240 }
241 case LookupIterator::ACCESS_CHECK:
242 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
243 // access checks for global proxies.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 break;
246 }
247 return;
248 case LookupIterator::ACCESSOR:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 case LookupIterator::DATA:
251 return;
252 }
253 }
254}
255
256
257bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
258 Handle<String> name) {
259 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400260 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265
266 // The current map wasn't handled yet. There's no reason to stay monomorphic,
267 // *unless* we're moving from a deprecated map to its replacement, or
268 // to a more general elements kind.
269 // TODO(verwaest): Check if the current map is actually what the old map
270 // would transition to.
271 if (maybe_handler_.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 if (!receiver_map()->IsJSObjectMap()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273 Map* first_map = FirstTargetMap();
274 if (first_map == NULL) return false;
275 Handle<Map> old_map(first_map);
276 if (old_map->is_deprecated()) return true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
278 receiver_map()->elements_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 }
280
281 CacheHolderFlag flag;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283
284 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
285 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
286 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary);
287
288 if (state() == MONOMORPHIC) {
289 int index = ic_holder_map->IndexInCodeCache(*name, *target());
290 if (index >= 0) {
291 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
292 }
293 }
294
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 if (receiver->IsJSGlobalObject()) {
296 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
298 if (it.state() == LookupIterator::ACCESS_CHECK) return false;
299 if (!it.IsFound()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 return it.property_details().cell_type() == PropertyCellType::kConstant;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 }
302
303 return true;
304}
305
306
307bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
308 if (target()->is_keyed_stub()) {
309 // Determine whether the failure is due to a name failure.
310 if (!name->IsName()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400311 Name* stub_name =
312 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 if (*name != stub_name) return false;
314 }
315
316 return true;
317}
318
319
320void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 if (!name->IsString()) return;
323 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
324 if (receiver->IsUndefined() || receiver->IsNull()) return;
325
326 // Remove the target from the code cache if it became invalid
327 // because of changes in the prototype chain to avoid hitting it
328 // again.
329 if (TryRemoveInvalidPrototypeDependentStub(receiver,
330 Handle<String>::cast(name))) {
331 MarkPrototypeFailure(name);
332 return;
333 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334}
335
336
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
338 Handle<Object> object, Handle<Object> key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341}
342
343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 HandleScope scope(isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 THROW_NEW_ERROR(
347 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348}
349
350
351static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
352 int* polymorphic_delta,
353 int* generic_delta) {
354 switch (old_state) {
355 case UNINITIALIZED:
356 case PREMONOMORPHIC:
357 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
358 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
359 *polymorphic_delta = 1;
360 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
361 *generic_delta = 1;
362 }
363 break;
364 case MONOMORPHIC:
365 case POLYMORPHIC:
366 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
367 *polymorphic_delta = -1;
368 if (new_state == MEGAMORPHIC || new_state == GENERIC) {
369 *generic_delta = 1;
370 }
371 break;
372 case MEGAMORPHIC:
373 case GENERIC:
374 if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
375 *generic_delta = -1;
376 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
377 *polymorphic_delta = 1;
378 }
379 break;
380 case PROTOTYPE_FAILURE:
381 case DEBUG_STUB:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 UNREACHABLE();
383 }
384}
385
386
387void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
388 State old_state, State new_state,
389 bool target_remains_ic_stub) {
390 Code* host =
391 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
392 if (host->kind() != Code::FUNCTION) return;
393
394 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub &&
395 // Not all Code objects have TypeFeedbackInfo.
396 host->type_feedback_info()->IsTypeFeedbackInfo()) {
397 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
398 int generic_delta = 0; // "Generic" here includes megamorphic.
399 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
400 &generic_delta);
401 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
402 info->change_ic_with_type_info_count(polymorphic_delta);
403 info->change_ic_generic_count(generic_delta);
404 }
405 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
406 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
407 info->change_own_type_change_checksum();
408 }
409 host->set_profiler_ticks(0);
410 isolate->runtime_profiler()->NotifyICChanged();
411 // TODO(2029): When an optimized function is patched, it would
412 // be nice to propagate the corresponding type information to its
413 // unoptimized version for the benefit of later inlining.
414}
415
416
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419 if (host->kind() != Code::FUNCTION) return;
420
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
422 info->change_own_type_change_checksum();
423 host->set_profiler_ticks(0);
424 isolate->runtime_profiler()->NotifyICChanged();
425 // TODO(2029): When an optimized function is patched, it would
426 // be nice to propagate the corresponding type information to its
427 // unoptimized version for the benefit of later inlining.
428}
429
430
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431void IC::PostPatching(Address address, Code* target, Code* old_target) {
432 // Type vector based ICs update these statistics at a different time because
433 // they don't always patch on state change.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400434 if (ICUseVector(target->kind())) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000435
436 Isolate* isolate = target->GetHeap()->isolate();
437 State old_state = UNINITIALIZED;
438 State new_state = UNINITIALIZED;
439 bool target_remains_ic_stub = false;
440 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) {
441 old_state = old_target->ic_state();
442 new_state = target->ic_state();
443 target_remains_ic_stub = true;
444 }
445
446 OnTypeFeedbackChanged(isolate, address, old_state, new_state,
447 target_remains_ic_stub);
448}
449
450
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 Code* target = GetTargetAtAddress(address, constant_pool);
453
454 // Don't clear debug break inline cache as it will remove the break point.
455 if (target->is_debug_stub()) return;
456
457 switch (target->kind()) {
458 case Code::LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000459 case Code::KEYED_LOAD_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460 case Code::STORE_IC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461 case Code::KEYED_STORE_IC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 case Code::COMPARE_IC:
464 return CompareIC::Clear(isolate, address, target, constant_pool);
465 case Code::COMPARE_NIL_IC:
466 return CompareNilIC::Clear(address, target, constant_pool);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400467 case Code::CALL_IC: // CallICs are vector-based and cleared differently.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 case Code::BINARY_OP_IC:
469 case Code::TO_BOOLEAN_IC:
470 // Clearing these is tricky and does not
471 // make any performance difference.
472 return;
473 default:
474 UNREACHABLE();
475 }
476}
477
478
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400479void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
480 if (IsCleared(nexus)) return;
481 // Make sure to also clear the map used in inline fast cases. If we
482 // do not clear these maps, cached code can keep objects alive
483 // through the embedded maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400484 nexus->ConfigurePremonomorphic();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400486}
487
488
489void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
490 // Determine our state.
491 Object* feedback = nexus->vector()->Get(nexus->slot());
492 State state = nexus->StateFromFeedback();
493
494 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
495 nexus->ConfigureUninitialized();
496 // The change in state must be processed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400498 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499}
500
501
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400502void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
503 if (IsCleared(nexus)) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400504 nexus->ConfigurePremonomorphic();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 OnTypeFeedbackChanged(isolate, host);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400506}
507
508
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 if (IsCleared(target)) return;
512 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC,
513 target->extra_ic_state());
514 SetTargetAtAddress(address, code, constant_pool);
515}
516
517
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
519 if (IsCleared(nexus)) return;
520 nexus->ConfigurePremonomorphic();
521 OnTypeFeedbackChanged(isolate, host);
522}
523
524
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000526 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 if (IsCleared(target)) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 Handle<Code> code = pre_monomorphic_stub(
529 isolate, StoreICState::GetLanguageMode(target->extra_ic_state()));
530 SetTargetAtAddress(address, *code, constant_pool);
531}
532
533
534void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
535 KeyedStoreICNexus* nexus) {
536 if (IsCleared(nexus)) return;
537 nexus->ConfigurePremonomorphic();
538 OnTypeFeedbackChanged(isolate, host);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539}
540
541
542void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
545 CompareICStub stub(target->stub_key(), isolate);
546 // Only clear CompareICs that can retain objects.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 if (stub.state() != CompareICState::KNOWN_RECEIVER) return;
548 SetTargetAtAddress(address,
549 GetRawUninitialized(isolate, stub.op(), stub.strength()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 constant_pool);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552}
553
554
555// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate,
557 ExtraICState extra_state) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 if (FLAG_compiled_keyed_generic_loads) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000559 return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 return is_strong(LoadICState::GetLanguageMode(extra_state))
562 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong()
563 : 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
576
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577void IC::ConfigureVectorState(IC::State new_state) {
578 DCHECK(UseVector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 if (new_state == PREMONOMORPHIC) {
580 nexus()->ConfigurePremonomorphic();
581 } else if (new_state == MEGAMORPHIC) {
582 nexus()->ConfigureMegamorphic();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400583 } else {
584 UNREACHABLE();
585 }
586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 vector_set_ = true;
588 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400589}
590
591
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400593 Handle<Code> handler) {
594 DCHECK(UseVector());
595 if (kind() == Code::LOAD_IC) {
596 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 nexus->ConfigureMonomorphic(map, handler);
598 } else if (kind() == Code::KEYED_LOAD_IC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400599 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 nexus->ConfigureMonomorphic(name, map, handler);
601 } else if (kind() == Code::STORE_IC) {
602 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
603 nexus->ConfigureMonomorphic(map, handler);
604 } else {
605 DCHECK(kind() == Code::KEYED_STORE_IC);
606 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
607 nexus->ConfigureMonomorphic(name, map, handler);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400608 }
609
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 vector_set_ = true;
611 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400612}
613
614
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400616 CodeHandleList* handlers) {
617 DCHECK(UseVector());
618 if (kind() == Code::LOAD_IC) {
619 LoadICNexus* nexus = casted_nexus<LoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 nexus->ConfigurePolymorphic(maps, handlers);
621 } else if (kind() == Code::KEYED_LOAD_IC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400622 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 nexus->ConfigurePolymorphic(name, maps, handlers);
624 } else if (kind() == Code::STORE_IC) {
625 StoreICNexus* nexus = casted_nexus<StoreICNexus>();
626 nexus->ConfigurePolymorphic(maps, handlers);
627 } else {
628 DCHECK(kind() == Code::KEYED_STORE_IC);
629 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
630 nexus->ConfigurePolymorphic(name, maps, handlers);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400631 }
632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000633 vector_set_ = true;
634 OnTypeFeedbackChanged(isolate(), get_host());
635}
636
637
638void IC::ConfigureVectorState(MapHandleList* maps,
639 MapHandleList* transitioned_maps,
640 CodeHandleList* handlers) {
641 DCHECK(UseVector());
642 DCHECK(kind() == Code::KEYED_STORE_IC);
643 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
644 nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
645
646 vector_set_ = true;
647 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400648}
649
650
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
652 // If the object is undefined or null it's illegal to try to get any
653 // of its properties; throw a TypeError in that case.
654 if (object->IsUndefined() || object->IsNull()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000655 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 }
657
658 // Check if the name is trivially convertible to an index and get
659 // the element or char if so.
660 uint32_t index;
661 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
662 // Rewrite to the generic keyed load stub.
663 if (FLAG_use_ic) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 DCHECK(UseVector());
665 ConfigureVectorState(MEGAMORPHIC);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666 TRACE_IC("LoadIC", name);
667 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
668 }
669 Handle<Object> result;
670 ASSIGN_RETURN_ON_EXCEPTION(
671 isolate(), result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 Object::GetElement(isolate(), object, index, language_mode()), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 return result;
674 }
675
676 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
677
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000678 if (object->IsJSGlobalObject() && name->IsString()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400679 // Look up in script context table.
680 Handle<String> str_name = Handle<String>::cast(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400682 Handle<ScriptContextTable> script_contexts(
683 global->native_context()->script_context_table());
684
685 ScriptContextTable::LookupResult lookup_result;
686 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 Handle<Object> result =
688 FixedArray::get(ScriptContextTable::GetContext(
689 script_contexts, lookup_result.context_index),
690 lookup_result.slot_index);
691 if (*result == *isolate()->factory()->the_hole_value()) {
692 // Do not install stubs and stay pre-monomorphic for
693 // uninitialized accesses.
694 return ReferenceError(name);
695 }
696
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
698 LoadScriptContextFieldStub stub(isolate(), &lookup_result);
699 PatchCache(name, stub.GetCode());
700 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 return result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400702 }
703 }
704
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705 // Named lookup in the object.
706 LookupIterator it(object, name);
707 LookupForRead(&it);
708
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 if (it.IsFound() || !ShouldThrowReferenceError(object)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000710 // Update inline cache and stub cache.
711 if (use_ic) UpdateCaches(&it);
712
713 // Get the property.
714 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715
716 ASSIGN_RETURN_ON_EXCEPTION(
717 isolate(), result, Object::GetProperty(&it, language_mode()), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 if (it.IsFound()) {
719 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 } else if (!ShouldThrowReferenceError(object)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 LOG(isolate(), SuspectReadEvent(*name, *object));
722 return result;
723 }
724 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 return ReferenceError(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726}
727
728
729static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
730 Handle<Map> new_receiver_map) {
731 DCHECK(!new_receiver_map.is_null());
732 for (int current = 0; current < receiver_maps->length(); ++current) {
733 if (!receiver_maps->at(current).is_null() &&
734 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
735 return false;
736 }
737 }
738 receiver_maps->Add(new_receiver_map);
739 return true;
740}
741
742
743bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
744 if (!code->is_handler()) return false;
745 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 Handle<Map> map = receiver_map();
747 MapHandleList maps;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 CodeHandleList handlers;
749
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 TargetMaps(&maps);
751 int number_of_maps = maps.length();
752 int deprecated_maps = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 int handler_to_overwrite = -1;
754
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000755 for (int i = 0; i < number_of_maps; i++) {
756 Handle<Map> current_map = maps.at(i);
757 if (current_map->is_deprecated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758 // Filter out deprecated maps to ensure their instances get migrated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759 ++deprecated_maps;
760 } else if (map.is_identical_to(current_map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 // If the receiver type is already in the polymorphic IC, this indicates
762 // there was a prototoype chain failure. In that case, just overwrite the
763 // handler.
764 handler_to_overwrite = i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765 } else if (handler_to_overwrite == -1 &&
766 IsTransitionOfMonomorphicTarget(*current_map, *map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767 handler_to_overwrite = i;
768 }
769 }
770
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771 int number_of_valid_maps =
772 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 if (number_of_valid_maps >= 4) return false;
775 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400776 return false;
777 }
778 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400780 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 if (!target()->FindHandlers(&handlers, maps.length())) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 number_of_valid_maps++;
785 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 Handle<Code> ic;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000787 if (number_of_valid_maps == 1) {
788 ConfigureVectorState(name, receiver_map(), code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 } else {
790 if (handler_to_overwrite >= 0) {
791 handlers.Set(handler_to_overwrite, code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792 if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
793 maps.Set(handler_to_overwrite, map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 }
795 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000796 maps.Add(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000797 handlers.Add(code);
798 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400799
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 ConfigureVectorState(name, &maps, &handlers);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400802
803 if (!UseVector()) set_target(*ic);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 return true;
805}
806
807
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
809 DCHECK(handler->is_handler());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000810 ConfigureVectorState(name, receiver_map(), handler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000811}
812
813
814void IC::CopyICToMegamorphicCache(Handle<Name> name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 MapHandleList maps;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 CodeHandleList handlers;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 TargetMaps(&maps);
818 if (!target()->FindHandlers(&handlers, maps.length())) return;
819 for (int i = 0; i < maps.length(); i++) {
820 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000821 }
822}
823
824
825bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
826 if (source_map == NULL) return true;
827 if (target_map == NULL) return false;
828 ElementsKind target_elements_kind = target_map->elements_kind();
829 bool more_general_transition = IsMoreGeneralElementsKindTransition(
830 source_map->elements_kind(), target_elements_kind);
831 Map* transitioned_map =
832 more_general_transition
833 ? source_map->LookupElementsTransitionMap(target_elements_kind)
834 : NULL;
835
836 return transitioned_map == target_map;
837}
838
839
840void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
841 switch (state()) {
842 case UNINITIALIZED:
843 case PREMONOMORPHIC:
844 UpdateMonomorphicIC(code, name);
845 break;
846 case PROTOTYPE_FAILURE:
847 case MONOMORPHIC:
848 case POLYMORPHIC:
849 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
850 if (UpdatePolymorphicIC(name, code)) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400851 // For keyed stubs, we can't know whether old handlers were for the
852 // same key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000853 CopyICToMegamorphicCache(name);
854 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400855 if (UseVector()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000856 ConfigureVectorState(MEGAMORPHIC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400857 } else {
858 set_target(*megamorphic_stub());
859 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 // Fall through.
861 case MEGAMORPHIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 UpdateMegamorphicCache(*receiver_map(), *name, *code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400863 // Indicate that we've handled this case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000864 if (UseVector()) {
865 vector_set_ = true;
866 } else {
867 target_set_ = true;
868 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869 break;
870 case DEBUG_STUB:
871 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400872 case GENERIC:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000873 UNREACHABLE();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400874 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000875 }
876}
877
878
879Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
880 ExtraICState extra_state) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000882}
883
884
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400885Handle<Code> LoadIC::initialize_stub_in_optimized_code(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 Isolate* isolate, ExtraICState extra_state, State initialization_state) {
887 return LoadICStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400888}
889
890
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000891Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate,
892 ExtraICState extra_state) {
893 return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400894}
895
896
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000897Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
898 Isolate* isolate, State initialization_state, ExtraICState extra_state) {
899 if (initialization_state != MEGAMORPHIC) {
900 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400901 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 return is_strong(LoadICState::GetLanguageMode(extra_state))
903 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong()
904 : isolate->builtins()->KeyedLoadIC_Megamorphic();
905}
906
907
908static Handle<Code> KeyedStoreICInitializeStubHelper(
909 Isolate* isolate, LanguageMode language_mode,
910 InlineCacheState initialization_state) {
911 switch (initialization_state) {
912 case UNINITIALIZED:
913 return is_strict(language_mode)
914 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict()
915 : isolate->builtins()->KeyedStoreIC_Initialize();
916 case PREMONOMORPHIC:
917 return is_strict(language_mode)
918 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict()
919 : isolate->builtins()->KeyedStoreIC_PreMonomorphic();
920 case MEGAMORPHIC:
921 return is_strict(language_mode)
922 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict()
923 : isolate->builtins()->KeyedStoreIC_Megamorphic();
924 default:
925 UNREACHABLE();
926 }
927 return Handle<Code>();
928}
929
930
931Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate,
932 LanguageMode language_mode,
933 State initialization_state) {
934 if (initialization_state != MEGAMORPHIC) {
935 VectorKeyedStoreICTrampolineStub stub(isolate, StoreICState(language_mode));
936 return stub.GetCode();
937 }
938
939 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
940 initialization_state);
941}
942
943
944Handle<Code> KeyedStoreIC::initialize_stub_in_optimized_code(
945 Isolate* isolate, LanguageMode language_mode, State initialization_state) {
946 if (initialization_state != MEGAMORPHIC) {
947 VectorKeyedStoreICStub stub(isolate, StoreICState(language_mode));
948 return stub.GetCode();
949 }
950
951 return KeyedStoreICInitializeStubHelper(isolate, language_mode,
952 initialization_state);
953}
954
955
956Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
957 ExtraICState extra_state) {
958 LanguageMode mode = StoreICState::GetLanguageMode(extra_state);
959 return KeyedStoreICInitializeStubHelper(isolate, mode, MEGAMORPHIC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400960}
961
962
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963Handle<Code> LoadIC::megamorphic_stub() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 DCHECK_EQ(Code::KEYED_LOAD_IC, kind());
965 return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000966}
967
968
969Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
970 LoadFieldStub stub(isolate(), index);
971 return stub.GetCode();
972}
973
974
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
976 DCHECK(lookup->state() == LookupIterator::ACCESSOR);
977 Isolate* isolate = lookup->isolate();
978 Handle<Object> accessors = lookup->GetAccessors();
979 if (accessors->IsExecutableAccessorInfo()) {
980 Handle<ExecutableAccessorInfo> info =
981 Handle<ExecutableAccessorInfo>::cast(accessors);
982 if (info->getter() != NULL &&
983 !ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate, info,
984 receiver_map)) {
985 return false;
986 }
987 } else if (accessors->IsAccessorPair()) {
988 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
989 isolate);
990 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
991 Handle<Object> receiver = lookup->GetReceiver();
992 if (getter->IsJSFunction() && holder->HasFastProperties()) {
993 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
994 if (receiver->IsJSObject() || function->shared()->IsBuiltin() ||
995 !is_sloppy(function->shared()->language_mode())) {
996 CallOptimization call_optimization(function);
997 if (call_optimization.is_simple_api_call() &&
998 !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) {
999 return false;
1000 }
1001 }
1002 }
1003 }
1004 return true;
1005}
1006
1007
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001008void LoadIC::UpdateCaches(LookupIterator* lookup) {
1009 if (state() == UNINITIALIZED) {
1010 // This is the first time we execute this inline cache. Set the target to
1011 // the pre monomorphic stub to delay setting the monomorphic state.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001012 ConfigureVectorState(PREMONOMORPHIC);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 TRACE_IC("LoadIC", lookup->name());
1014 return;
1015 }
1016
1017 Handle<Code> code;
1018 if (lookup->state() == LookupIterator::JSPROXY ||
1019 lookup->state() == LookupIterator::ACCESS_CHECK) {
1020 code = slow_stub();
1021 } else if (!lookup->IsFound()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 if (kind() == Code::LOAD_IC && !is_strong(language_mode())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001023 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024 receiver_map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
1026 if (code.is_null()) code = slow_stub();
1027 } else {
1028 code = slow_stub();
1029 }
1030 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 if (lookup->state() == LookupIterator::ACCESSOR) {
1032 if (!IsCompatibleReceiver(lookup, receiver_map())) {
1033 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1034 code = slow_stub();
1035 }
1036 } else if (lookup->state() == LookupIterator::INTERCEPTOR) {
1037 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1038 // the original iterator will be used to fetch the value.
1039 LookupIterator it = *lookup;
1040 it.Next();
1041 LookupForRead(&it);
1042 if (it.state() == LookupIterator::ACCESSOR &&
1043 !IsCompatibleReceiver(&it, receiver_map())) {
1044 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type");
1045 code = slow_stub();
1046 }
1047 }
1048 if (code.is_null()) code = ComputeHandler(lookup);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049 }
1050
1051 PatchCache(lookup->name(), code);
1052 TRACE_IC("LoadIC", lookup->name());
1053}
1054
1055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057 isolate()->stub_cache()->Set(name, map, code);
1058}
1059
1060
1061Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
1062 bool receiver_is_holder =
1063 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
1064 CacheHolderFlag flag;
1065 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 receiver_map(), receiver_is_holder, isolate(), &flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001067
1068 Handle<Code> code = PropertyHandlerCompiler::Find(
1069 lookup->name(), stub_holder_map, kind(), flag,
1070 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST);
1071 // Use the cached value if it exists, and if it is different from the
1072 // handler that just missed.
1073 if (!code.is_null()) {
1074 if (!maybe_handler_.is_null() &&
1075 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
1076 return code;
1077 }
1078 if (maybe_handler_.is_null()) {
1079 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1080 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1081 // cache (which just missed) is different from the cached handler.
1082 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1083 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1084 Code* megamorphic_cached_code =
1085 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
1086 if (megamorphic_cached_code != *code) return code;
1087 } else {
1088 return code;
1089 }
1090 }
1091 }
1092
1093 code = CompileHandler(lookup, value, flag);
1094 DCHECK(code->is_handler());
1095
1096 // TODO(mvstanton): we'd only like to cache code on the map when it's custom
1097 // code compiled for this map, otherwise it's already cached in the global
1098 // code
1099 // cache. We are also guarding against installing code with flags that don't
1100 // match the desired CacheHolderFlag computed above, which would lead to
1101 // invalid lookups later.
1102 if (code->type() != Code::NORMAL &&
1103 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
1104 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
1105 }
1106
1107 return code;
1108}
1109
1110
1111Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1112 Handle<Object> unused,
1113 CacheHolderFlag cache_holder) {
1114 Handle<Object> receiver = lookup->GetReceiver();
1115 if (receiver->IsString() &&
1116 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1117 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1118 return SimpleFieldLoad(index);
1119 }
1120
1121 if (receiver->IsStringWrapper() &&
1122 Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
1123 StringLengthStub string_length_stub(isolate());
1124 return string_length_stub.GetCode();
1125 }
1126
1127 // Use specialized code for getting prototype of functions.
1128 if (receiver->IsJSFunction() &&
1129 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130 receiver->IsConstructor() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131 !Handle<JSFunction>::cast(receiver)
1132 ->map()
1133 ->has_non_instance_prototype()) {
1134 Handle<Code> stub;
1135 FunctionPrototypeStub function_prototype_stub(isolate());
1136 return function_prototype_stub.GetCode();
1137 }
1138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001139 Handle<Map> map = receiver_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140 Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1141 bool receiver_is_holder = receiver.is_identical_to(holder);
1142 switch (lookup->state()) {
1143 case LookupIterator::INTERCEPTOR: {
1144 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1147 // the original iterator will be used to fetch the value.
1148 LookupIterator it = *lookup;
1149 it.Next();
1150 LookupForRead(&it);
1151 return compiler.CompileLoadInterceptor(&it);
1152 }
1153
1154 case LookupIterator::ACCESSOR: {
1155 // Use simple field loads for some well-known callback properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 // The method will only return true for absolute truths based on the
1157 // receiver maps.
1158 int object_offset;
1159 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1160 &object_offset)) {
1161 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1162 return SimpleFieldLoad(index);
1163 }
1164 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
1165 &object_offset)) {
1166 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1167 ArrayBufferViewLoadFieldStub stub(isolate(), index);
1168 return stub.GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001169 }
1170
1171 Handle<Object> accessors = lookup->GetAccessors();
1172 if (accessors->IsExecutableAccessorInfo()) {
1173 Handle<ExecutableAccessorInfo> info =
1174 Handle<ExecutableAccessorInfo>::cast(accessors);
1175 if (v8::ToCData<Address>(info->getter()) == 0) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001176 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1177 map)) {
1178 // This case should be already handled in LoadIC::UpdateCaches.
1179 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001180 break;
1181 }
1182 if (!holder->HasFastProperties()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001183 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001184 return compiler.CompileLoadCallback(lookup->name(), info);
1185 }
1186 if (accessors->IsAccessorPair()) {
1187 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1188 isolate());
1189 if (!getter->IsJSFunction()) break;
1190 if (!holder->HasFastProperties()) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191 // When debugging we need to go the slow path to flood the accessor.
1192 if (GetSharedFunctionInfo()->HasDebugInfo()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001194 if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() &&
1195 is_sloppy(function->shared()->language_mode())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 // Calling sloppy non-builtins with a value as the receiver
1197 // requires boxing.
1198 break;
1199 }
1200 CallOptimization call_optimization(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
1202 if (call_optimization.is_simple_api_call()) {
1203 if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1204 return compiler.CompileLoadCallback(
1205 lookup->name(), call_optimization, lookup->GetAccessorIndex());
1206 } else {
1207 // This case should be already handled in LoadIC::UpdateCaches.
1208 UNREACHABLE();
1209 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001210 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 int expected_arguments =
1212 function->shared()->internal_formal_parameter_count();
1213 return compiler.CompileLoadViaGetter(
1214 lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
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 Murdoch4a90d5f2016-03-22 12:00:34 +00001240 return is_strong(language_mode())
1241 ? isolate()->builtins()->LoadIC_Normal_Strong()
1242 : isolate()->builtins()->LoadIC_Normal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 }
1244
1245 // -------------- Fields --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 if (lookup->property_details().type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 FieldIndex field = lookup->GetFieldIndex();
1248 if (receiver_is_holder) {
1249 return SimpleFieldLoad(field);
1250 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001251 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252 return compiler.CompileLoadField(lookup->name(), field);
1253 }
1254
1255 // -------------- Constant properties --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001256 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001257 if (receiver_is_holder) {
1258 LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
1259 return stub.GetCode();
1260 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001261 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001262 return compiler.CompileLoadConstant(lookup->name(),
1263 lookup->GetConstantIndex());
1264 }
1265
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1267 return slow_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268 case LookupIterator::ACCESS_CHECK:
1269 case LookupIterator::JSPROXY:
1270 case LookupIterator::NOT_FOUND:
1271 case LookupIterator::TRANSITION:
1272 UNREACHABLE();
1273 }
1274
1275 return slow_stub();
1276}
1277
1278
1279static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1280 // This helper implements a few common fast cases for converting
1281 // non-smi keys of keyed loads/stores to a smi or a string.
1282 if (key->IsHeapNumber()) {
1283 double value = Handle<HeapNumber>::cast(key)->value();
1284 if (std::isnan(value)) {
1285 key = isolate->factory()->nan_string();
1286 } else {
1287 int int_value = FastD2I(value);
1288 if (value == int_value && Smi::IsValid(int_value)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289 key = handle(Smi::FromInt(int_value), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001290 }
1291 }
1292 } else if (key->IsUndefined()) {
1293 key = isolate->factory()->undefined_string();
1294 }
1295 return key;
1296}
1297
1298
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001299Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
1300 Handle<Code> null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001301 Handle<Map> receiver_map(receiver->map(), isolate());
1302 MapHandleList target_receiver_maps;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001303 TargetMaps(&target_receiver_maps);
1304
1305
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 if (target_receiver_maps.length() == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 Handle<Code> handler =
1308 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1309 receiver_map, extra_ic_state());
1310 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1311 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001312 }
1313
1314 // The first time a receiver is seen that is a transitioned version of the
1315 // previous monomorphic receiver type, assume the new ElementsKind is the
1316 // monomorphic type. This benefits global arrays that only transition
1317 // once, and all call sites accessing them are faster if they remain
1318 // monomorphic. If this optimistic assumption is not true, the IC will
1319 // miss again and it will become polymorphic and support both the
1320 // untransitioned and transitioned maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001321 if (state() == MONOMORPHIC && !receiver->IsString() &&
1322 IsMoreGeneralElementsKindTransition(
1323 target_receiver_maps.at(0)->elements_kind(),
1324 Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325 Handle<Code> handler =
1326 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
1327 receiver_map, extra_ic_state());
1328 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1329 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001330 }
1331
1332 DCHECK(state() != GENERIC);
1333
1334 // Determine the list of receiver maps that this call site has seen,
1335 // adding the map that was just encountered.
1336 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1337 // If the miss wasn't due to an unseen map, a polymorphic stub
1338 // won't help, use the generic stub.
1339 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001340 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341 }
1342
1343 // If the maximum number of receiver maps has been exceeded, use the generic
1344 // version of the IC.
1345 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1346 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001347 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001348 }
1349
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001350 CodeHandleList handlers(target_receiver_maps.length());
1351 ElementHandlerCompiler compiler(isolate());
1352 compiler.CompileElementHandlers(&target_receiver_maps, &handlers,
1353 language_mode());
1354 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers);
1355 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356}
1357
1358
1359MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1360 Handle<Object> key) {
1361 if (MigrateDeprecated(object)) {
1362 Handle<Object> result;
1363 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001364 isolate(), result,
1365 Runtime::GetObjectProperty(isolate(), object, key, language_mode()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001366 Object);
1367 return result;
1368 }
1369
1370 Handle<Object> load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001372
1373 // Check for non-string values that can be converted into an
1374 // internalized string directly or is representable as a smi.
1375 key = TryConvertKey(key, isolate());
1376
1377 if (key->IsInternalizedString() || key->IsSymbol()) {
1378 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1379 LoadIC::Load(object, Handle<Name>::cast(key)),
1380 Object);
1381 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001382 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
1383 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001384 if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 }
1386 }
1387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 DCHECK(UseVector());
1389 if (!is_vector_set() || stub.is_null()) {
1390 Code* generic = *megamorphic_stub();
1391 if (!stub.is_null() && *stub == generic) {
1392 ConfigureVectorState(MEGAMORPHIC);
1393 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001396 TRACE_IC("LoadIC", key);
1397 }
1398
1399 if (!load_handle.is_null()) return load_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001402 ASSIGN_RETURN_ON_EXCEPTION(
1403 isolate(), result,
1404 Runtime::GetObjectProperty(isolate(), object, key, language_mode()),
1405 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 return result;
1407}
1408
1409
1410bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1411 JSReceiver::StoreFromKeyed store_mode) {
1412 // Disable ICs for non-JSObjects for now.
1413 Handle<Object> receiver = it->GetReceiver();
1414 if (!receiver->IsJSObject()) return false;
1415 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
1416
1417 for (; it->IsFound(); it->Next()) {
1418 switch (it->state()) {
1419 case LookupIterator::NOT_FOUND:
1420 case LookupIterator::TRANSITION:
1421 UNREACHABLE();
1422 case LookupIterator::JSPROXY:
1423 return false;
1424 case LookupIterator::INTERCEPTOR: {
1425 Handle<JSObject> holder = it->GetHolder<JSObject>();
1426 InterceptorInfo* info = holder->GetNamedInterceptor();
1427 if (it->HolderIsReceiverOrHiddenPrototype()) {
1428 if (!info->setter()->IsUndefined()) return true;
1429 } else if (!info->getter()->IsUndefined() ||
1430 !info->query()->IsUndefined()) {
1431 return false;
1432 }
1433 break;
1434 }
1435 case LookupIterator::ACCESS_CHECK:
1436 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1437 break;
1438 case LookupIterator::ACCESSOR:
1439 return !it->IsReadOnly();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1441 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 case LookupIterator::DATA: {
1443 if (it->IsReadOnly()) return false;
1444 Handle<JSObject> holder = it->GetHolder<JSObject>();
1445 if (receiver.is_identical_to(holder)) {
1446 it->PrepareForDataProperty(value);
1447 // The previous receiver map might just have been deprecated,
1448 // so reload it.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 update_receiver_map(receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 return true;
1451 }
1452
1453 // Receiver != holder.
1454 PrototypeIterator iter(it->isolate(), receiver);
1455 if (receiver->IsJSGlobalProxy()) {
1456 return it->GetHolder<Object>().is_identical_to(
1457 PrototypeIterator::GetCurrent(iter));
1458 }
1459
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001460 if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1461
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001462 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1463 return it->IsCacheableTransition();
1464 }
1465 }
1466 }
1467
1468 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1469 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()) {
1482 ConfigureVectorState(MEGAMORPHIC);
1483 } 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 =
1513 FixedArray::get(script_context, lookup_result.slot_index);
1514
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
1567
1568Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001569 ConvertReceiverMode mode) {
1570 CallICTrampolineStub stub(isolate, CallICState(argc, mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 Handle<Code> code = stub.GetCode();
1572 return code;
1573}
1574
1575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001576Handle<Code> CallIC::initialize_stub_in_optimized_code(
1577 Isolate* isolate, int argc, ConvertReceiverMode mode) {
1578 CallICStub stub(isolate, CallICState(argc, mode));
1579 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001656 ConfigureVectorState(PREMONOMORPHIC);
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 Murdoch4a90d5f2016-03-22 12:00:34 +00001696 DCHECK(!receiver->IsAccessCheckNeeded() ||
1697 isolate()->IsInternallyUsedPropertyName(lookup->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001698
1699 switch (lookup->state()) {
1700 case LookupIterator::TRANSITION: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001701 auto store_target = lookup->GetStoreTarget();
1702 if (store_target->IsJSGlobalObject()) {
1703 // TODO(dcarney): this currently just deopts. Use the transition cell.
1704 auto cell = isolate()->factory()->NewPropertyCell();
1705 cell->set_value(*value);
1706 auto code = PropertyCellStoreHandler(
1707 isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
1708 lookup->name(), cell, PropertyCellType::kConstant);
1709 cell->set_value(isolate()->heap()->the_hole_value());
1710 return code;
1711 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 Handle<Map> transition = lookup->transition_map();
1713 // Currently not handled by CompileStoreTransition.
1714 if (!holder->HasFastProperties()) {
1715 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
1716 break;
1717 }
1718
1719 DCHECK(lookup->IsCacheableTransition());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001720 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001721 return compiler.CompileStoreTransition(transition, lookup->name());
1722 }
1723
1724 case LookupIterator::INTERCEPTOR: {
1725 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001726 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001727 return compiler.CompileStoreInterceptor(lookup->name());
1728 }
1729
1730 case LookupIterator::ACCESSOR: {
1731 if (!holder->HasFastProperties()) {
1732 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
1733 break;
1734 }
1735 Handle<Object> accessors = lookup->GetAccessors();
1736 if (accessors->IsExecutableAccessorInfo()) {
1737 Handle<ExecutableAccessorInfo> info =
1738 Handle<ExecutableAccessorInfo>::cast(accessors);
1739 if (v8::ToCData<Address>(info->setter()) == 0) {
1740 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
1741 break;
1742 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001743 if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1744 !lookup->HolderIsReceiverOrHiddenPrototype()) {
1745 TRACE_GENERIC_IC(isolate(), "StoreIC",
1746 "special data property in prototype chain");
1747 break;
1748 }
1749 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1750 receiver_map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001751 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
1752 break;
1753 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001754 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001755 return compiler.CompileStoreCallback(receiver, lookup->name(), info);
1756 } else if (accessors->IsAccessorPair()) {
1757 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1758 isolate());
1759 if (!setter->IsJSFunction()) {
1760 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
1761 break;
1762 }
1763 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1764 CallOptimization call_optimization(function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001765 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766 if (call_optimization.is_simple_api_call() &&
1767 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1768 return compiler.CompileStoreCallback(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001769 call_optimization,
1770 lookup->GetAccessorIndex());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 int expected_arguments =
1773 function->shared()->internal_formal_parameter_count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001774 return compiler.CompileStoreViaSetter(receiver, lookup->name(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001775 lookup->GetAccessorIndex(),
1776 expected_arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 break;
1779 }
1780
1781 case LookupIterator::DATA: {
1782 if (lookup->is_dictionary_holder()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001783 if (holder->IsJSGlobalObject()) {
1784 DCHECK(holder.is_identical_to(receiver) ||
1785 receiver->map()->prototype() == *holder);
1786 auto cell = lookup->GetPropertyCell();
1787 auto updated_type = PropertyCell::UpdatedType(
1788 cell, value, lookup->property_details());
1789 auto code = PropertyCellStoreHandler(
1790 isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
1791 lookup->name(), cell, updated_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001792 return code;
1793 }
1794 DCHECK(holder.is_identical_to(receiver));
1795 return isolate()->builtins()->StoreIC_Normal();
1796 }
1797
1798 // -------------- Fields --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 if (lookup->property_details().type() == DATA) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001800 bool use_stub = true;
1801 if (lookup->representation().IsHeapObject()) {
1802 // Only use a generic stub if no types need to be tracked.
1803 Handle<HeapType> field_type = lookup->GetFieldType();
1804 HeapType::Iterator<Map> it = field_type->Classes();
1805 use_stub = it.Done();
1806 }
1807 if (use_stub) {
1808 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1809 lookup->representation());
1810 return stub.GetCode();
1811 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001812 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001813 return compiler.CompileStoreField(lookup);
1814 }
1815
1816 // -------------- Constant properties --------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001817 DCHECK(lookup->property_details().type() == DATA_CONSTANT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001818 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
1819 break;
1820 }
1821
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001822 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001823 case LookupIterator::ACCESS_CHECK:
1824 case LookupIterator::JSPROXY:
1825 case LookupIterator::NOT_FOUND:
1826 UNREACHABLE();
1827 }
1828 return slow_stub();
1829}
1830
1831
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 KeyedAccessStoreMode store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001834 Handle<Code> null_handle;
1835 // Don't handle megamorphic property accesses for INTERCEPTORS or
1836 // ACCESSOR_CONSTANT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001837 // via megamorphic stubs, since they don't have a map in their relocation info
1838 // and so the stubs can't be harvested for the object needed for a map check.
1839 if (target()->type() != Code::NORMAL) {
1840 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 }
1843
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 MapHandleList target_receiver_maps;
1845 TargetMaps(&target_receiver_maps);
1846 if (target_receiver_maps.length() == 0) {
1847 Handle<Map> monomorphic_map =
1848 ComputeTransitionedMap(receiver_map, store_mode);
1849 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001850 Handle<Code> handler =
1851 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1852 monomorphic_map, language_mode(), store_mode);
1853 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler);
1854 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855 }
1856
1857 // There are several special cases where an IC that is MONOMORPHIC can still
1858 // transition to a different GetNonTransitioningStoreMode IC that handles a
1859 // superset of the original IC. Handle those here if the receiver map hasn't
1860 // changed or it has transitioned to a more general kind.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001861 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001862 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1863 if (state() == MONOMORPHIC) {
1864 Handle<Map> transitioned_receiver_map = receiver_map;
1865 if (IsTransitionStoreMode(store_mode)) {
1866 transitioned_receiver_map =
1867 ComputeTransitionedMap(receiver_map, store_mode);
1868 }
1869 if ((receiver_map.is_identical_to(previous_receiver_map) &&
1870 IsTransitionStoreMode(store_mode)) ||
1871 IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1872 *transitioned_receiver_map)) {
1873 // If the "old" and "new" maps are in the same elements map family, or
1874 // if they at least come from the same origin for a transitioning store,
1875 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1876 store_mode = GetNonTransitioningStoreMode(store_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001877 Handle<Code> handler =
1878 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1879 transitioned_receiver_map, language_mode(), store_mode);
1880 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map,
1881 handler);
1882 return null_handle;
1883 } else if (receiver_map.is_identical_to(previous_receiver_map) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 old_store_mode == STANDARD_STORE &&
1885 (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1886 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1887 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1888 // A "normal" IC that handles stores can switch to a version that can
1889 // grow at the end of the array, handle OOB accesses or copy COW arrays
1890 // and still stay MONOMORPHIC.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001891 Handle<Code> handler =
1892 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
1893 receiver_map, language_mode(), store_mode);
1894 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
1895 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001896 }
1897 }
1898
1899 DCHECK(state() != GENERIC);
1900
1901 bool map_added =
1902 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1903
1904 if (IsTransitionStoreMode(store_mode)) {
1905 Handle<Map> transitioned_receiver_map =
1906 ComputeTransitionedMap(receiver_map, store_mode);
1907 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1908 transitioned_receiver_map);
1909 }
1910
1911 if (!map_added) {
1912 // If the miss wasn't due to an unseen map, a polymorphic stub
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001913 // won't help, use the megamorphic stub which can handle everything.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001914 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001915 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 }
1917
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001918 // If the maximum number of receiver maps has been exceeded, use the
1919 // megamorphic version of the IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001921 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001922 }
1923
1924 // Make sure all polymorphic handlers have the same store mode, otherwise the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001925 // megamorphic stub must be used.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 store_mode = GetNonTransitioningStoreMode(store_mode);
1927 if (old_store_mode != STANDARD_STORE) {
1928 if (store_mode == STANDARD_STORE) {
1929 store_mode = old_store_mode;
1930 } else if (store_mode != old_store_mode) {
1931 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001932 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 }
1934 }
1935
1936 // If the store mode isn't the standard mode, make sure that all polymorphic
1937 // receivers are either external arrays, or all "normal" arrays. Otherwise,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001938 // use the megamorphic stub.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 if (store_mode != STANDARD_STORE) {
1940 int external_arrays = 0;
1941 for (int i = 0; i < target_receiver_maps.length(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001942 if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 external_arrays++;
1944 }
1945 }
1946 if (external_arrays != 0 &&
1947 external_arrays != target_receiver_maps.length()) {
1948 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
1949 "unsupported combination of external and normal arrays");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001950 return megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951 }
1952 }
1953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001954 MapHandleList transitioned_maps(target_receiver_maps.length());
1955 CodeHandleList handlers(target_receiver_maps.length());
1956 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
1957 &target_receiver_maps, &transitioned_maps, &handlers, store_mode,
1958 language_mode());
1959 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
1960 return null_handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961}
1962
1963
1964Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1965 Handle<Map> map, KeyedAccessStoreMode store_mode) {
1966 switch (store_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001967 case STORE_TRANSITION_TO_OBJECT:
1968 case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1969 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1970 ? FAST_HOLEY_ELEMENTS
1971 : FAST_ELEMENTS;
1972 return Map::TransitionElementsTo(map, kind);
1973 }
1974 case STORE_TRANSITION_TO_DOUBLE:
1975 case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1976 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
1977 ? FAST_HOLEY_DOUBLE_ELEMENTS
1978 : FAST_DOUBLE_ELEMENTS;
1979 return Map::TransitionElementsTo(map, kind);
1980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001982 DCHECK(map->has_fixed_typed_array_elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983 // Fall through
1984 case STORE_NO_TRANSITION_HANDLE_COW:
1985 case STANDARD_STORE:
1986 case STORE_AND_GROW_NO_TRANSITION:
1987 return map;
1988 }
1989 UNREACHABLE();
1990 return MaybeHandle<Map>().ToHandleChecked();
1991}
1992
1993
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001994bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
1995 uint32_t length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001996 if (receiver->IsJSArray()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001997 JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1998 } else {
1999 length = static_cast<uint32_t>(receiver->elements()->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001 return index >= length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002}
2003
2004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002005static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2006 uint32_t index, Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002007 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2008 // Don't consider this a growing store if the store would send the receiver to
2009 // dictionary mode.
2010 bool allow_growth = receiver->IsJSArray() && oob_access &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002011 !receiver->WouldConvertToSlowElements(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002012 if (allow_growth) {
2013 // Handle growing array in stub if necessary.
2014 if (receiver->HasFastSmiElements()) {
2015 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002016 return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002017 }
2018 if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002019 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002020 }
2021 } else if (receiver->HasFastDoubleElements()) {
2022 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002023 return STORE_AND_GROW_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002024 }
2025 }
2026 return STORE_AND_GROW_NO_TRANSITION;
2027 } else {
2028 // Handle only in-bounds elements accesses.
2029 if (receiver->HasFastSmiElements()) {
2030 if (value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002031 return STORE_TRANSITION_TO_DOUBLE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002032 } else if (value->IsHeapObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002033 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002034 }
2035 } else if (receiver->HasFastDoubleElements()) {
2036 if (!value->IsSmi() && !value->IsHeapNumber()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002037 return STORE_TRANSITION_TO_OBJECT;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002038 }
2039 }
2040 if (!FLAG_trace_external_array_abuse &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002041 receiver->map()->has_fixed_typed_array_elements() && oob_access) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2043 }
2044 Heap* heap = receiver->GetHeap();
2045 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2046 return STORE_NO_TRANSITION_HANDLE_COW;
2047 } else {
2048 return STANDARD_STORE;
2049 }
2050 }
2051}
2052
2053
2054MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2055 Handle<Object> key,
2056 Handle<Object> value) {
2057 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2058 // might deprecate the current map again, if value does not fit.
2059 if (MigrateDeprecated(object)) {
2060 Handle<Object> result;
2061 ASSIGN_RETURN_ON_EXCEPTION(
2062 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002063 value, language_mode()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002064 Object);
2065 return result;
2066 }
2067
2068 // Check for non-string values that can be converted into an
2069 // internalized string directly or is representable as a smi.
2070 key = TryConvertKey(key, isolate());
2071
2072 Handle<Object> store_handle;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002073 Handle<Code> stub = megamorphic_stub();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002074
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002075 uint32_t index;
2076 if ((key->IsInternalizedString() &&
2077 !String::cast(*key)->AsArrayIndex(&index)) ||
2078 key->IsSymbol()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 ASSIGN_RETURN_ON_EXCEPTION(
2080 isolate(), store_handle,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002081 StoreIC::Store(object, Handle<Name>::cast(key), value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002082 JSReceiver::MAY_BE_STORE_FROM_KEYED),
2083 Object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002084 if (!is_vector_set()) {
2085 ConfigureVectorState(MEGAMORPHIC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002086 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2087 "unhandled internalized string key");
2088 TRACE_IC("StoreIC", key);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002089 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002090 return store_handle;
2091 }
2092
2093 bool use_ic =
2094 FLAG_use_ic && !object->IsStringWrapper() &&
2095 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() &&
2096 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed());
2097 if (use_ic && !object->IsSmi()) {
2098 // Don't use ICs for maps of the objects in Array's prototype chain. We
2099 // expect to be able to trap element sets to objects with those maps in
2100 // the runtime to enable optimization of element hole access.
2101 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2102 if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2103 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype");
2104 use_ic = false;
2105 }
2106 }
2107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002108 Handle<Map> old_receiver_map;
2109 bool sloppy_arguments_elements = false;
2110 bool key_is_valid_index = false;
2111 KeyedAccessStoreMode store_mode = STANDARD_STORE;
2112 if (use_ic && object->IsJSObject()) {
2113 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2114 old_receiver_map = handle(receiver->map(), isolate());
2115 sloppy_arguments_elements =
2116 !is_sloppy(language_mode()) &&
2117 receiver->elements()->map() ==
2118 isolate()->heap()->sloppy_arguments_elements_map();
2119 if (!sloppy_arguments_elements) {
2120 key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
2121 if (key_is_valid_index) {
2122 uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2123 store_mode = GetStoreMode(receiver, index, value);
2124 }
2125 }
2126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002128 DCHECK(store_handle.is_null());
2129 ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2130 Runtime::SetObjectProperty(isolate(), object, key,
2131 value, language_mode()),
2132 Object);
2133
2134 if (use_ic) {
2135 if (!old_receiver_map.is_null()) {
2136 if (sloppy_arguments_elements) {
2137 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver");
2138 } else if (key_is_valid_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002139 // We should go generic if receiver isn't a dictionary, but our
2140 // prototype chain does have dictionary elements. This ensures that
2141 // other non-dictionary receivers in the polymorphic case benefit
2142 // from fast path keyed stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002143 if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2144 stub = StoreElementStub(old_receiver_map, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002145 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002146 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2147 "dictionary or proxy prototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002148 }
2149 } else {
2150 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key");
2151 }
2152 } else {
2153 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver");
2154 }
2155 }
2156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002157 if (!is_vector_set() || stub.is_null()) {
2158 Code* megamorphic = *megamorphic_stub();
2159 if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) {
2160 ConfigureVectorState(MEGAMORPHIC);
2161 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
2162 *stub == megamorphic ? "set generic" : "slow stub");
2163 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002164 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002165 TRACE_IC("StoreIC", key);
2166
2167 return store_handle;
2168}
2169
2170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002171void CallIC::HandleMiss(Handle<Object> function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002172 Handle<Object> name = isolate()->factory()->empty_string();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002173 CallICNexus* nexus = casted_nexus<CallICNexus>();
2174 Object* feedback = nexus->GetFeedback();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002175
2176 // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
2177 DCHECK(!feedback->IsSmi());
2178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002179 if (feedback->IsWeakCell() || !function->IsJSFunction() ||
2180 feedback->IsAllocationSite()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002181 // We are going generic.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002182 nexus->ConfigureMegamorphic();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002183 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002184 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
2185 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002187 Handle<JSFunction> array_function =
2188 Handle<JSFunction>(isolate()->native_context()->array_function());
2189 if (array_function.is_identical_to(js_function)) {
2190 // Alter the slot.
2191 nexus->ConfigureMonomorphicArray();
2192 } else if (js_function->context()->native_context() !=
2193 *isolate()->native_context()) {
2194 // Don't collect cross-native context feedback for the CallIC.
2195 // TODO(bmeurer): We should collect the SharedFunctionInfo as
2196 // feedback in this case instead.
2197 nexus->ConfigureMegamorphic();
2198 } else {
2199 nexus->ConfigureMonomorphic(js_function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002200 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002201 }
2202
2203 if (function->IsJSFunction()) {
2204 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
2205 name = handle(js_function->shared()->name(), isolate());
2206 }
2207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002208 OnTypeFeedbackChanged(isolate(), get_host());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002209 TRACE_IC("CallIC", name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002210}
2211
2212
2213#undef TRACE_IC
2214
2215
2216// ----------------------------------------------------------------------------
2217// Static IC stub generators.
2218//
2219
2220// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002221RUNTIME_FUNCTION(Runtime_CallIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 TimerEventScope<TimerEventIcMiss> timer(isolate);
2223 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002224 DCHECK(args.length() == 3);
2225 Handle<Object> function = args.at<Object>(0);
2226 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1);
2227 Handle<Smi> slot = args.at<Smi>(2);
2228 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002229 CallICNexus nexus(vector, vector_slot);
2230 CallIC ic(isolate, &nexus);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002231 ic.HandleMiss(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002232 return *function;
2233}
2234
2235
2236// Used from ic-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002237RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238 TimerEventScope<TimerEventIcMiss> timer(isolate);
2239 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);
2271 HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002272 Handle<Object> receiver = args.at<Object>(0);
2273 Handle<Object> key = args.at<Object>(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002274 Handle<Object> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002275
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 DCHECK(args.length() == 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002277 Handle<Smi> slot = args.at<Smi>(2);
2278 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2279 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2280 KeyedLoadICNexus nexus(vector, vector_slot);
2281 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2282 ic.UpdateState(receiver, key);
2283 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2284 return *result;
2285}
2286
2287
2288RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) {
2289 TimerEventScope<TimerEventIcMiss> timer(isolate);
2290 HandleScope scope(isolate);
2291 Handle<Object> receiver = args.at<Object>(0);
2292 Handle<Object> key = args.at<Object>(1);
2293 Handle<Object> result;
2294
2295 DCHECK(args.length() == 4);
2296 Handle<Smi> slot = args.at<Smi>(2);
2297 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2298 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2299 KeyedLoadICNexus nexus(vector, vector_slot);
2300 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2301 ic.UpdateState(receiver, key);
2302 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2303
2304 return *result;
2305}
2306
2307
2308// Used from ic-<arch>.cc.
2309RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2310 TimerEventScope<TimerEventIcMiss> timer(isolate);
2311 HandleScope scope(isolate);
2312 Handle<Object> receiver = args.at<Object>(0);
2313 Handle<Name> key = args.at<Name>(1);
2314 Handle<Object> value = args.at<Object>(2);
2315 Handle<Object> result;
2316
2317 DCHECK(args.length() == 5 || args.length() == 6);
2318 Handle<Smi> slot = args.at<Smi>(3);
2319 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2320 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2321 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2322 StoreICNexus nexus(vector, vector_slot);
2323 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2324 ic.UpdateState(receiver, key);
2325 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2326 ic.Store(receiver, key, value));
2327 } else {
2328 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2329 vector->GetKind(vector_slot));
2330 KeyedStoreICNexus nexus(vector, vector_slot);
2331 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2332 ic.UpdateState(receiver, key);
2333 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2334 ic.Store(receiver, key, value));
2335 }
2336 return *result;
2337}
2338
2339
2340RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) {
2341 TimerEventScope<TimerEventIcMiss> timer(isolate);
2342 HandleScope scope(isolate);
2343 Handle<Object> receiver = args.at<Object>(0);
2344 Handle<Name> key = args.at<Name>(1);
2345 Handle<Object> value = args.at<Object>(2);
2346 Handle<Object> result;
2347
2348 int length = args.length();
2349 DCHECK(length == 5 || length == 6);
2350 // We might have slot and vector, for a normal miss (slot(3), vector(4)).
2351 // Or, map and vector for a transitioning store miss (map(3), vector(4)).
2352 // In this case, we need to recover the slot from a virtual register.
2353 // If length == 6, then a map is included (map(3), slot(4), vector(5)).
2354 Handle<Smi> slot;
2355 Handle<TypeFeedbackVector> vector;
2356 if (length == 5) {
2357 if (args.at<Object>(3)->IsMap()) {
2358 vector = args.at<TypeFeedbackVector>(4);
2359 slot = handle(
2360 *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()),
2361 isolate);
2362 } else {
2363 vector = args.at<TypeFeedbackVector>(4);
2364 slot = args.at<Smi>(3);
2365 }
2366 } else {
2367 vector = args.at<TypeFeedbackVector>(5);
2368 slot = args.at<Smi>(4);
2369 }
2370
2371 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2372 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) {
2373 StoreICNexus nexus(vector, vector_slot);
2374 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2375 ic.UpdateState(receiver, key);
2376 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2377 ic.Store(receiver, key, value));
2378 } else {
2379 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC,
2380 vector->GetKind(vector_slot));
2381 KeyedStoreICNexus nexus(vector, vector_slot);
2382 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2383 ic.UpdateState(receiver, key);
2384 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2385 ic.Store(receiver, key, value));
2386 }
2387 return *result;
2388}
2389
2390
2391// Used from ic-<arch>.cc.
2392RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2393 TimerEventScope<TimerEventIcMiss> timer(isolate);
2394 HandleScope scope(isolate);
2395 Handle<Object> receiver = args.at<Object>(0);
2396 Handle<Object> key = args.at<Object>(1);
2397 Handle<Object> value = args.at<Object>(2);
2398 Handle<Object> result;
2399
2400 DCHECK(args.length() == 5);
2401 Handle<Smi> slot = args.at<Smi>(3);
2402 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2403 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2404 KeyedStoreICNexus nexus(vector, vector_slot);
2405 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2406 ic.UpdateState(receiver, key);
2407 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2408 ic.Store(receiver, key, value));
2409 return *result;
2410}
2411
2412
2413RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) {
2414 TimerEventScope<TimerEventIcMiss> timer(isolate);
2415 HandleScope scope(isolate);
2416 Handle<Object> receiver = args.at<Object>(0);
2417 Handle<Object> key = args.at<Object>(1);
2418 Handle<Object> value = args.at<Object>(2);
2419 Handle<Object> result;
2420
2421 DCHECK(args.length() == 5);
2422 Handle<Smi> slot = args.at<Smi>(3);
2423 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4);
2424 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2425 KeyedStoreICNexus nexus(vector, vector_slot);
2426 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2427 ic.UpdateState(receiver, key);
2428 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2429 ic.Store(receiver, key, value));
2430 return *result;
2431}
2432
2433
2434RUNTIME_FUNCTION(Runtime_StoreIC_Slow) {
2435 HandleScope scope(isolate);
2436 DCHECK(args.length() == 5);
2437 Handle<Object> object = args.at<Object>(0);
2438 Handle<Object> key = args.at<Object>(1);
2439 Handle<Object> value = args.at<Object>(2);
2440 LanguageMode language_mode;
2441 StoreICNexus nexus(isolate);
2442 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2443 language_mode = ic.language_mode();
2444 Handle<Object> result;
2445 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2446 isolate, result,
2447 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2448 return *result;
2449}
2450
2451
2452RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2453 HandleScope scope(isolate);
2454 DCHECK(args.length() == 5);
2455 Handle<Object> object = args.at<Object>(0);
2456 Handle<Object> key = args.at<Object>(1);
2457 Handle<Object> value = args.at<Object>(2);
2458 LanguageMode language_mode;
2459 KeyedStoreICNexus nexus(isolate);
2460 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2461 language_mode = ic.language_mode();
2462 Handle<Object> result;
2463 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2464 isolate, result,
2465 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2466 return *result;
2467}
2468
2469
2470RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2471 TimerEventScope<TimerEventIcMiss> timer(isolate);
2472 HandleScope scope(isolate);
2473 // Length == 5 or 6, depending on whether the vector slot
2474 // is passed in a virtual register or not.
2475 DCHECK(args.length() == 5 || args.length() == 6);
2476 Handle<Object> object = args.at<Object>(0);
2477 Handle<Object> key = args.at<Object>(1);
2478 Handle<Object> value = args.at<Object>(2);
2479 Handle<Map> map = args.at<Map>(3);
2480 LanguageMode language_mode;
2481 KeyedStoreICNexus nexus(isolate);
2482 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2483 language_mode = ic.language_mode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002484 if (object->IsJSObject()) {
2485 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2486 map->elements_kind());
2487 }
2488 Handle<Object> result;
2489 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2490 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002491 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492 return *result;
2493}
2494
2495
2496MaybeHandle<Object> BinaryOpIC::Transition(
2497 Handle<AllocationSite> allocation_site, Handle<Object> left,
2498 Handle<Object> right) {
2499 BinaryOpICState state(isolate(), target()->extra_ic_state());
2500
2501 // Compute the actual result using the builtin for the binary operation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002502 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002503 switch (state.op()) {
2504 default:
2505 UNREACHABLE();
2506 case Token::ADD:
2507 ASSIGN_RETURN_ON_EXCEPTION(
2508 isolate(), result,
2509 Object::Add(isolate(), left, right, state.strength()), Object);
2510 break;
2511 case Token::SUB:
2512 ASSIGN_RETURN_ON_EXCEPTION(
2513 isolate(), result,
2514 Object::Subtract(isolate(), left, right, state.strength()), Object);
2515 break;
2516 case Token::MUL:
2517 ASSIGN_RETURN_ON_EXCEPTION(
2518 isolate(), result,
2519 Object::Multiply(isolate(), left, right, state.strength()), Object);
2520 break;
2521 case Token::DIV:
2522 ASSIGN_RETURN_ON_EXCEPTION(
2523 isolate(), result,
2524 Object::Divide(isolate(), left, right, state.strength()), Object);
2525 break;
2526 case Token::MOD:
2527 ASSIGN_RETURN_ON_EXCEPTION(
2528 isolate(), result,
2529 Object::Modulus(isolate(), left, right, state.strength()), Object);
2530 break;
2531 case Token::BIT_OR:
2532 ASSIGN_RETURN_ON_EXCEPTION(
2533 isolate(), result,
2534 Object::BitwiseOr(isolate(), left, right, state.strength()), Object);
2535 break;
2536 case Token::BIT_AND:
2537 ASSIGN_RETURN_ON_EXCEPTION(
2538 isolate(), result,
2539 Object::BitwiseAnd(isolate(), left, right, state.strength()), Object);
2540 break;
2541 case Token::BIT_XOR:
2542 ASSIGN_RETURN_ON_EXCEPTION(
2543 isolate(), result,
2544 Object::BitwiseXor(isolate(), left, right, state.strength()), Object);
2545 break;
2546 case Token::SAR:
2547 ASSIGN_RETURN_ON_EXCEPTION(
2548 isolate(), result,
2549 Object::ShiftRight(isolate(), left, right, state.strength()), Object);
2550 break;
2551 case Token::SHR:
2552 ASSIGN_RETURN_ON_EXCEPTION(
2553 isolate(), result,
2554 Object::ShiftRightLogical(isolate(), left, right, state.strength()),
2555 Object);
2556 break;
2557 case Token::SHL:
2558 ASSIGN_RETURN_ON_EXCEPTION(
2559 isolate(), result,
2560 Object::ShiftLeft(isolate(), left, right, state.strength()), Object);
2561 break;
2562 }
2563
2564 // Do not try to update the target if the code was marked for lazy
2565 // deoptimization. (Since we do not relocate addresses in these
2566 // code objects, an attempt to access the target could fail.)
2567 if (AddressIsDeoptimizedCode()) {
2568 return result;
2569 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002570
2571 // Execution::Call can execute arbitrary JavaScript, hence potentially
2572 // update the state of this very IC, so we must update the stored state.
2573 UpdateTarget();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002574
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002575 // Compute the new state.
2576 BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2577 state.Update(left, right, result);
2578
2579 // Check if we have a string operation here.
2580 Handle<Code> target;
2581 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2582 // Setup the allocation site on-demand.
2583 if (allocation_site.is_null()) {
2584 allocation_site = isolate()->factory()->NewAllocationSite();
2585 }
2586
2587 // Install the stub with an allocation site.
2588 BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2589 target = stub.GetCodeCopyFromTemplate(allocation_site);
2590
2591 // Sanity check the trampoline stub.
2592 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite());
2593 } else {
2594 // Install the generic stub.
2595 BinaryOpICStub stub(isolate(), state);
2596 target = stub.GetCode();
2597
2598 // Sanity check the generic stub.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002599 DCHECK_NULL(target->FindFirstAllocationSite());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002600 }
2601 set_target(*target);
2602
2603 if (FLAG_trace_ic) {
2604 OFStream os(stdout);
2605 os << "[BinaryOpIC" << old_state << " => " << state << " @ "
2606 << static_cast<void*>(*target) << " <- ";
2607 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2608 if (!allocation_site.is_null()) {
2609 os << " using allocation site " << static_cast<void*>(*allocation_site);
2610 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002611 os << "]" << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002612 }
2613
2614 // Patch the inlined smi code as necessary.
2615 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002616 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002617 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002618 PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002619 }
2620
2621 return result;
2622}
2623
2624
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002625RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002626 TimerEventScope<TimerEventIcMiss> timer(isolate);
2627 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);
2642 HandleScope scope(isolate);
2643 DCHECK_EQ(3, args.length());
2644 Handle<AllocationSite> allocation_site =
2645 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite);
2646 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft);
2647 Handle<Object> right =
2648 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight);
2649 BinaryOpIC ic(isolate);
2650 Handle<Object> result;
2651 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2652 isolate, result, ic.Transition(allocation_site, left, right));
2653 return *result;
2654}
2655
2656
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002657Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op,
2658 Strength strength) {
2659 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002660 CompareICState::UNINITIALIZED,
2661 CompareICState::UNINITIALIZED);
2662 Code* code = NULL;
2663 CHECK(stub.FindCodeInCache(&code));
2664 return code;
2665}
2666
2667
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002668Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op,
2669 Strength strength) {
2670 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002671 CompareICState::UNINITIALIZED,
2672 CompareICState::UNINITIALIZED);
2673 return stub.GetCode();
2674}
2675
2676
2677Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2678 HandleScope scope(isolate());
2679 CompareICStub old_stub(target()->stub_key(), isolate());
2680 CompareICState::State new_left =
2681 CompareICState::NewInputState(old_stub.left(), x);
2682 CompareICState::State new_right =
2683 CompareICState::NewInputState(old_stub.right(), y);
2684 CompareICState::State state = CompareICState::TargetState(
2685 old_stub.state(), old_stub.left(), old_stub.right(), op_,
2686 HasInlinedSmiCode(address()), x, y);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002687 CompareICStub stub(isolate(), op_, old_stub.strength(), new_left, new_right,
2688 state);
2689 if (state == CompareICState::KNOWN_RECEIVER) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002690 stub.set_known_map(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002691 Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002692 }
2693 Handle<Code> new_target = stub.GetCode();
2694 set_target(*new_target);
2695
2696 if (FLAG_trace_ic) {
2697 PrintF("[CompareIC in ");
2698 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2699 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2700 CompareICState::GetStateName(old_stub.left()),
2701 CompareICState::GetStateName(old_stub.right()),
2702 CompareICState::GetStateName(old_stub.state()),
2703 CompareICState::GetStateName(new_left),
2704 CompareICState::GetStateName(new_right),
2705 CompareICState::GetStateName(state), Token::Name(op_),
2706 static_cast<void*>(*stub.GetCode()));
2707 }
2708
2709 // Activate inlined smi code.
2710 if (old_stub.state() == CompareICState::UNINITIALIZED) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002711 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002712 }
2713
2714 return *new_target;
2715}
2716
2717
2718// Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002719RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002720 TimerEventScope<TimerEventIcMiss> timer(isolate);
2721 HandleScope scope(isolate);
2722 DCHECK(args.length() == 3);
2723 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2724 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2725}
2726
2727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002728void CompareNilIC::Clear(Address address, Code* target, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002729 if (IsCleared(target)) return;
2730 ExtraICState state = target->extra_ic_state();
2731
2732 CompareNilICStub stub(target->GetIsolate(), state,
2733 HydrogenCodeStub::UNINITIALIZED);
2734 stub.ClearState();
2735
2736 Code* code = NULL;
2737 CHECK(stub.FindCodeInCache(&code));
2738
2739 SetTargetAtAddress(address, code, constant_pool);
2740}
2741
2742
2743Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil,
2744 Handle<Object> object) {
2745 if (object->IsNull() || object->IsUndefined()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002746 return isolate->factory()->true_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002747 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002748 return isolate->factory()->ToBoolean(object->IsUndetectableObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002749}
2750
2751
2752Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) {
2753 ExtraICState extra_ic_state = target()->extra_ic_state();
2754
2755 CompareNilICStub stub(isolate(), extra_ic_state);
2756
2757 // Extract the current supported types from the patched IC and calculate what
2758 // types must be supported as a result of the miss.
2759 bool already_monomorphic = stub.IsMonomorphic();
2760
2761 stub.UpdateStatus(object);
2762
2763 NilValue nil = stub.nil_value();
2764
2765 // Find or create the specialized stub to support the new set of types.
2766 Handle<Code> code;
2767 if (stub.IsMonomorphic()) {
2768 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL
2769 ? FirstTargetMap()
2770 : HeapObject::cast(*object)->map());
2771 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub);
2772 } else {
2773 code = stub.GetCode();
2774 }
2775 set_target(*code);
2776 return DoCompareNilSlow(isolate(), nil, object);
2777}
2778
2779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002780RUNTIME_FUNCTION(Runtime_CompareNilIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002781 TimerEventScope<TimerEventIcMiss> timer(isolate);
2782 HandleScope scope(isolate);
2783 Handle<Object> object = args.at<Object>(0);
2784 CompareNilIC ic(isolate);
2785 return *ic.CompareNil(object);
2786}
2787
2788
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002789RUNTIME_FUNCTION(Runtime_Unreachable) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002790 UNREACHABLE();
2791 CHECK(false);
2792 return isolate->heap()->undefined_value();
2793}
2794
2795
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002796Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2797 ToBooleanStub stub(isolate(), target()->extra_ic_state());
2798 bool to_boolean_value = stub.UpdateStatus(object);
2799 Handle<Code> code = stub.GetCode();
2800 set_target(*code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002801 return isolate()->factory()->ToBoolean(to_boolean_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002802}
2803
2804
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002805RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002806 TimerEventScope<TimerEventIcMiss> timer(isolate);
2807 DCHECK(args.length() == 1);
2808 HandleScope scope(isolate);
2809 Handle<Object> object = args.at<Object>(0);
2810 ToBooleanIC ic(isolate);
2811 return *ic.ToBoolean(object);
2812}
2813
2814
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002815RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002816 Handle<JSObject> receiver = args.at<JSObject>(0);
2817 Handle<JSObject> holder = args.at<JSObject>(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002818 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002819 Handle<Name> name = args.at<Name>(3);
2820 Handle<Object> value = args.at<Object>(4);
2821 HandleScope scope(isolate);
2822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002823 Handle<ExecutableAccessorInfo> callback(
2824 callback_or_cell->IsWeakCell()
2825 ? ExecutableAccessorInfo::cast(
2826 WeakCell::cast(*callback_or_cell)->value())
2827 : ExecutableAccessorInfo::cast(*callback_or_cell));
2828
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 DCHECK(callback->IsCompatibleReceiver(*receiver));
2830
2831 Address setter_address = v8::ToCData<Address>(callback->setter());
2832 v8::AccessorNameSetterCallback fun =
2833 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2834 DCHECK(fun != NULL);
2835
2836 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
2837 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2838 *holder);
2839 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
2840 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2841 return *value;
2842}
2843
2844
2845/**
2846 * Attempts to load a property with an interceptor (which must be present),
2847 * but doesn't search the prototype chain.
2848 *
2849 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
2850 * provide any value for the given name.
2851 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002852RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002853 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002854 Handle<Name> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002855 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002856 Handle<JSObject> receiver =
2857 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2858 Handle<JSObject> holder =
2859 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002860 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002861 LookupIterator it(receiver, name, holder, LookupIterator::OWN);
2862 bool done;
2863 Handle<Object> result;
2864 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2865 isolate, result, JSObject::GetPropertyWithInterceptor(&it, &done));
2866 if (done) return *result;
2867 return isolate->heap()->no_interceptor_result_sentinel();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002868}
2869
2870
2871/**
2872 * Loads a property with an interceptor performing post interceptor
2873 * lookup if interceptor failed.
2874 */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002875RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002876 HandleScope scope(isolate);
2877 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
2878 Handle<Name> name =
2879 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
2880 Handle<JSObject> receiver =
2881 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
2882 Handle<JSObject> holder =
2883 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
2884
2885 Handle<Object> result;
2886 LookupIterator it(receiver, name, holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002887 // TODO(conradw): Investigate strong mode semantics for this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2889 JSObject::GetProperty(&it));
2890
2891 if (it.IsFound()) return *result;
2892
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002893 // Return the undefined result if the reference error should not be thrown.
2894 // Note that both keyed and non-keyed loads may end up here.
2895 LoadICNexus nexus(isolate);
2896 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
2897 if (!ic.ShouldThrowReferenceError(it.GetReceiver())) {
2898 return isolate->heap()->undefined_value();
2899 }
2900
2901 // Throw a reference error.
2902 THROW_NEW_ERROR_RETURN_FAILURE(
2903 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002904}
2905
2906
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002907RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002908 HandleScope scope(isolate);
2909 DCHECK(args.length() == 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002910 StoreICNexus nexus(isolate);
2911 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002912 Handle<JSObject> receiver = args.at<JSObject>(0);
2913 Handle<Name> name = args.at<Name>(1);
2914 Handle<Object> value = args.at<Object>(2);
2915#ifdef DEBUG
2916 PrototypeIterator iter(isolate, receiver,
2917 PrototypeIterator::START_AT_RECEIVER);
2918 bool found = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002919 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002920 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
2921 if (current->IsJSObject() &&
2922 Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
2923 found = true;
2924 break;
2925 }
2926 }
2927 DCHECK(found);
2928#endif
2929 Handle<Object> result;
2930 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2931 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002932 JSObject::SetProperty(receiver, name, value, ic.language_mode()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002933 return *result;
2934}
2935
2936
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002937RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2938 // TODO(verwaest): This should probably get the holder and receiver as input.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002939 HandleScope scope(isolate);
2940 Handle<JSObject> receiver = args.at<JSObject>(0);
2941 DCHECK(args.smi_at(1) >= 0);
2942 uint32_t index = args.smi_at(1);
2943 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002944 // TODO(conradw): Investigate strong mode semantics for this.
2945 LanguageMode language_mode = SLOPPY;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002946 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2947 isolate, result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002948 Object::GetElement(isolate, receiver, index, language_mode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002949 return *result;
2950}
2951
2952
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002953RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002954 TimerEventScope<TimerEventIcMiss> timer(isolate);
2955 HandleScope scope(isolate);
2956 Handle<Object> receiver = args.at<Object>(0);
2957 Handle<Name> key = args.at<Name>(1);
2958 Handle<Object> result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002959
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002960 DCHECK(args.length() == 4);
2961 Handle<Smi> slot = args.at<Smi>(2);
2962 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
2963 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value());
2964 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2965 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2966 // set up outside the IC, handle that here.
2967 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) {
2968 LoadICNexus nexus(vector, vector_slot);
2969 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
2970 ic.UpdateState(receiver, key);
2971 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002972 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002973 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC,
2974 vector->GetKind(vector_slot));
2975 KeyedLoadICNexus nexus(vector, vector_slot);
2976 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002977 ic.UpdateState(receiver, key);
2978 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
2979 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002980
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002981 return *result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002982}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002983} // namespace internal
2984} // namespace v8