Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/ic/ic.h"
6 :
7 : #include "src/accessors.h"
8 : #include "src/api-arguments-inl.h"
9 : #include "src/api.h"
10 : #include "src/arguments.h"
11 : #include "src/base/bits.h"
12 : #include "src/codegen.h"
13 : #include "src/conversions.h"
14 : #include "src/execution.h"
15 : #include "src/field-type.h"
16 : #include "src/frames-inl.h"
17 : #include "src/ic/call-optimization.h"
18 : #include "src/ic/handler-compiler.h"
19 : #include "src/ic/handler-configuration-inl.h"
20 : #include "src/ic/ic-inl.h"
21 : #include "src/ic/ic-stats.h"
22 : #include "src/ic/stub-cache.h"
23 : #include "src/isolate-inl.h"
24 : #include "src/macro-assembler.h"
25 : #include "src/prototype.h"
26 : #include "src/runtime-profiler.h"
27 : #include "src/runtime/runtime-utils.h"
28 : #include "src/runtime/runtime.h"
29 : #include "src/tracing/trace-event.h"
30 : #include "src/tracing/tracing-category-observer.h"
31 :
32 : namespace v8 {
33 : namespace internal {
34 :
35 0 : char IC::TransitionMarkFromState(IC::State state) {
36 0 : switch (state) {
37 : case UNINITIALIZED:
38 : return '0';
39 : case PREMONOMORPHIC:
40 0 : return '.';
41 : case MONOMORPHIC:
42 0 : return '1';
43 : case RECOMPUTE_HANDLER:
44 0 : return '^';
45 : case POLYMORPHIC:
46 0 : return 'P';
47 : case MEGAMORPHIC:
48 0 : return 'N';
49 : case GENERIC:
50 0 : return 'G';
51 : }
52 0 : UNREACHABLE();
53 : return 0;
54 : }
55 :
56 :
57 0 : const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
58 0 : if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
59 0 : if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
60 : return ".IGNORE_OOB";
61 : }
62 0 : if (IsGrowStoreMode(mode)) return ".GROW";
63 0 : return "";
64 : }
65 :
66 : #define TRACE_GENERIC_IC(reason) set_slow_stub_reason(reason);
67 :
68 13450565 : void IC::TraceIC(const char* type, Handle<Object> name) {
69 13450565 : if (FLAG_ic_stats) {
70 13450565 : if (AddressIsDeoptimizedCode()) return;
71 0 : State new_state = nexus()->StateFromFeedback();
72 0 : TraceIC(type, name, state(), new_state);
73 : }
74 : }
75 :
76 0 : Address IC::GetAbstractPC(int* line, int* column) const {
77 0 : JavaScriptFrameIterator it(isolate());
78 :
79 : JavaScriptFrame* frame = it.frame();
80 : DCHECK(!frame->is_builtin());
81 0 : int position = frame->position();
82 :
83 0 : Object* maybe_script = frame->function()->shared()->script();
84 0 : if (maybe_script->IsScript()) {
85 : Handle<Script> script(Script::cast(maybe_script), isolate());
86 : Script::PositionInfo info;
87 0 : Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET);
88 0 : *line = info.line + 1;
89 0 : *column = info.column + 1;
90 : } else {
91 0 : *line = position;
92 0 : *column = -1;
93 : }
94 :
95 0 : if (frame->is_interpreted()) {
96 : InterpretedFrame* iframe = static_cast<InterpretedFrame*>(frame);
97 : Address bytecode_start =
98 0 : reinterpret_cast<Address>(iframe->GetBytecodeArray()) - kHeapObjectTag +
99 0 : BytecodeArray::kHeaderSize;
100 0 : return bytecode_start + iframe->GetBytecodeOffset();
101 : }
102 :
103 0 : return frame->pc();
104 : }
105 :
106 0 : void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
107 0 : State new_state) {
108 0 : if (V8_LIKELY(!FLAG_ic_stats)) return;
109 :
110 : Map* map = nullptr;
111 0 : if (!receiver_map().is_null()) {
112 : map = *receiver_map();
113 : }
114 :
115 : const char* modifier = "";
116 0 : if (IsKeyedStoreIC()) {
117 : KeyedAccessStoreMode mode =
118 0 : casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
119 : modifier = GetTransitionMarkModifier(mode);
120 : }
121 :
122 0 : if (!(FLAG_ic_stats &
123 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
124 : int line;
125 : int column;
126 0 : Address pc = GetAbstractPC(&line, &column);
127 0 : LOG(isolate(), ICEvent(type, is_keyed(), pc, line, column, map, *name,
128 : TransitionMarkFromState(old_state),
129 : TransitionMarkFromState(new_state), modifier,
130 : slow_stub_reason_));
131 : return;
132 : }
133 :
134 0 : ICStats::instance()->Begin();
135 : ICInfo& ic_info = ICStats::instance()->Current();
136 0 : ic_info.type = is_keyed() ? "Keyed" : "";
137 : ic_info.type += type;
138 :
139 : Object* maybe_function =
140 0 : Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset);
141 : DCHECK(maybe_function->IsJSFunction());
142 : JSFunction* function = JSFunction::cast(maybe_function);
143 : int code_offset = 0;
144 0 : if (function->IsInterpreted()) {
145 0 : code_offset = InterpretedFrame::GetBytecodeOffset(fp());
146 : } else {
147 : code_offset =
148 0 : static_cast<int>(pc() - function->code()->instruction_start());
149 : }
150 : JavaScriptFrame::CollectFunctionAndOffsetForICStats(
151 0 : function, function->abstract_code(), code_offset);
152 :
153 : // Reserve enough space for IC transition state, the longest length is 17.
154 0 : ic_info.state.reserve(17);
155 : ic_info.state = "(";
156 0 : ic_info.state += TransitionMarkFromState(old_state);
157 : ic_info.state += "->";
158 0 : ic_info.state += TransitionMarkFromState(new_state);
159 : ic_info.state += modifier;
160 : ic_info.state += ")";
161 0 : ic_info.map = reinterpret_cast<void*>(map);
162 0 : if (map != nullptr) {
163 0 : ic_info.is_dictionary_map = map->is_dictionary_map();
164 0 : ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
165 0 : ic_info.instance_type = std::to_string(map->instance_type());
166 : }
167 : // TODO(lpy) Add name as key field in ICStats.
168 0 : ICStats::instance()->End();
169 : }
170 :
171 :
172 : #define TRACE_IC(type, name) TraceIC(type, name)
173 :
174 14598146 : IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
175 : : isolate_(isolate),
176 : vector_set_(false),
177 : kind_(FeedbackSlotKind::kInvalid),
178 : target_maps_set_(false),
179 : slow_stub_reason_(nullptr),
180 29196292 : nexus_(nexus) {
181 : // To improve the performance of the (much used) IC code, we unfold a few
182 : // levels of the stack frame iteration code. This yields a ~35% speedup when
183 : // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
184 14598146 : const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
185 : Address* constant_pool = NULL;
186 : if (FLAG_enable_embedded_constant_pool) {
187 : constant_pool = reinterpret_cast<Address*>(
188 : entry + ExitFrameConstants::kConstantPoolOffset);
189 : }
190 : Address* pc_address =
191 14598146 : reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
192 14598146 : Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
193 : // If there's another JavaScript frame on the stack or a
194 : // StubFailureTrampoline, we need to look one frame further down the stack to
195 : // find the frame pointer and the return address stack slot.
196 14598146 : if (depth == EXTRA_CALL_FRAME) {
197 : if (FLAG_enable_embedded_constant_pool) {
198 : constant_pool = reinterpret_cast<Address*>(
199 : fp + StandardFrameConstants::kConstantPoolOffset);
200 : }
201 : const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
202 841413 : pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
203 841413 : fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
204 : }
205 : #ifdef DEBUG
206 : StackFrameIterator it(isolate);
207 : for (int i = 0; i < depth + 1; i++) it.Advance();
208 : StackFrame* frame = it.frame();
209 : DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
210 : #endif
211 : // For interpreted functions, some bytecode handlers construct a
212 : // frame. We have to skip the constructed frame to find the interpreted
213 : // function's frame. Check if the there is an additional frame, and if there
214 : // is skip this frame. However, the pc should not be updated. The call to
215 : // ICs happen from bytecode handlers.
216 : intptr_t frame_marker =
217 14598146 : Memory::intptr_at(fp + TypedFrameConstants::kFrameTypeOffset);
218 14598146 : if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
219 9080537 : fp = Memory::Address_at(fp + TypedFrameConstants::kCallerFPOffset);
220 : }
221 14598146 : fp_ = fp;
222 : if (FLAG_enable_embedded_constant_pool) {
223 : constant_pool_address_ = constant_pool;
224 : }
225 14598146 : pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
226 14598146 : if (nexus) {
227 13756733 : kind_ = nexus->kind();
228 13756737 : state_ = nexus->StateFromFeedback();
229 13756733 : extra_ic_state_ = kNoExtraICState;
230 : } else {
231 841413 : Code* target = this->target();
232 : Code::Kind kind = target->kind();
233 841413 : if (kind == Code::BINARY_OP_IC) {
234 437808 : kind_ = FeedbackSlotKind::kBinaryOp;
235 403605 : } else if (kind == Code::COMPARE_IC) {
236 272912 : kind_ = FeedbackSlotKind::kCompareOp;
237 130693 : } else if (kind == Code::TO_BOOLEAN_IC) {
238 130693 : kind_ = FeedbackSlotKind::kToBoolean;
239 : } else {
240 0 : UNREACHABLE();
241 : kind_ = FeedbackSlotKind::kInvalid;
242 : }
243 841413 : state_ = StateFromCode(target);
244 841413 : extra_ic_state_ = target->extra_ic_state();
245 : }
246 14598146 : old_state_ = state_;
247 14598146 : }
248 :
249 : // The ICs that don't pass slot and vector through the stack have to
250 : // save/restore them in the dispatcher.
251 77396 : bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
252 77396 : if (kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
253 : kind == Code::KEYED_LOAD_IC) {
254 : return true;
255 : }
256 76842 : if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
257 : return !StoreWithVectorDescriptor::kPassLastArgsOnStack;
258 : }
259 0 : return false;
260 : }
261 :
262 2516237 : InlineCacheState IC::StateFromCode(Code* code) {
263 : Isolate* isolate = code->GetIsolate();
264 2516237 : switch (code->kind()) {
265 : case Code::BINARY_OP_IC: {
266 1305418 : BinaryOpICState state(isolate, code->extra_ic_state());
267 1305418 : return state.GetICState();
268 : }
269 : case Code::COMPARE_IC: {
270 : CompareICStub stub(isolate, code->extra_ic_state());
271 818740 : return stub.GetICState();
272 : }
273 : case Code::TO_BOOLEAN_IC: {
274 : ToBooleanICStub stub(isolate, code->extra_ic_state());
275 : return stub.GetICState();
276 : }
277 : default:
278 0 : if (code->is_debug_stub()) return UNINITIALIZED;
279 0 : UNREACHABLE();
280 : return UNINITIALIZED;
281 : }
282 : }
283 :
284 38031045 : JSFunction* IC::GetHostFunction() const {
285 : // Compute the JavaScript frame for the frame pointer of this IC
286 : // structure. We need this to be able to find the function
287 : // corresponding to the frame.
288 10447462 : StackFrameIterator it(isolate());
289 38031046 : while (it.frame()->fp() != this->fp()) it.Advance();
290 : JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
291 : // Find the function on the stack and both the active code for the
292 : // function and the original code.
293 20894918 : return frame->function();
294 : }
295 :
296 13392844 : static void LookupForRead(LookupIterator* it) {
297 13431098 : for (; it->IsFound(); it->Next()) {
298 6281840 : switch (it->state()) {
299 : case LookupIterator::NOT_FOUND:
300 : case LookupIterator::TRANSITION:
301 0 : UNREACHABLE();
302 : case LookupIterator::JSPROXY:
303 : return;
304 : case LookupIterator::INTERCEPTOR: {
305 : // If there is a getter, return; otherwise loop to perform the lookup.
306 : Handle<JSObject> holder = it->GetHolder<JSObject>();
307 2560 : if (!holder->GetNamedInterceptor()->getter()->IsUndefined(
308 2560 : it->isolate())) {
309 : return;
310 : }
311 : break;
312 : }
313 : case LookupIterator::ACCESS_CHECK:
314 : // ICs know how to perform access checks on global proxies.
315 41067 : if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
316 : break;
317 : }
318 : return;
319 : case LookupIterator::ACCESSOR:
320 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
321 : case LookupIterator::DATA:
322 : return;
323 : }
324 : }
325 : }
326 :
327 6647276 : bool IC::ShouldRecomputeHandler(Handle<String> name) {
328 2232162 : if (!RecomputeHandlerForName(name)) return false;
329 :
330 2207557 : maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
331 :
332 : // This is a contextual access, always just update the handler and stay
333 : // monomorphic.
334 2207557 : if (IsLoadGlobalIC()) return true;
335 :
336 : // The current map wasn't handled yet. There's no reason to stay monomorphic,
337 : // *unless* we're moving from a deprecated map to its replacement, or
338 : // to a more general elements kind.
339 : // TODO(verwaest): Check if the current map is actually what the old map
340 : // would transition to.
341 2206753 : if (maybe_handler_.is_null()) {
342 2096521 : if (!receiver_map()->IsJSObjectMap()) return false;
343 2084025 : Map* first_map = FirstTargetMap();
344 2084025 : if (first_map == NULL) return false;
345 : Handle<Map> old_map(first_map);
346 701348 : if (old_map->is_deprecated()) return true;
347 : return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
348 472530 : receiver_map()->elements_kind());
349 : }
350 :
351 : return true;
352 : }
353 :
354 2264072 : bool IC::RecomputeHandlerForName(Handle<Object> name) {
355 2232162 : if (is_keyed()) {
356 : // Determine whether the failure is due to a name failure.
357 31910 : if (!name->IsName()) return false;
358 31910 : Name* stub_name = nexus()->FindFirstName();
359 31910 : if (*name != stub_name) return false;
360 : }
361 :
362 : return true;
363 : }
364 :
365 :
366 28781736 : void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
367 13756733 : update_receiver_map(receiver);
368 13756733 : if (!name->IsString()) return;
369 12792623 : if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
370 2232380 : if (receiver->IsNullOrUndefined(isolate())) return;
371 :
372 : // Remove the target from the code cache if it became invalid
373 : // because of changes in the prototype chain to avoid hitting it
374 : // again.
375 2232162 : if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
376 : MarkRecomputeHandler(name);
377 : }
378 : }
379 :
380 :
381 3468 : MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index,
382 3468 : Handle<Object> object, Handle<Object> key) {
383 : HandleScope scope(isolate());
384 10404 : THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
385 : }
386 :
387 :
388 140293 : MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
389 : HandleScope scope(isolate());
390 420879 : THROW_NEW_ERROR(
391 : isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
392 : }
393 :
394 :
395 764022 : static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
396 : int* polymorphic_delta,
397 : int* generic_delta) {
398 764022 : switch (old_state) {
399 : case UNINITIALIZED:
400 : case PREMONOMORPHIC:
401 723801 : if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
402 723801 : if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
403 712489 : *polymorphic_delta = 1;
404 11312 : } else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
405 11312 : *generic_delta = 1;
406 : }
407 : break;
408 : case MONOMORPHIC:
409 : case POLYMORPHIC:
410 40148 : if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
411 13250 : *polymorphic_delta = -1;
412 13250 : if (new_state == MEGAMORPHIC || new_state == GENERIC) {
413 13248 : *generic_delta = 1;
414 : }
415 : break;
416 : case MEGAMORPHIC:
417 : case GENERIC:
418 73 : if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
419 0 : *generic_delta = -1;
420 0 : if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
421 0 : *polymorphic_delta = 1;
422 : }
423 : break;
424 : case RECOMPUTE_HANDLER:
425 0 : UNREACHABLE();
426 : }
427 764022 : }
428 :
429 : // static
430 20781286 : void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
431 : Code* host = host_function->shared()->code();
432 :
433 10390643 : if (host->kind() == Code::FUNCTION) {
434 : TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
435 : info->change_own_type_change_checksum();
436 : host->set_profiler_ticks(0);
437 7177312 : } else if (host_function->IsInterpreted()) {
438 6645899 : if (FLAG_trace_opt_verbose) {
439 0 : if (host_function->shared()->profiler_ticks() != 0) {
440 0 : PrintF("[resetting ticks for ");
441 0 : host_function->PrintName();
442 : PrintF(" due from %d due to IC change]\n",
443 0 : host_function->shared()->profiler_ticks());
444 : }
445 : }
446 : host_function->shared()->set_profiler_ticks(0);
447 : }
448 : isolate->runtime_profiler()->NotifyICChanged();
449 : // TODO(2029): When an optimized function is patched, it would
450 : // be nice to propagate the corresponding type information to its
451 : // unoptimized version for the benefit of later inlining.
452 10390643 : }
453 :
454 837412 : void IC::PostPatching(Address address, Code* target, Code* old_target) {
455 : // Type vector based ICs update these statistics at a different time because
456 : // they don't always patch on state change.
457 : DCHECK(target->kind() == Code::BINARY_OP_IC ||
458 : target->kind() == Code::COMPARE_IC ||
459 : target->kind() == Code::TO_BOOLEAN_IC);
460 :
461 : DCHECK(old_target->is_inline_cache_stub());
462 : DCHECK(target->is_inline_cache_stub());
463 837412 : State old_state = StateFromCode(old_target);
464 837412 : State new_state = StateFromCode(target);
465 :
466 1601434 : Isolate* isolate = target->GetIsolate();
467 : Code* host =
468 837412 : isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
469 1674824 : if (host->kind() != Code::FUNCTION) return;
470 :
471 : // Not all Code objects have TypeFeedbackInfo.
472 764022 : if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
473 764022 : if (FLAG_type_info_threshold > 0) {
474 764022 : int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
475 764022 : int generic_delta = 0; // "Generic" here includes megamorphic.
476 : ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
477 764022 : &generic_delta);
478 : TypeFeedbackInfo* info =
479 : TypeFeedbackInfo::cast(host->type_feedback_info());
480 764022 : info->change_ic_with_type_info_count(polymorphic_delta);
481 764022 : info->change_ic_generic_count(generic_delta);
482 : }
483 : TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
484 : info->change_own_type_change_checksum();
485 : }
486 : host->set_profiler_ticks(0);
487 : isolate->runtime_profiler()->NotifyICChanged();
488 : // TODO(2029): When an optimized function is patched, it would
489 : // be nice to propagate the corresponding type information to its
490 : // unoptimized version for the benefit of later inlining.
491 : }
492 :
493 132634 : void IC::Clear(Isolate* isolate, Address address, Address constant_pool) {
494 132634 : Code* target = GetTargetAtAddress(address, constant_pool);
495 :
496 : // Don't clear debug break inline cache as it will remove the break point.
497 265268 : if (target->is_debug_stub()) return;
498 :
499 132634 : if (target->kind() == Code::COMPARE_IC) {
500 5029 : CompareIC::Clear(isolate, address, target, constant_pool);
501 : }
502 : }
503 :
504 5029 : void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
505 : Address constant_pool) {
506 : DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
507 : CompareICStub stub(target->stub_key(), isolate);
508 : // Only clear CompareICs that can retain objects.
509 10058 : if (stub.state() != CompareICState::KNOWN_RECEIVER) return;
510 : SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
511 2 : constant_pool);
512 2 : PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK);
513 : }
514 :
515 14261528 : static bool MigrateDeprecated(Handle<Object> object) {
516 14261528 : if (!object->IsJSObject()) return false;
517 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
518 14019054 : if (!receiver->map()->is_deprecated()) return false;
519 7435 : JSObject::MigrateInstance(Handle<JSObject>::cast(object));
520 7435 : return true;
521 : }
522 :
523 15151794 : void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
524 5050598 : if (new_state == PREMONOMORPHIC) {
525 4945078 : nexus()->ConfigurePremonomorphic();
526 105520 : } else if (new_state == MEGAMORPHIC) {
527 : DCHECK_IMPLIES(!is_keyed(), key->IsName());
528 211040 : nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
529 : } else {
530 0 : UNREACHABLE();
531 : }
532 :
533 5050599 : vector_set_ = true;
534 10101197 : OnFeedbackChanged(isolate(), GetHostFunction());
535 5050598 : }
536 :
537 4736345 : void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
538 14209034 : Handle<Object> handler) {
539 4736345 : if (IsLoadGlobalIC()) {
540 : LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
541 59462 : nexus->ConfigureHandlerMode(handler);
542 : } else {
543 : // Non-keyed ICs don't track the name explicitly.
544 4676883 : if (!is_keyed()) name = Handle<Name>::null();
545 4676883 : nexus()->ConfigureMonomorphic(name, map, handler);
546 : }
547 :
548 4736347 : vector_set_ = true;
549 9472691 : OnFeedbackChanged(isolate(), GetHostFunction());
550 4736344 : }
551 :
552 553319 : void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
553 1106638 : List<Handle<Object>>* handlers) {
554 : DCHECK(!IsLoadGlobalIC());
555 : // Non-keyed ICs don't track the name explicitly.
556 553319 : if (!is_keyed()) name = Handle<Name>::null();
557 553319 : nexus()->ConfigurePolymorphic(name, maps, handlers);
558 :
559 553319 : vector_set_ = true;
560 1106638 : OnFeedbackChanged(isolate(), GetHostFunction());
561 553319 : }
562 :
563 6678125 : MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
564 : // If the object is undefined or null it's illegal to try to get any
565 : // of its properties; throw a TypeError in that case.
566 24259698 : if (object->IsNullOrUndefined(isolate())) {
567 6788 : if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
568 : // Ensure the IC state progresses.
569 245 : TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
570 245 : update_receiver_map(object);
571 490 : PatchCache(name, slow_stub());
572 245 : TRACE_IC("LoadIC", name);
573 : }
574 3394 : return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
575 : }
576 :
577 6674734 : bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
578 :
579 6674733 : if (state() != UNINITIALIZED) {
580 3930995 : JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
581 3930995 : update_receiver_map(object);
582 : }
583 : // Named lookup in the object.
584 6674733 : LookupIterator it(object, name);
585 6674735 : LookupForRead(&it);
586 :
587 7108444 : if (it.IsFound() || !ShouldThrowReferenceError()) {
588 : // Update inline cache and stub cache.
589 6535113 : if (use_ic) UpdateCaches(&it);
590 :
591 : // Get the property.
592 : Handle<Object> result;
593 :
594 13070228 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
595 : Object);
596 6532867 : if (it.IsFound()) {
597 : return result;
598 294358 : } else if (!ShouldThrowReferenceError()) {
599 294323 : LOG(isolate(), SuspectReadEvent(*name, *object));
600 : return result;
601 : }
602 : }
603 139657 : return ReferenceError(name);
604 : }
605 :
606 2094578 : MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
607 2262182 : Handle<JSGlobalObject> global = isolate()->global_object();
608 :
609 2094580 : if (name->IsString()) {
610 : // Look up in script context table.
611 2094579 : Handle<String> str_name = Handle<String>::cast(name);
612 : Handle<ScriptContextTable> script_contexts(
613 : global->native_context()->script_context_table());
614 :
615 : ScriptContextTable::LookupResult lookup_result;
616 2094580 : if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
617 : Handle<Object> result =
618 : FixedArray::get(*ScriptContextTable::GetContext(
619 112148 : script_contexts, lookup_result.context_index),
620 112148 : lookup_result.slot_index, isolate());
621 56074 : if (result->IsTheHole(isolate())) {
622 : // Do not install stubs and stay pre-monomorphic for
623 : // uninitialized accesses.
624 618 : return ReferenceError(name);
625 : }
626 :
627 110912 : if (FLAG_use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
628 55456 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub);
629 : LoadScriptContextFieldStub stub(isolate(), &lookup_result);
630 110912 : PatchCache(name, stub.GetCode());
631 55456 : TRACE_IC("LoadGlobalIC", name);
632 : }
633 : return result;
634 : }
635 : }
636 2038507 : return LoadIC::Load(global, name);
637 : }
638 :
639 176232 : static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
640 : Handle<Map> new_receiver_map) {
641 : DCHECK(!new_receiver_map.is_null());
642 243860 : for (int current = 0; current < receiver_maps->length(); ++current) {
643 166546 : if (!receiver_maps->at(current).is_null() &&
644 : receiver_maps->at(current).is_identical_to(new_receiver_map)) {
645 : return false;
646 : }
647 : }
648 38657 : receiver_maps->Add(new_receiver_map);
649 38657 : return true;
650 : }
651 :
652 5746877 : bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
653 : DCHECK(IsHandler(*handler));
654 2198616 : if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
655 2198377 : Handle<Map> map = receiver_map();
656 : MapHandleList maps;
657 : List<Handle<Object>> handlers;
658 :
659 2198377 : TargetMaps(&maps);
660 2198377 : int number_of_maps = maps.length();
661 : int deprecated_maps = 0;
662 : int handler_to_overwrite = -1;
663 :
664 3501657 : for (int i = 0; i < number_of_maps; i++) {
665 1303280 : Handle<Map> current_map = maps.at(i);
666 1303280 : if (current_map->is_deprecated()) {
667 : // Filter out deprecated maps to ensure their instances get migrated.
668 294280 : ++deprecated_maps;
669 1009000 : } else if (map.is_identical_to(current_map)) {
670 : // If the receiver type is already in the polymorphic IC, this indicates
671 : // there was a prototoype chain failure. In that case, just overwrite the
672 : // handler.
673 : handler_to_overwrite = i;
674 1773078 : } else if (handler_to_overwrite == -1 &&
675 873004 : IsTransitionOfMonomorphicTarget(*current_map, *map)) {
676 : handler_to_overwrite = i;
677 : }
678 : }
679 :
680 : int number_of_valid_maps =
681 2198377 : number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
682 :
683 2198377 : if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
684 3548261 : if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
685 : return false;
686 : }
687 2167575 : if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
688 :
689 2167575 : number_of_valid_maps++;
690 2686796 : if (number_of_valid_maps > 1 && is_keyed()) return false;
691 2167559 : if (number_of_valid_maps == 1) {
692 1648354 : ConfigureVectorState(name, receiver_map(), handler);
693 : } else {
694 519205 : if (handler_to_overwrite >= 0) {
695 30133 : handlers.Set(handler_to_overwrite, handler);
696 30133 : if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
697 : maps.Set(handler_to_overwrite, map);
698 : }
699 : } else {
700 489072 : maps.Add(map);
701 489072 : handlers.Add(handler);
702 : }
703 :
704 519205 : ConfigureVectorState(name, &maps, &handlers);
705 : }
706 :
707 : return true;
708 : }
709 :
710 0 : void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
711 : DCHECK(IsHandler(*handler));
712 2473780 : ConfigureVectorState(name, receiver_map(), handler);
713 0 : }
714 :
715 :
716 61636 : void IC::CopyICToMegamorphicCache(Handle<Name> name) {
717 : MapHandleList maps;
718 : List<Handle<Object>> handlers;
719 30818 : TargetMaps(&maps);
720 61636 : if (!nexus()->FindHandlers(&handlers, maps.length())) return;
721 123542 : for (int i = 0; i < maps.length(); i++) {
722 123542 : UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
723 : }
724 : }
725 :
726 :
727 892025 : bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
728 892025 : if (source_map == NULL) return true;
729 892025 : if (target_map == NULL) return false;
730 : ElementsKind target_elements_kind = target_map->elements_kind();
731 : bool more_general_transition = IsMoreGeneralElementsKindTransition(
732 892025 : source_map->elements_kind(), target_elements_kind);
733 : Map* transitioned_map = nullptr;
734 892025 : if (more_general_transition) {
735 : MapHandleList map_list;
736 25003 : map_list.Add(handle(target_map));
737 25003 : transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list);
738 : }
739 892025 : return transitioned_map == target_map;
740 : }
741 :
742 7847624 : void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
743 : DCHECK(IsHandler(*handler));
744 : // Currently only load and store ICs support non-code handlers.
745 : DCHECK(IsAnyLoad() || IsAnyStore());
746 5921509 : switch (state()) {
747 : case UNINITIALIZED:
748 : case PREMONOMORPHIC:
749 : UpdateMonomorphicIC(handler, name);
750 : break;
751 : case RECOMPUTE_HANDLER:
752 : case MONOMORPHIC:
753 1926115 : if (IsLoadGlobalIC()) {
754 : UpdateMonomorphicIC(handler, name);
755 : break;
756 : }
757 : // Fall through.
758 : case POLYMORPHIC:
759 2232088 : if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
760 2198377 : if (UpdatePolymorphicIC(name, handler)) break;
761 : // For keyed stubs, we can't know whether old handlers were for the
762 : // same key.
763 30818 : CopyICToMegamorphicCache(name);
764 : }
765 64529 : ConfigureVectorState(MEGAMORPHIC, name);
766 : // Fall through.
767 : case MEGAMORPHIC:
768 1280173 : UpdateMegamorphicCache(*receiver_map(), *name, *handler);
769 : // Indicate that we've handled this case.
770 1280173 : vector_set_ = true;
771 1280173 : break;
772 : case GENERIC:
773 0 : UNREACHABLE();
774 : break;
775 : }
776 5921509 : }
777 :
778 2055965 : Handle<Smi> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
779 2055965 : TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH);
780 2055965 : return LoadHandler::LoadField(isolate, index);
781 : }
782 :
783 : namespace {
784 :
785 : template <bool fill_array = true>
786 2824724 : int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
787 : Handle<JSObject> holder, Handle<Name> name,
788 : Handle<FixedArray> array, int first_index) {
789 5150520 : if (!holder.is_null() && holder->map() == *receiver_map) return 0;
790 :
791 : HandleScope scope(isolate);
792 : int checks_count = 0;
793 :
794 5545572 : if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
795 : // The validity cell check for primitive and global proxy receivers does
796 : // not guarantee that certain native context ever had access to other
797 : // native context. However, a handler created for one native context could
798 : // be used in other native context through the megamorphic stub cache.
799 : // So we record the original native context to which this handler
800 : // corresponds.
801 : if (fill_array) {
802 55822 : Handle<Context> native_context = isolate->native_context();
803 55822 : array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
804 : native_context->self_weak_cell());
805 : }
806 : checks_count++;
807 :
808 2712417 : } else if (receiver_map->IsJSGlobalObjectMap()) {
809 : // If we are creating a handler for [Load/Store]GlobalIC then we need to
810 : // check that the property did not appear in the global object.
811 : if (fill_array) {
812 2192 : Handle<JSGlobalObject> global = isolate->global_object();
813 : Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
814 2192 : global, name, PropertyCellType::kInvalidated);
815 : DCHECK(cell->value()->IsTheHole(isolate));
816 2192 : Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
817 2192 : array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell);
818 : }
819 : checks_count++;
820 : }
821 :
822 : // Create/count entries for each global or dictionary prototype appeared in
823 : // the prototype chain contains from receiver till holder.
824 2824061 : PrototypeIterator::WhereToEnd end = name->IsPrivate()
825 : ? PrototypeIterator::END_AT_NON_HIDDEN
826 2824061 : : PrototypeIterator::END_AT_NULL;
827 9285664 : for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
828 3637541 : iter.Advance()) {
829 : Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
830 5962662 : if (holder.is_identical_to(current)) break;
831 : Handle<Map> current_map(current->map(), isolate);
832 :
833 3637541 : if (current_map->IsJSGlobalObjectMap()) {
834 : if (fill_array) {
835 1257 : Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current);
836 : Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
837 1257 : global, name, PropertyCellType::kInvalidated);
838 : DCHECK(cell->value()->IsTheHole(isolate));
839 1257 : Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
840 2514 : array->set(first_index + checks_count, *weak_cell);
841 : }
842 2514 : checks_count++;
843 :
844 3635027 : } else if (current_map->is_dictionary_map()) {
845 : DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
846 : if (fill_array) {
847 : DCHECK_EQ(NameDictionary::kNotFound,
848 : current->property_dictionary()->FindEntry(name));
849 : Handle<WeakCell> weak_cell =
850 270 : Map::GetOrCreatePrototypeWeakCell(current, isolate);
851 540 : array->set(first_index + checks_count, *weak_cell);
852 : }
853 540 : checks_count++;
854 : }
855 : }
856 : return checks_count;
857 : }
858 :
859 : // Returns 0 if the validity cell check is enough to ensure that the
860 : // prototype chain from |receiver_map| till |holder| did not change.
861 : // If the |holder| is an empty handle then the full prototype chain is
862 : // checked.
863 : // Returns -1 if the handler has to be compiled or the number of prototype
864 : // checks otherwise.
865 : int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
866 : Handle<JSObject> holder, Handle<Name> name) {
867 : return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
868 2765994 : Handle<FixedArray>(), 0);
869 : }
870 :
871 1208737 : Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
872 : Handle<Name> name, Handle<Smi> smi_handler) {
873 3626211 : if (holder->IsJSGlobalObject() &&
874 1246533 : *smi_handler != *LoadHandler::LoadInterceptor(isolate)) {
875 : Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
876 : GlobalDictionary* dict = global->global_dictionary();
877 18898 : int number = dict->FindEntry(name);
878 : DCHECK_NE(NameDictionary::kNotFound, number);
879 : Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(number)),
880 18898 : isolate);
881 18898 : return isolate->factory()->NewWeakCell(cell);
882 : }
883 1189839 : return Map::GetOrCreatePrototypeWeakCell(holder, isolate);
884 : }
885 :
886 : } // namespace
887 :
888 1208737 : Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
889 : Handle<JSObject> holder,
890 : Handle<Name> name,
891 : Handle<Smi> smi_handler) {
892 : int checks_count =
893 4935458 : GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
894 : DCHECK_LE(0, checks_count);
895 :
896 2372784 : if (receiver_map->IsPrimitiveMap() ||
897 : receiver_map->is_access_check_needed()) {
898 : DCHECK(!receiver_map->is_dictionary_map());
899 : DCHECK_LE(1, checks_count); // For native context.
900 : smi_handler =
901 49127 : LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
902 1162485 : } else if (receiver_map->is_dictionary_map() &&
903 : !receiver_map->IsJSGlobalObjectMap()) {
904 1259 : smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
905 : }
906 :
907 : Handle<Cell> validity_cell =
908 1208737 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
909 : DCHECK(!validity_cell.is_null());
910 :
911 : Handle<WeakCell> holder_cell =
912 1208737 : HolderCell(isolate(), holder, name, smi_handler);
913 :
914 1208737 : if (checks_count == 0) {
915 : return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
916 1158613 : validity_cell);
917 : }
918 : Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray(
919 100248 : LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
920 : handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
921 50124 : handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
922 50124 : handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
923 : InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
924 50124 : LoadHandler::kFirstPrototypeIndex);
925 50124 : return handler_array;
926 : }
927 :
928 277625 : Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
929 : Handle<Object> holder, Handle<Name> name,
930 : Handle<Smi> smi_handler) {
931 : Handle<JSObject> end; // null handle
932 714495 : int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
933 : DCHECK_LE(0, checks_count);
934 :
935 548665 : if (receiver_map->IsPrimitiveMap() ||
936 : receiver_map->is_access_check_needed()) {
937 : DCHECK(!receiver_map->is_dictionary_map());
938 : DCHECK_LE(1, checks_count); // For native context.
939 : smi_handler =
940 6695 : LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
941 273040 : } else if (receiver_map->is_dictionary_map() &&
942 : !receiver_map->IsJSGlobalObjectMap()) {
943 871 : smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
944 : }
945 :
946 : Handle<Object> validity_cell =
947 277625 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
948 277625 : if (validity_cell.is_null()) {
949 : DCHECK_EQ(0, checks_count);
950 : // Lookup on receiver isn't supported in case of a simple smi handler.
951 267954 : if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) {
952 133950 : return smi_handler;
953 : }
954 : validity_cell = handle(Smi::kZero, isolate());
955 : }
956 :
957 : Factory* factory = isolate()->factory();
958 143675 : if (checks_count == 0) {
959 135698 : return factory->NewTuple3(holder, smi_handler, validity_cell);
960 : }
961 : Handle<FixedArray> handler_array(factory->NewFixedArray(
962 7977 : LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
963 : handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
964 7977 : handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
965 7977 : handler_array->set(LoadHandler::kHolderCellIndex, *holder);
966 : InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array,
967 7977 : LoadHandler::kFirstPrototypeIndex);
968 7977 : return handler_array;
969 : }
970 :
971 14250095 : void LoadIC::UpdateCaches(LookupIterator* lookup) {
972 17122355 : if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
973 : // This is the first time we execute this inline cache. Set the target to
974 : // the pre monomorphic stub to delay setting the monomorphic state.
975 703676 : TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
976 703676 : ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
977 703676 : TRACE_IC("LoadIC", lookup->name());
978 3302051 : return;
979 : }
980 :
981 : Handle<Object> code;
982 5824490 : if (lookup->state() == LookupIterator::JSPROXY ||
983 : lookup->state() == LookupIterator::ACCESS_CHECK) {
984 4452 : code = slow_stub();
985 5820038 : } else if (!lookup->IsFound()) {
986 277560 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
987 277560 : Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
988 : code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(),
989 277560 : lookup->name(), smi_handler);
990 : } else {
991 5542478 : if (IsLoadGlobalIC()) {
992 1897439 : if (lookup->TryLookupCachedProperty()) {
993 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
994 : }
995 3792894 : if (lookup->state() == LookupIterator::DATA &&
996 : lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
997 : DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
998 : // Now update the cell in the feedback vector.
999 : LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
1000 1894699 : nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1001 1894701 : TRACE_IC("LoadGlobalIC", lookup->name());
1002 1894701 : return;
1003 : }
1004 : }
1005 3647779 : code = ComputeHandler(lookup);
1006 : }
1007 :
1008 3929789 : PatchCache(lookup->name(), code);
1009 3929791 : TRACE_IC("LoadIC", lookup->name());
1010 : }
1011 :
1012 1403844 : StubCache* IC::stub_cache() {
1013 1403844 : if (IsAnyLoad()) {
1014 656535 : return isolate()->load_stub_cache();
1015 : } else {
1016 : DCHECK(IsAnyStore());
1017 747309 : return isolate()->store_stub_cache();
1018 : }
1019 : }
1020 :
1021 1403715 : void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
1022 1403715 : stub_cache()->Set(name, map, handler);
1023 1403715 : }
1024 :
1025 2794 : void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
1026 : DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
1027 5588 : if (V8_LIKELY(!FLAG_runtime_stats)) return;
1028 0 : if (IsAnyLoad()) {
1029 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
1030 : } else {
1031 : DCHECK(IsAnyStore());
1032 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
1033 : }
1034 : }
1035 :
1036 5401356 : Handle<Object> IC::ComputeHandler(LookupIterator* lookup) {
1037 : // Try to find a globally shared handler stub.
1038 5399201 : Handle<Object> shared_handler = GetMapIndependentHandler(lookup);
1039 5399199 : if (!shared_handler.is_null()) {
1040 : DCHECK(IC::IsHandler(*shared_handler));
1041 5357707 : return shared_handler;
1042 : }
1043 :
1044 : Handle<Code> handler = PropertyHandlerCompiler::Find(
1045 41492 : lookup->name(), receiver_map(), handler_kind());
1046 : // Use the cached value if it exists, and if it is different from the
1047 : // handler that just missed.
1048 41492 : if (!handler.is_null()) {
1049 : Handle<Object> current_handler;
1050 3748 : if (maybe_handler_.ToHandle(¤t_handler)) {
1051 1593 : if (!current_handler.is_identical_to(handler)) {
1052 725 : TraceHandlerCacheHitStats(lookup);
1053 725 : return handler;
1054 : }
1055 : } else {
1056 : // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
1057 : // In MEGAMORPHIC case, check if the handler in the megamorphic stub
1058 : // cache (which just missed) is different from the cached handler.
1059 2284 : if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
1060 : Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
1061 : Object* megamorphic_cached_handler =
1062 129 : stub_cache()->Get(*lookup->name(), map);
1063 129 : if (megamorphic_cached_handler != *handler) {
1064 43 : TraceHandlerCacheHitStats(lookup);
1065 43 : return handler;
1066 : }
1067 : } else {
1068 2026 : TraceHandlerCacheHitStats(lookup);
1069 2026 : return handler;
1070 : }
1071 : }
1072 : }
1073 :
1074 38698 : handler = CompileHandler(lookup);
1075 38698 : Map::UpdateCodeCache(receiver_map(), lookup->name(), handler);
1076 38698 : return handler;
1077 : }
1078 :
1079 7224039 : Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
1080 : Handle<Object> receiver = lookup->GetReceiver();
1081 3704524 : if (receiver->IsString() &&
1082 3987477 : *lookup->name() == isolate()->heap()->length_string()) {
1083 17480 : FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1084 17480 : return SimpleFieldLoad(isolate(), index);
1085 : }
1086 :
1087 3633651 : if (receiver->IsStringWrapper() &&
1088 3326 : *lookup->name() == isolate()->heap()->length_string()) {
1089 248 : TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
1090 : StringLengthStub string_length_stub(isolate());
1091 248 : return string_length_stub.GetCode();
1092 : }
1093 :
1094 : // Use specialized code for getting prototype of functions.
1095 3768075 : if (receiver->IsJSFunction() &&
1096 193937 : *lookup->name() == isolate()->heap()->prototype_string() &&
1097 3685944 : receiver->IsConstructor() &&
1098 : !Handle<JSFunction>::cast(receiver)
1099 : ->map()
1100 : ->has_non_instance_prototype()) {
1101 : Handle<Code> stub;
1102 53843 : TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
1103 53843 : return isolate()->builtins()->LoadIC_FunctionPrototype();
1104 : }
1105 :
1106 3576234 : Handle<Map> map = receiver_map();
1107 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1108 : bool receiver_is_holder = receiver.is_identical_to(holder);
1109 3576234 : switch (lookup->state()) {
1110 : case LookupIterator::INTERCEPTOR: {
1111 1164 : Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
1112 :
1113 2328 : if (holder->GetNamedInterceptor()->non_masking()) {
1114 : Handle<Object> holder_ref = isolate()->factory()->null_value();
1115 102 : if (!receiver_is_holder || IsLoadGlobalIC()) {
1116 28 : holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate());
1117 : }
1118 65 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
1119 65 : return LoadFullChain(map, holder_ref, lookup->name(), smi_handler);
1120 : }
1121 :
1122 1099 : if (receiver_is_holder) {
1123 : DCHECK(map->has_named_interceptor());
1124 901 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
1125 901 : return smi_handler;
1126 : }
1127 :
1128 198 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
1129 198 : return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1130 : }
1131 :
1132 : case LookupIterator::ACCESSOR: {
1133 : // Use simple field loads for some well-known callback properties.
1134 : // The method will only return true for absolute truths based on the
1135 : // receiver maps.
1136 : int object_offset;
1137 312423 : if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
1138 : &object_offset)) {
1139 373084 : FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
1140 186542 : return SimpleFieldLoad(isolate(), index);
1141 : }
1142 :
1143 125881 : Handle<Object> accessors = lookup->GetAccessors();
1144 125881 : if (accessors->IsAccessorPair()) {
1145 107224 : if (lookup->TryLookupCachedProperty()) {
1146 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
1147 106584 : return ComputeHandler(lookup);
1148 : }
1149 :
1150 : // When debugging we need to go the slow path to flood the accessor.
1151 214396 : if (GetHostFunction()->shared()->HasDebugInfo()) {
1152 20 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1153 20 : return slow_stub();
1154 : }
1155 :
1156 : Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
1157 : isolate());
1158 107999 : if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
1159 736 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1160 736 : return slow_stub();
1161 : }
1162 :
1163 106442 : CallOptimization call_optimization(getter);
1164 106442 : if (call_optimization.is_simple_api_call()) {
1165 1380 : if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
1166 685 : !holder->HasFastProperties()) {
1167 29 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1168 29 : return slow_stub();
1169 : }
1170 666 : break;
1171 : }
1172 :
1173 : // FunctionTemplate isn't yet supported as smi-handler.
1174 105747 : if (getter->IsFunctionTemplateInfo()) {
1175 0 : if (!holder->HasFastProperties()) {
1176 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1177 0 : return slow_stub();
1178 : }
1179 : break;
1180 : }
1181 :
1182 : Handle<Smi> smi_handler;
1183 105747 : if (holder->HasFastProperties()) {
1184 : smi_handler =
1185 192270 : LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
1186 :
1187 96135 : if (receiver_is_holder) {
1188 22682 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
1189 22682 : return smi_handler;
1190 : }
1191 73453 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
1192 9612 : } else if (holder->IsJSGlobalObject()) {
1193 956 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
1194 956 : smi_handler = LoadHandler::LoadGlobal(isolate());
1195 : } else {
1196 8656 : smi_handler = LoadHandler::LoadNormal(isolate());
1197 :
1198 8656 : if (receiver_is_holder) {
1199 8542 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1200 8542 : return smi_handler;
1201 : }
1202 114 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1203 : }
1204 :
1205 74523 : return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1206 : }
1207 :
1208 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1209 :
1210 37300 : if (v8::ToCData<Address>(info->getter()) == nullptr ||
1211 37272 : !AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map) ||
1212 55190 : !holder->HasFastProperties() ||
1213 636 : (info->is_sloppy() && !receiver->IsJSReceiver())) {
1214 759 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1215 759 : return slow_stub();
1216 : }
1217 :
1218 : Handle<Smi> smi_handler =
1219 35796 : LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
1220 17898 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
1221 17898 : if (receiver_is_holder) return smi_handler;
1222 610 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
1223 610 : return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1224 : }
1225 :
1226 : case LookupIterator::DATA: {
1227 : DCHECK_EQ(kData, lookup->property_details().kind());
1228 : Handle<Smi> smi_handler;
1229 3262590 : if (lookup->is_dictionary_holder()) {
1230 30565 : smi_handler = LoadHandler::LoadNormal(isolate());
1231 30565 : if (receiver_is_holder) {
1232 : DCHECK(!holder->IsJSGlobalObject());
1233 10814 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1234 10814 : return smi_handler;
1235 : }
1236 :
1237 19751 : if (holder->IsJSGlobalObject()) {
1238 17942 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
1239 17942 : smi_handler = LoadHandler::LoadGlobal(isolate());
1240 : } else {
1241 1809 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1242 : }
1243 :
1244 3232025 : } else if (lookup->property_details().location() == kField) {
1245 1851943 : FieldIndex field = lookup->GetFieldIndex();
1246 1851944 : smi_handler = SimpleFieldLoad(isolate(), field);
1247 1851943 : if (receiver_is_holder) return smi_handler;
1248 35292 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
1249 : } else {
1250 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
1251 : smi_handler =
1252 2760164 : LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
1253 1380082 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
1254 1380082 : if (receiver_is_holder) return smi_handler;
1255 1078363 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
1256 : }
1257 1133406 : return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
1258 : }
1259 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1260 56 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
1261 56 : return LoadHandler::LoadNonExistent(isolate());
1262 : case LookupIterator::ACCESS_CHECK:
1263 : case LookupIterator::JSPROXY:
1264 : case LookupIterator::NOT_FOUND:
1265 : case LookupIterator::TRANSITION:
1266 0 : UNREACHABLE();
1267 : }
1268 :
1269 666 : return Handle<Code>::null();
1270 : }
1271 :
1272 277 : Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup) {
1273 : DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
1274 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1275 554 : Handle<Map> map = receiver_map();
1276 :
1277 277 : Handle<Object> accessors = lookup->GetAccessors();
1278 : DCHECK(accessors->IsAccessorPair());
1279 : DCHECK(holder->HasFastProperties());
1280 : DCHECK(!GetHostFunction()->shared()->HasDebugInfo());
1281 : Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
1282 : isolate());
1283 277 : CallOptimization call_optimization(getter);
1284 : NamedLoadHandlerCompiler compiler(isolate(), map, holder);
1285 : DCHECK(call_optimization.is_simple_api_call());
1286 277 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
1287 277 : int index = lookup->GetAccessorIndex();
1288 : Handle<Code> code = compiler.CompileLoadCallback(
1289 277 : lookup->name(), call_optimization, index, slow_stub());
1290 554 : return code;
1291 : }
1292 :
1293 :
1294 1406574 : static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1295 : // This helper implements a few common fast cases for converting
1296 : // non-smi keys of keyed loads/stores to a smi or a string.
1297 1406574 : if (key->IsHeapNumber()) {
1298 : double value = Handle<HeapNumber>::cast(key)->value();
1299 3045 : if (std::isnan(value)) {
1300 : key = isolate->factory()->nan_string();
1301 : } else {
1302 : int int_value = FastD2I(value);
1303 2731 : if (value == int_value && Smi::IsValid(int_value)) {
1304 : key = handle(Smi::FromInt(int_value), isolate);
1305 : }
1306 : }
1307 1403529 : } else if (key->IsUndefined(isolate)) {
1308 : key = isolate->factory()->undefined_string();
1309 1395707 : } else if (key->IsString()) {
1310 467576 : key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
1311 : }
1312 1406574 : return key;
1313 : }
1314 :
1315 413610 : void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
1316 446639 : Handle<Map> receiver_map(receiver->map(), isolate());
1317 : DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
1318 : receiver_map->instance_type() != JS_PROXY_TYPE); // Checked by caller.
1319 : MapHandleList target_receiver_maps;
1320 413610 : TargetMaps(&target_receiver_maps);
1321 :
1322 413610 : if (target_receiver_maps.length() == 0) {
1323 380551 : Handle<Object> handler = LoadElementHandler(receiver_map);
1324 380551 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1325 : }
1326 :
1327 52925 : for (int i = 0; i < target_receiver_maps.length(); i++) {
1328 52955 : Handle<Map> map = target_receiver_maps.at(i);
1329 52955 : if (map.is_null()) continue;
1330 52955 : if (map->instance_type() == JS_VALUE_TYPE) {
1331 : TRACE_GENERIC_IC("JSValue");
1332 : return;
1333 : }
1334 52940 : if (map->instance_type() == JS_PROXY_TYPE) {
1335 : TRACE_GENERIC_IC("JSProxy");
1336 : return;
1337 : }
1338 : }
1339 :
1340 : // The first time a receiver is seen that is a transitioned version of the
1341 : // previous monomorphic receiver type, assume the new ElementsKind is the
1342 : // monomorphic type. This benefits global arrays that only transition
1343 : // once, and all call sites accessing them are faster if they remain
1344 : // monomorphic. If this optimistic assumption is not true, the IC will
1345 : // miss again and it will become polymorphic and support both the
1346 : // untransitioned and transitioned maps.
1347 77433 : if (state() == MONOMORPHIC && !receiver->IsString() &&
1348 : IsMoreGeneralElementsKindTransition(
1349 : target_receiver_maps.at(0)->elements_kind(),
1350 22026 : Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1351 4470 : Handle<Object> handler = LoadElementHandler(receiver_map);
1352 4470 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1353 : }
1354 :
1355 : DCHECK(state() != GENERIC);
1356 :
1357 : // Determine the list of receiver maps that this call site has seen,
1358 : // adding the map that was just encountered.
1359 28559 : if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1360 : // If the miss wasn't due to an unseen map, a polymorphic stub
1361 : // won't help, use the generic stub.
1362 : TRACE_GENERIC_IC("same map added twice");
1363 : return;
1364 : }
1365 :
1366 : // If the maximum number of receiver maps has been exceeded, use the generic
1367 : // version of the IC.
1368 21831 : if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
1369 : TRACE_GENERIC_IC("max polymorph exceeded");
1370 : return;
1371 : }
1372 :
1373 : List<Handle<Object>> handlers(target_receiver_maps.length());
1374 18932 : LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers);
1375 18932 : ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
1376 : }
1377 :
1378 433064 : Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map) {
1379 433189 : if (receiver_map->has_indexed_interceptor() &&
1380 : !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
1381 998363 : isolate()) &&
1382 : !receiver_map->GetIndexedInterceptor()->non_masking()) {
1383 97 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1384 97 : return LoadIndexedInterceptorStub(isolate()).GetCode();
1385 : }
1386 432967 : if (receiver_map->IsStringMap()) {
1387 1709 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringStub);
1388 1709 : return isolate()->builtins()->KeyedLoadIC_IndexedString();
1389 : }
1390 : InstanceType instance_type = receiver_map->instance_type();
1391 431258 : if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1392 45 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1393 45 : return isolate()->builtins()->KeyedLoadIC_Slow();
1394 : }
1395 :
1396 : ElementsKind elements_kind = receiver_map->elements_kind();
1397 431213 : if (IsSloppyArgumentsElementsKind(elements_kind)) {
1398 3189 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1399 3189 : return KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
1400 : }
1401 428024 : bool is_js_array = instance_type == JS_ARRAY_TYPE;
1402 428024 : if (elements_kind == DICTIONARY_ELEMENTS) {
1403 10529 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1404 : return LoadHandler::LoadElement(isolate(), elements_kind, false,
1405 21058 : is_js_array);
1406 : }
1407 : DCHECK(IsFastElementsKind(elements_kind) ||
1408 : IsFixedTypedArrayElementsKind(elements_kind));
1409 : // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind).
1410 : bool convert_hole_to_undefined =
1411 549633 : is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
1412 132138 : *receiver_map == isolate()->get_initial_js_array_map(elements_kind);
1413 417495 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1414 : return LoadHandler::LoadElement(isolate(), elements_kind,
1415 834990 : convert_hole_to_undefined, is_js_array);
1416 : }
1417 :
1418 18932 : void KeyedLoadIC::LoadElementPolymorphicHandlers(
1419 66975 : MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
1420 133950 : for (int i = 0; i < receiver_maps->length(); ++i) {
1421 48043 : Handle<Map> receiver_map(receiver_maps->at(i));
1422 :
1423 : // Mark all stable receiver maps that have elements kind transition map
1424 : // among receiver_maps as unstable because the optimizing compilers may
1425 : // generate an elements kind transition for this kind of receivers.
1426 48043 : if (receiver_map->is_stable()) {
1427 30630 : Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
1428 30630 : if (tmap != nullptr) {
1429 30 : receiver_map->NotifyLeafMapLayoutChange();
1430 : }
1431 : }
1432 48043 : handlers->Add(LoadElementHandler(receiver_map));
1433 : }
1434 18932 : }
1435 :
1436 704068 : MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1437 : Handle<Object> key) {
1438 704068 : if (MigrateDeprecated(object)) {
1439 : Handle<Object> result;
1440 2245468 : ASSIGN_RETURN_ON_EXCEPTION(
1441 : isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1442 : Object);
1443 : return result;
1444 : }
1445 :
1446 : Handle<Object> load_handle;
1447 :
1448 : // Check for non-string values that can be converted into an
1449 : // internalized string directly or is representable as a smi.
1450 704036 : key = TryConvertKey(key, isolate());
1451 :
1452 : uint32_t index;
1453 941786 : if ((key->IsInternalizedString() &&
1454 1415318 : !String::cast(*key)->AsArrayIndex(&index)) ||
1455 : key->IsSymbol()) {
1456 560010 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1457 : LoadIC::Load(object, Handle<Name>::cast(key)),
1458 : Object);
1459 1271953 : } else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1460 : !object->IsJSValue()) {
1461 1276804 : if ((object->IsJSObject() && key->IsSmi()) ||
1462 1918 : (object->IsString() && key->IsNumber())) {
1463 413610 : UpdateLoadElement(Handle<HeapObject>::cast(object));
1464 413610 : if (is_vector_set()) {
1465 403953 : TRACE_IC("LoadIC", key);
1466 : }
1467 : }
1468 : }
1469 :
1470 703727 : if (!is_vector_set()) {
1471 20078 : ConfigureVectorState(MEGAMORPHIC, key);
1472 20078 : TRACE_IC("LoadIC", key);
1473 : }
1474 :
1475 703727 : if (!load_handle.is_null()) return load_handle;
1476 :
1477 : Handle<Object> result;
1478 848062 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1479 : Runtime::GetObjectProperty(isolate(), object, key),
1480 : Object);
1481 : return result;
1482 : }
1483 :
1484 :
1485 3876445 : bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1486 : JSReceiver::StoreFromKeyed store_mode) {
1487 : // Disable ICs for non-JSObjects for now.
1488 : Handle<Object> object = it->GetReceiver();
1489 1935965 : if (!object->IsJSObject()) return false;
1490 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1491 : DCHECK(!receiver->map()->is_deprecated());
1492 :
1493 1943492 : for (; it->IsFound(); it->Next()) {
1494 641405 : switch (it->state()) {
1495 : case LookupIterator::NOT_FOUND:
1496 : case LookupIterator::TRANSITION:
1497 0 : UNREACHABLE();
1498 : case LookupIterator::JSPROXY:
1499 : return false;
1500 : case LookupIterator::INTERCEPTOR: {
1501 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1502 195 : InterceptorInfo* info = holder->GetNamedInterceptor();
1503 195 : if (it->HolderIsReceiverOrHiddenPrototype()) {
1504 522 : return !info->non_masking() && receiver.is_identical_to(holder) &&
1505 174 : !info->setter()->IsUndefined(it->isolate());
1506 21 : } else if (!info->getter()->IsUndefined(it->isolate()) ||
1507 : !info->query()->IsUndefined(it->isolate())) {
1508 : return false;
1509 : }
1510 : break;
1511 : }
1512 : case LookupIterator::ACCESS_CHECK:
1513 4071 : if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1514 : break;
1515 : case LookupIterator::ACCESSOR:
1516 58716 : return !it->IsReadOnly();
1517 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1518 : return false;
1519 : case LookupIterator::DATA: {
1520 578157 : if (it->IsReadOnly()) return false;
1521 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1522 555047 : if (receiver.is_identical_to(holder)) {
1523 409478 : it->PrepareForDataProperty(value);
1524 : // The previous receiver map might just have been deprecated,
1525 : // so reload it.
1526 409478 : update_receiver_map(receiver);
1527 409478 : return true;
1528 : }
1529 :
1530 : // Receiver != holder.
1531 145569 : if (receiver->IsJSGlobalProxy()) {
1532 846 : PrototypeIterator iter(it->isolate(), receiver);
1533 : return it->GetHolder<Object>().is_identical_to(
1534 : PrototypeIterator::GetCurrent(iter));
1535 : }
1536 :
1537 144723 : if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1538 :
1539 144723 : if (it->ExtendingNonExtensible(receiver)) return false;
1540 144723 : it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1541 144723 : return it->IsCacheableTransition();
1542 : }
1543 : }
1544 : }
1545 :
1546 1298034 : receiver = it->GetStoreTarget();
1547 1298034 : if (it->ExtendingNonExtensible(receiver)) return false;
1548 1297917 : it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode);
1549 1297917 : return it->IsCacheableTransition();
1550 : }
1551 :
1552 1690942 : MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
1553 : Handle<Name> name,
1554 : Handle<Object> value) {
1555 : DCHECK(object->IsJSGlobalObject());
1556 : DCHECK(name->IsString());
1557 :
1558 : // Look up in script context table.
1559 1690942 : Handle<String> str_name = Handle<String>::cast(name);
1560 : Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
1561 : Handle<ScriptContextTable> script_contexts(
1562 : global->native_context()->script_context_table());
1563 :
1564 : ScriptContextTable::LookupResult lookup_result;
1565 1690942 : if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
1566 : Handle<Context> script_context = ScriptContextTable::GetContext(
1567 82 : script_contexts, lookup_result.context_index);
1568 82 : if (lookup_result.mode == CONST) {
1569 122 : return TypeError(MessageTemplate::kConstAssign, object, name);
1570 : }
1571 :
1572 : Handle<Object> previous_value =
1573 116 : FixedArray::get(*script_context, lookup_result.slot_index, isolate());
1574 :
1575 58 : if (previous_value->IsTheHole(isolate())) {
1576 : // Do not install stubs and stay pre-monomorphic for
1577 : // uninitialized accesses.
1578 18 : return ReferenceError(name);
1579 : }
1580 :
1581 80 : if (FLAG_use_ic && StoreScriptContextFieldStub::Accepted(&lookup_result)) {
1582 40 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
1583 : StoreScriptContextFieldStub stub(isolate(), &lookup_result);
1584 80 : PatchCache(name, stub.GetCode());
1585 : }
1586 :
1587 80 : script_context->set(lookup_result.slot_index, *value);
1588 : return value;
1589 : }
1590 :
1591 1690860 : return StoreIC::Store(object, name, value);
1592 : }
1593 :
1594 6180193 : MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1595 : Handle<Object> value,
1596 : JSReceiver::StoreFromKeyed store_mode) {
1597 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
1598 : // might deprecate the current map again, if value does not fit.
1599 12359722 : if (MigrateDeprecated(object) || object->IsJSProxy()) {
1600 : Handle<Object> result;
1601 4634 : ASSIGN_RETURN_ON_EXCEPTION(
1602 : isolate(), result,
1603 : Object::SetProperty(object, name, value, language_mode()), Object);
1604 : return result;
1605 : }
1606 :
1607 : // If the object is undefined or null it's illegal to try to set any
1608 : // properties on it; throw a TypeError in that case.
1609 20469593 : if (object->IsNullOrUndefined(isolate())) {
1610 100 : if (FLAG_use_ic && state() != UNINITIALIZED && state() != PREMONOMORPHIC) {
1611 : // Ensure the IC state progresses.
1612 15 : TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1613 15 : update_receiver_map(object);
1614 15 : PatchCache(name, slow_stub());
1615 15 : TRACE_IC("StoreIC", name);
1616 : }
1617 50 : return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1618 : }
1619 :
1620 6177826 : if (state() != UNINITIALIZED) {
1621 1935965 : JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1622 : }
1623 6177826 : LookupIterator it(object, name);
1624 6177828 : if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
1625 :
1626 6177828 : MAYBE_RETURN_NULL(
1627 : Object::SetProperty(&it, value, language_mode(), store_mode));
1628 : return value;
1629 : }
1630 :
1631 6177368 : void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1632 : JSReceiver::StoreFromKeyed store_mode) {
1633 6177368 : if (state() == UNINITIALIZED) {
1634 : // This is the first time we execute this inline cache. Set the target to
1635 : // the pre monomorphic stub to delay setting the monomorphic state.
1636 4241403 : TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1637 4241403 : ConfigureVectorState(PREMONOMORPHIC, Handle<Object>());
1638 4241403 : TRACE_IC("StoreIC", lookup->name());
1639 10418771 : return;
1640 : }
1641 :
1642 : Handle<Object> handler;
1643 1935965 : if (LookupForWrite(lookup, value, store_mode)) {
1644 1751396 : handler = ComputeHandler(lookup);
1645 : } else {
1646 : TRACE_GENERIC_IC("LookupForWrite said 'false'");
1647 184569 : handler = slow_stub();
1648 : }
1649 :
1650 1935965 : PatchCache(lookup->name(), handler);
1651 1935965 : TRACE_IC("StoreIC", lookup->name());
1652 : }
1653 :
1654 1279632 : Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
1655 : Handle<JSObject> holder,
1656 : Handle<Map> transition,
1657 : Handle<Name> name) {
1658 : Handle<Object> smi_handler;
1659 1279632 : if (transition->is_dictionary_map()) {
1660 5316304 : smi_handler = StoreHandler::StoreNormal(isolate());
1661 : } else {
1662 : int descriptor = transition->LastAdded();
1663 : Handle<DescriptorArray> descriptors(transition->instance_descriptors());
1664 1261566 : PropertyDetails details = descriptors->GetDetails(descriptor);
1665 : Representation representation = details.representation();
1666 : DCHECK(!representation.IsNone());
1667 :
1668 : // Declarative handlers don't support access checks.
1669 : DCHECK(!transition->is_access_check_needed());
1670 :
1671 : DCHECK_EQ(kData, details.kind());
1672 1261566 : if (details.location() == kDescriptor) {
1673 75212 : smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
1674 :
1675 : } else {
1676 : DCHECK_EQ(kField, details.location());
1677 : bool extend_storage =
1678 1186354 : Map::cast(transition->GetBackPointer())->unused_property_fields() ==
1679 1186354 : 0;
1680 :
1681 1186354 : FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
1682 : smi_handler = StoreHandler::TransitionToField(
1683 : isolate(), descriptor, index, representation, extend_storage);
1684 : }
1685 : }
1686 : // |holder| is either a receiver if the property is non-existent or
1687 : // one of the prototypes.
1688 : DCHECK(!holder.is_null());
1689 1279632 : bool is_nonexistent = holder->map() == transition->GetBackPointer();
1690 1279632 : if (is_nonexistent) holder = Handle<JSObject>::null();
1691 :
1692 : int checks_count =
1693 : GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
1694 : DCHECK_LE(0, checks_count);
1695 : DCHECK(!receiver_map->IsJSGlobalObjectMap());
1696 :
1697 : Handle<Object> validity_cell =
1698 1279632 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1699 1279632 : if (validity_cell.is_null()) {
1700 : DCHECK_EQ(0, checks_count);
1701 : validity_cell = handle(Smi::kZero, isolate());
1702 : }
1703 :
1704 1279632 : Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
1705 :
1706 : Factory* factory = isolate()->factory();
1707 1279632 : if (checks_count == 0) {
1708 1279002 : return factory->NewTuple3(transition_cell, smi_handler, validity_cell);
1709 : }
1710 : Handle<FixedArray> handler_array(factory->NewFixedArray(
1711 630 : StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
1712 630 : handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
1713 630 : handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
1714 630 : handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
1715 : InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
1716 630 : StoreHandler::kFirstPrototypeIndex);
1717 630 : return handler_array;
1718 : }
1719 :
1720 : namespace {
1721 :
1722 : Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
1723 77644 : return isolate->factory()->NewWeakCell(cell);
1724 : }
1725 :
1726 : } // namespace
1727 :
1728 1751396 : Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
1729 : DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
1730 :
1731 : // This is currently guaranteed by checks in StoreIC::Store.
1732 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1733 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1734 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1735 :
1736 1751396 : switch (lookup->state()) {
1737 : case LookupIterator::TRANSITION: {
1738 1282736 : auto store_target = lookup->GetStoreTarget();
1739 1282736 : if (store_target->IsJSGlobalObject()) {
1740 470773 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1741 : return StoreGlobal(isolate(), lookup->transition_cell());
1742 : }
1743 : // Currently not handled by CompileStoreTransition.
1744 1280014 : if (!holder->HasFastProperties()) {
1745 : TRACE_GENERIC_IC("transition from slow");
1746 382 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1747 382 : return slow_stub();
1748 : }
1749 :
1750 : DCHECK(lookup->IsCacheableTransition());
1751 1279632 : Handle<Map> transition = lookup->transition_map();
1752 1279632 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
1753 : return StoreTransition(receiver_map(), holder, transition,
1754 1279632 : lookup->name());
1755 : }
1756 :
1757 : case LookupIterator::INTERCEPTOR: {
1758 : DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1759 153 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1760 : StoreInterceptorStub stub(isolate());
1761 153 : return stub.GetCode();
1762 : }
1763 :
1764 : case LookupIterator::ACCESSOR: {
1765 58213 : if (!holder->HasFastProperties()) {
1766 : TRACE_GENERIC_IC("accessor on slow map");
1767 410 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1768 410 : return slow_stub();
1769 : }
1770 57803 : Handle<Object> accessors = lookup->GetAccessors();
1771 57803 : if (accessors->IsAccessorInfo()) {
1772 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1773 21309 : if (v8::ToCData<Address>(info->setter()) == nullptr) {
1774 : TRACE_GENERIC_IC("setter == nullptr");
1775 7 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1776 7 : return slow_stub();
1777 : }
1778 42467 : if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1779 21165 : !lookup->HolderIsReceiverOrHiddenPrototype()) {
1780 : TRACE_GENERIC_IC("special data property in prototype chain");
1781 135 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1782 135 : return slow_stub();
1783 : }
1784 21167 : if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
1785 21167 : receiver_map())) {
1786 : TRACE_GENERIC_IC("incompatible receiver type");
1787 14 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1788 14 : return slow_stub();
1789 : }
1790 : break; // Custom-compiled handler.
1791 36494 : } else if (accessors->IsAccessorPair()) {
1792 : Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1793 : isolate());
1794 53378 : if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1795 : TRACE_GENERIC_IC("setter not a function");
1796 16818 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1797 16818 : return slow_stub();
1798 : }
1799 19676 : CallOptimization call_optimization(setter);
1800 19676 : if (call_optimization.is_simple_api_call()) {
1801 117 : if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1802 : break; // Custom-compiled handler.
1803 : }
1804 : TRACE_GENERIC_IC("incompatible receiver");
1805 3 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1806 3 : return slow_stub();
1807 : }
1808 : break; // Custom-compiled handler.
1809 : }
1810 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1811 0 : return slow_stub();
1812 : }
1813 :
1814 : case LookupIterator::DATA: {
1815 : DCHECK_EQ(kData, lookup->property_details().kind());
1816 410294 : if (lookup->is_dictionary_holder()) {
1817 80911 : if (holder->IsJSGlobalObject()) {
1818 74922 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
1819 74922 : return StoreGlobal(isolate(), lookup->GetPropertyCell());
1820 : }
1821 5989 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
1822 : DCHECK(holder.is_identical_to(receiver));
1823 5989 : return StoreHandler::StoreNormal(isolate());
1824 : }
1825 :
1826 : // -------------- Fields --------------
1827 329383 : if (lookup->property_details().location() == kField) {
1828 329326 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
1829 329326 : int descriptor = lookup->GetFieldDescriptorIndex();
1830 329326 : FieldIndex index = lookup->GetFieldIndex();
1831 : PropertyConstness constness = lookup->constness();
1832 329326 : if (constness == kConst && IsStoreOwnICKind(nexus()->kind())) {
1833 : // StoreOwnICs are used for initializing object literals therefore
1834 : // we must store the value unconditionally even to kConst fields.
1835 : constness = kMutable;
1836 : }
1837 : return StoreHandler::StoreField(isolate(), descriptor, index, constness,
1838 329326 : lookup->representation());
1839 : }
1840 :
1841 : // -------------- Constant properties --------------
1842 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
1843 : TRACE_GENERIC_IC("constant property");
1844 57 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1845 57 : return slow_stub();
1846 : }
1847 :
1848 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1849 : case LookupIterator::ACCESS_CHECK:
1850 : case LookupIterator::JSPROXY:
1851 : case LookupIterator::NOT_FOUND:
1852 0 : UNREACHABLE();
1853 : }
1854 40826 : return Handle<Code>::null();
1855 : }
1856 :
1857 38421 : Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup) {
1858 : DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
1859 :
1860 : // This is currently guaranteed by checks in StoreIC::Store.
1861 38421 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1862 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1863 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1864 :
1865 : DCHECK(holder->HasFastProperties());
1866 38421 : Handle<Object> accessors = lookup->GetAccessors();
1867 :
1868 38421 : if (accessors->IsAccessorInfo()) {
1869 20287 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1870 : DCHECK(v8::ToCData<Address>(info->setter()) != 0);
1871 : DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
1872 : lookup->HolderIsReceiverOrHiddenPrototype());
1873 : DCHECK(
1874 : AccessorInfo::IsCompatibleReceiverMap(isolate(), info, receiver_map()));
1875 56555 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
1876 : NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1877 : // TODO(ishell): don't hard-code language mode into the handler because
1878 : // this handler can be re-used through megamorphic stub cache for wrong
1879 : // language mode.
1880 : // Better pass vector/slot to Runtime::kStoreCallbackProperty and
1881 : // let it decode the language mode from the IC kind.
1882 : Handle<Code> code = compiler.CompileStoreCallback(receiver, lookup->name(),
1883 20287 : info, language_mode());
1884 20287 : return code;
1885 : }
1886 :
1887 : DCHECK(accessors->IsAccessorPair());
1888 : Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1889 : isolate());
1890 : DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
1891 18134 : CallOptimization call_optimization(setter);
1892 : NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
1893 18134 : if (call_optimization.is_simple_api_call()) {
1894 : DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
1895 70 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
1896 : Handle<Code> code = compiler.CompileStoreCallback(
1897 : receiver, lookup->name(), call_optimization, lookup->GetAccessorIndex(),
1898 70 : slow_stub());
1899 70 : return code;
1900 : }
1901 18064 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
1902 : int expected_arguments =
1903 : JSFunction::cast(*setter)->shared()->internal_formal_parameter_count();
1904 : return compiler.CompileStoreViaSetter(
1905 18064 : receiver, lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
1906 : }
1907 :
1908 247830 : void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
1909 : KeyedAccessStoreMode store_mode) {
1910 : MapHandleList target_receiver_maps;
1911 280263 : TargetMaps(&target_receiver_maps);
1912 247830 : if (target_receiver_maps.length() == 0) {
1913 : Handle<Map> monomorphic_map =
1914 215367 : ComputeTransitionedMap(receiver_map, store_mode);
1915 : store_mode = GetNonTransitioningStoreMode(store_mode);
1916 215367 : Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
1917 215367 : return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
1918 : }
1919 :
1920 41336 : for (int i = 0; i < target_receiver_maps.length(); i++) {
1921 82732 : if (!target_receiver_maps.at(i).is_null() &&
1922 : target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
1923 : TRACE_GENERIC_IC("JSValue");
1924 : return;
1925 : }
1926 : }
1927 :
1928 : // There are several special cases where an IC that is MONOMORPHIC can still
1929 : // transition to a different GetNonTransitioningStoreMode IC that handles a
1930 : // superset of the original IC. Handle those here if the receiver map hasn't
1931 : // changed or it has transitioned to a more general kind.
1932 : KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
1933 32433 : Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1934 32433 : if (state() == MONOMORPHIC) {
1935 : Handle<Map> transitioned_receiver_map = receiver_map;
1936 27526 : if (IsTransitionStoreMode(store_mode)) {
1937 : transitioned_receiver_map =
1938 15433 : ComputeTransitionedMap(receiver_map, store_mode);
1939 : }
1940 37938 : if ((receiver_map.is_identical_to(previous_receiver_map) &&
1941 46547 : IsTransitionStoreMode(store_mode)) ||
1942 : IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1943 19021 : *transitioned_receiver_map)) {
1944 : // If the "old" and "new" maps are in the same elements map family, or
1945 : // if they at least come from the same origin for a transitioning store,
1946 : // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1947 : store_mode = GetNonTransitioningStoreMode(store_mode);
1948 : Handle<Object> handler =
1949 13570 : StoreElementHandler(transitioned_receiver_map, store_mode);
1950 13570 : ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
1951 : return;
1952 : }
1953 15863 : if (receiver_map.is_identical_to(previous_receiver_map) &&
1954 15531 : old_store_mode == STANDARD_STORE &&
1955 3150 : (store_mode == STORE_AND_GROW_NO_TRANSITION ||
1956 2932 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1957 : store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1958 : // A "normal" IC that handles stores can switch to a version that can
1959 : // grow at the end of the array, handle OOB accesses or copy COW arrays
1960 : // and still stay MONOMORPHIC.
1961 253 : Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
1962 253 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1963 : }
1964 : }
1965 :
1966 : DCHECK(state() != GENERIC);
1967 :
1968 : bool map_added =
1969 18610 : AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1970 :
1971 18610 : if (IsTransitionStoreMode(store_mode)) {
1972 : Handle<Map> transitioned_receiver_map =
1973 7133 : ComputeTransitionedMap(receiver_map, store_mode);
1974 : map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1975 7133 : transitioned_receiver_map);
1976 : }
1977 :
1978 18610 : if (!map_added) {
1979 : // If the miss wasn't due to an unseen map, a polymorphic stub
1980 : // won't help, use the megamorphic stub which can handle everything.
1981 : TRACE_GENERIC_IC("same map added twice");
1982 : return;
1983 : }
1984 :
1985 : // If the maximum number of receiver maps has been exceeded, use the
1986 : // megamorphic version of the IC.
1987 16496 : if (target_receiver_maps.length() > kMaxKeyedPolymorphism) return;
1988 :
1989 : // Make sure all polymorphic handlers have the same store mode, otherwise the
1990 : // megamorphic stub must be used.
1991 : store_mode = GetNonTransitioningStoreMode(store_mode);
1992 15227 : if (old_store_mode != STANDARD_STORE) {
1993 3420 : if (store_mode == STANDARD_STORE) {
1994 : store_mode = old_store_mode;
1995 3138 : } else if (store_mode != old_store_mode) {
1996 : TRACE_GENERIC_IC("store mode mismatch");
1997 : return;
1998 : }
1999 : }
2000 :
2001 : // If the store mode isn't the standard mode, make sure that all polymorphic
2002 : // receivers are either external arrays, or all "normal" arrays. Otherwise,
2003 : // use the megamorphic stub.
2004 15227 : if (store_mode != STANDARD_STORE) {
2005 : int external_arrays = 0;
2006 7880 : for (int i = 0; i < target_receiver_maps.length(); ++i) {
2007 15760 : if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
2008 45 : external_arrays++;
2009 : }
2010 : }
2011 3752 : if (external_arrays != 0 &&
2012 : external_arrays != target_receiver_maps.length()) {
2013 : TRACE_GENERIC_IC("unsupported combination of external and normal arrays");
2014 : return;
2015 : }
2016 : }
2017 :
2018 : List<Handle<Object>> handlers(target_receiver_maps.length());
2019 15182 : StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
2020 15182 : ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
2021 : }
2022 :
2023 :
2024 237933 : Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
2025 : Handle<Map> map, KeyedAccessStoreMode store_mode) {
2026 237933 : switch (store_mode) {
2027 : case STORE_TRANSITION_TO_OBJECT:
2028 : case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
2029 : ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
2030 : ? FAST_HOLEY_ELEMENTS
2031 72528 : : FAST_ELEMENTS;
2032 72528 : return Map::TransitionElementsTo(map, kind);
2033 : }
2034 : case STORE_TRANSITION_TO_DOUBLE:
2035 : case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
2036 : ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind())
2037 : ? FAST_HOLEY_DOUBLE_ELEMENTS
2038 4948 : : FAST_DOUBLE_ELEMENTS;
2039 4948 : return Map::TransitionElementsTo(map, kind);
2040 : }
2041 : case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
2042 : DCHECK(map->has_fixed_typed_array_elements());
2043 : // Fall through
2044 : case STORE_NO_TRANSITION_HANDLE_COW:
2045 : case STANDARD_STORE:
2046 : case STORE_AND_GROW_NO_TRANSITION:
2047 160457 : return map;
2048 : }
2049 0 : UNREACHABLE();
2050 : return MaybeHandle<Map>().ToHandleChecked();
2051 : }
2052 :
2053 256173 : Handle<Object> KeyedStoreIC::StoreElementHandler(
2054 : Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
2055 : DCHECK(store_mode == STANDARD_STORE ||
2056 : store_mode == STORE_AND_GROW_NO_TRANSITION ||
2057 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
2058 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
2059 : DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
2060 :
2061 : ElementsKind elements_kind = receiver_map->elements_kind();
2062 256173 : bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
2063 : Handle<Code> stub;
2064 256173 : if (receiver_map->has_sloppy_arguments_elements()) {
2065 762154 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
2066 0 : stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
2067 292272 : } else if (receiver_map->has_fast_elements() ||
2068 : receiver_map->has_fixed_typed_array_elements()) {
2069 253466 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
2070 : stub =
2071 : StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode)
2072 506932 : .GetCode();
2073 : } else {
2074 2707 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
2075 : DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
2076 5414 : stub = StoreSlowElementStub(isolate(), store_mode).GetCode();
2077 : }
2078 : Handle<Object> validity_cell =
2079 256173 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
2080 256173 : if (validity_cell.is_null()) return stub;
2081 249808 : return isolate()->factory()->NewTuple2(validity_cell, stub);
2082 : }
2083 :
2084 15182 : void KeyedStoreIC::StoreElementPolymorphicHandlers(
2085 50448 : MapHandleList* receiver_maps, List<Handle<Object>>* handlers,
2086 : KeyedAccessStoreMode store_mode) {
2087 : DCHECK(store_mode == STANDARD_STORE ||
2088 : store_mode == STORE_AND_GROW_NO_TRANSITION ||
2089 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
2090 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
2091 :
2092 100896 : for (int i = 0; i < receiver_maps->length(); ++i) {
2093 35266 : Handle<Map> receiver_map(receiver_maps->at(i));
2094 : Handle<Object> handler;
2095 : Handle<Map> transitioned_map;
2096 :
2097 70502 : if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
2098 35236 : receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2099 : // TODO(mvstanton): Consider embedding store_mode in the state of the slow
2100 : // keyed store ic for uniformity.
2101 25407 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
2102 45 : handler = isolate()->builtins()->KeyedStoreIC_Slow();
2103 :
2104 : } else {
2105 : {
2106 : Map* tmap =
2107 35221 : receiver_map->FindElementsKindTransitionedMap(receiver_maps);
2108 35221 : if (tmap != nullptr) {
2109 8238 : if (receiver_map->is_stable()) {
2110 30 : receiver_map->NotifyLeafMapLayoutChange();
2111 : }
2112 : transitioned_map = handle(tmap);
2113 : }
2114 : }
2115 :
2116 : // TODO(mvstanton): The code below is doing pessimistic elements
2117 : // transitions. I would like to stop doing that and rely on Allocation
2118 : // Site Tracking to do a better job of ensuring the data types are what
2119 : // they need to be. Not all the elements are in place yet, pessimistic
2120 : // elements transitions are still important for performance.
2121 35221 : if (!transitioned_map.is_null()) {
2122 8238 : bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
2123 : ElementsKind elements_kind = receiver_map->elements_kind();
2124 8238 : TRACE_HANDLER_STATS(isolate(),
2125 : KeyedStoreIC_ElementsTransitionAndStoreStub);
2126 : Handle<Code> stub =
2127 : ElementsTransitionAndStoreStub(isolate(), elements_kind,
2128 : transitioned_map->elements_kind(),
2129 : is_js_array, store_mode)
2130 16476 : .GetCode();
2131 : Handle<Object> validity_cell =
2132 8238 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
2133 8238 : if (validity_cell.is_null()) {
2134 : validity_cell = handle(Smi::kZero, isolate());
2135 : }
2136 8238 : Handle<WeakCell> transition = Map::WeakCellForMap(transitioned_map);
2137 : handler =
2138 8238 : isolate()->factory()->NewTuple3(transition, stub, validity_cell);
2139 : } else {
2140 26983 : handler = StoreElementHandler(receiver_map, store_mode);
2141 : }
2142 : }
2143 : DCHECK(!handler.is_null());
2144 35266 : handlers->Add(handler);
2145 : }
2146 15182 : }
2147 :
2148 409926 : bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) {
2149 409926 : uint32_t length = 0;
2150 409926 : if (receiver->IsJSArray()) {
2151 : JSArray::cast(*receiver)->length()->ToArrayLength(&length);
2152 : } else {
2153 45657 : length = static_cast<uint32_t>(receiver->elements()->length());
2154 : }
2155 409926 : return index >= length;
2156 : }
2157 :
2158 :
2159 409926 : static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
2160 : uint32_t index, Handle<Object> value) {
2161 409926 : bool oob_access = IsOutOfBoundsAccess(receiver, index);
2162 : // Don't consider this a growing store if the store would send the receiver to
2163 : // dictionary mode.
2164 596391 : bool allow_growth = receiver->IsJSArray() && oob_access &&
2165 186465 : !receiver->WouldConvertToSlowElements(index);
2166 409926 : if (allow_growth) {
2167 : // Handle growing array in stub if necessary.
2168 185296 : if (receiver->HasFastSmiElements()) {
2169 24453 : if (value->IsHeapNumber()) {
2170 : return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
2171 : }
2172 23916 : if (value->IsHeapObject()) {
2173 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2174 : }
2175 160843 : } else if (receiver->HasFastDoubleElements()) {
2176 655 : if (!value->IsSmi() && !value->IsHeapNumber()) {
2177 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2178 : }
2179 : }
2180 : return STORE_AND_GROW_NO_TRANSITION;
2181 : } else {
2182 : // Handle only in-bounds elements accesses.
2183 224630 : if (receiver->HasFastSmiElements()) {
2184 117423 : if (value->IsHeapNumber()) {
2185 : return STORE_TRANSITION_TO_DOUBLE;
2186 113522 : } else if (value->IsHeapObject()) {
2187 : return STORE_TRANSITION_TO_OBJECT;
2188 : }
2189 107207 : } else if (receiver->HasFastDoubleElements()) {
2190 11700 : if (!value->IsSmi() && !value->IsHeapNumber()) {
2191 : return STORE_TRANSITION_TO_OBJECT;
2192 : }
2193 : }
2194 512094 : if (!FLAG_trace_external_array_abuse &&
2195 198787 : receiver->map()->has_fixed_typed_array_elements() && oob_access) {
2196 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2197 : }
2198 170046 : Heap* heap = receiver->GetHeap();
2199 170046 : if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2200 : return STORE_NO_TRANSITION_HANDLE_COW;
2201 : } else {
2202 169052 : return STANDARD_STORE;
2203 : }
2204 : }
2205 : }
2206 :
2207 :
2208 702538 : MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2209 : Handle<Object> key,
2210 : Handle<Object> value) {
2211 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
2212 : // might deprecate the current map again, if value does not fit.
2213 702538 : if (MigrateDeprecated(object)) {
2214 : Handle<Object> result;
2215 2083351 : ASSIGN_RETURN_ON_EXCEPTION(
2216 : isolate(), result, Runtime::SetObjectProperty(isolate(), object, key,
2217 : value, language_mode()),
2218 : Object);
2219 : return result;
2220 : }
2221 :
2222 : // Check for non-string values that can be converted into an
2223 : // internalized string directly or is representable as a smi.
2224 702538 : key = TryConvertKey(key, isolate());
2225 :
2226 : Handle<Object> store_handle;
2227 :
2228 : uint32_t index;
2229 940500 : if ((key->IsInternalizedString() &&
2230 1406507 : !String::cast(*key)->AsArrayIndex(&index)) ||
2231 : key->IsSymbol()) {
2232 568686 : ASSIGN_RETURN_ON_EXCEPTION(
2233 : isolate(), store_handle,
2234 : StoreIC::Store(object, Handle<Name>::cast(key), value,
2235 : JSReceiver::MAY_BE_STORE_FROM_KEYED),
2236 : Object);
2237 282647 : if (!is_vector_set()) {
2238 99 : ConfigureVectorState(MEGAMORPHIC, key);
2239 : TRACE_GENERIC_IC("unhandled internalized string key");
2240 99 : TRACE_IC("StoreIC", key);
2241 : }
2242 : return store_handle;
2243 : }
2244 :
2245 836011 : bool use_ic = FLAG_use_ic && !object->IsStringWrapper() &&
2246 835968 : !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy();
2247 835774 : if (use_ic && !object->IsSmi()) {
2248 : // Don't use ICs for maps of the objects in Array's prototype chain. We
2249 : // expect to be able to trap element sets to objects with those maps in
2250 : // the runtime to enable optimization of element hole access.
2251 : Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2252 416927 : if (heap_object->map()->IsMapInArrayPrototypeChain()) {
2253 : TRACE_GENERIC_IC("map in array prototype");
2254 : use_ic = false;
2255 : }
2256 : }
2257 :
2258 : Handle<Map> old_receiver_map;
2259 : bool is_arguments = false;
2260 : bool key_is_valid_index = false;
2261 : KeyedAccessStoreMode store_mode = STANDARD_STORE;
2262 834685 : if (use_ic && object->IsJSObject()) {
2263 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2264 : old_receiver_map = handle(receiver->map(), isolate());
2265 : is_arguments = receiver->IsJSArgumentsObject();
2266 414785 : if (!is_arguments) {
2267 823445 : key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0;
2268 412910 : if (key_is_valid_index) {
2269 409926 : uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value());
2270 409926 : store_mode = GetStoreMode(receiver, index, value);
2271 : }
2272 : }
2273 : }
2274 :
2275 : DCHECK(store_handle.is_null());
2276 1254585 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2277 : Runtime::SetObjectProperty(isolate(), object, key,
2278 : value, language_mode()),
2279 : Object);
2280 :
2281 265186 : if (use_ic) {
2282 263521 : if (!old_receiver_map.is_null()) {
2283 262620 : if (is_arguments) {
2284 : TRACE_GENERIC_IC("arguments receiver");
2285 260745 : } else if (key_is_valid_index) {
2286 : // We should go generic if receiver isn't a dictionary, but our
2287 : // prototype chain does have dictionary elements. This ensures that
2288 : // other non-dictionary receivers in the polymorphic case benefit
2289 : // from fast path keyed stores.
2290 258735 : if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) {
2291 247830 : UpdateStoreElement(old_receiver_map, store_mode);
2292 : } else {
2293 : TRACE_GENERIC_IC("dictionary or proxy prototype");
2294 : }
2295 : } else {
2296 : TRACE_GENERIC_IC("non-smi-like key");
2297 : }
2298 : } else {
2299 : TRACE_GENERIC_IC("non-JSObject receiver");
2300 : }
2301 : }
2302 :
2303 265186 : if (!is_vector_set()) {
2304 20814 : ConfigureVectorState(MEGAMORPHIC, key);
2305 : }
2306 265186 : TRACE_IC("StoreIC", key);
2307 :
2308 : return store_handle;
2309 : }
2310 :
2311 :
2312 : #undef TRACE_IC
2313 :
2314 :
2315 : // ----------------------------------------------------------------------------
2316 : // Static IC stub generators.
2317 : //
2318 :
2319 : // Used from ic-<arch>.cc.
2320 8719557 : RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2321 4359779 : HandleScope scope(isolate);
2322 : DCHECK_EQ(4, args.length());
2323 : // Runtime functions don't follow the IC's calling convention.
2324 4359779 : Handle<Object> receiver = args.at(0);
2325 4359779 : Handle<Name> key = args.at<Name>(1);
2326 4359779 : Handle<Smi> slot = args.at<Smi>(2);
2327 4359779 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2328 4359779 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2329 : // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2330 : // LoadIC miss handler if the handler misses. Since the vector Nexus is
2331 : // set up outside the IC, handle that here.
2332 4359778 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2333 4359778 : if (IsLoadICKind(kind)) {
2334 4359620 : LoadICNexus nexus(vector, vector_slot);
2335 8719240 : LoadIC ic(isolate, &nexus);
2336 4359622 : ic.UpdateState(receiver, key);
2337 13078864 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2338 :
2339 158 : } else if (IsLoadGlobalICKind(kind)) {
2340 : DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2341 158 : receiver = isolate->global_object();
2342 158 : LoadGlobalICNexus nexus(vector, vector_slot);
2343 316 : LoadGlobalIC ic(isolate, &nexus);
2344 158 : ic.UpdateState(receiver, key);
2345 474 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2346 :
2347 : } else {
2348 : DCHECK(IsKeyedLoadICKind(kind));
2349 0 : KeyedLoadICNexus nexus(vector, vector_slot);
2350 0 : KeyedLoadIC ic(isolate, &nexus);
2351 0 : ic.UpdateState(receiver, key);
2352 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2353 4359779 : }
2354 : }
2355 :
2356 : // Used from ic-<arch>.cc.
2357 4188843 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2358 2094421 : HandleScope scope(isolate);
2359 : DCHECK_EQ(3, args.length());
2360 : // Runtime functions don't follow the IC's calling convention.
2361 2094422 : Handle<JSGlobalObject> global = isolate->global_object();
2362 2094422 : Handle<String> name = args.at<String>(0);
2363 2094422 : Handle<Smi> slot = args.at<Smi>(1);
2364 2094422 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2365 2094421 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2366 :
2367 4188844 : LoadGlobalICNexus nexus(vector, vector_slot);
2368 4188844 : LoadGlobalIC ic(isolate, &nexus);
2369 2094422 : ic.UpdateState(global, name);
2370 :
2371 : Handle<Object> result;
2372 4188844 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2373 2094422 : return *result;
2374 : }
2375 :
2376 1736 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2377 868 : HandleScope scope(isolate);
2378 : DCHECK_EQ(3, args.length());
2379 1736 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2380 :
2381 868 : Handle<Context> native_context = isolate->native_context();
2382 : Handle<ScriptContextTable> script_contexts(
2383 868 : native_context->script_context_table());
2384 :
2385 : ScriptContextTable::LookupResult lookup_result;
2386 868 : if (ScriptContextTable::Lookup(script_contexts, name, &lookup_result)) {
2387 : Handle<Context> script_context = ScriptContextTable::GetContext(
2388 0 : script_contexts, lookup_result.context_index);
2389 : Handle<Object> result =
2390 0 : FixedArray::get(*script_context, lookup_result.slot_index, isolate);
2391 0 : if (*result == isolate->heap()->the_hole_value()) {
2392 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2393 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2394 : }
2395 : return *result;
2396 : }
2397 :
2398 868 : Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2399 : Handle<Object> result;
2400 868 : bool is_found = false;
2401 1736 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2402 : isolate, result,
2403 : Runtime::GetObjectProperty(isolate, global, name, &is_found));
2404 868 : if (!is_found) {
2405 0 : Handle<Smi> slot = args.at<Smi>(1);
2406 0 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2407 0 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2408 0 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2409 : // It is actually a LoadGlobalICs here but the predicate handles this case
2410 : // properly.
2411 0 : if (LoadIC::ShouldThrowReferenceError(kind)) {
2412 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2413 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2414 : }
2415 : }
2416 868 : return *result;
2417 : }
2418 :
2419 : // Used from ic-<arch>.cc
2420 1408136 : RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2421 704068 : HandleScope scope(isolate);
2422 : DCHECK_EQ(4, args.length());
2423 : // Runtime functions don't follow the IC's calling convention.
2424 704068 : Handle<Object> receiver = args.at(0);
2425 704068 : Handle<Object> key = args.at(1);
2426 704068 : Handle<Smi> slot = args.at<Smi>(2);
2427 704068 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(3);
2428 704068 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2429 1408136 : KeyedLoadICNexus nexus(vector, vector_slot);
2430 1408136 : KeyedLoadIC ic(isolate, &nexus);
2431 704068 : ic.UpdateState(receiver, key);
2432 2112204 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2433 : }
2434 :
2435 : // Used from ic-<arch>.cc.
2436 11791868 : RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2437 5895934 : HandleScope scope(isolate);
2438 : DCHECK_EQ(5, args.length());
2439 : // Runtime functions don't follow the IC's calling convention.
2440 5895934 : Handle<Object> value = args.at(0);
2441 5895934 : Handle<Smi> slot = args.at<Smi>(1);
2442 5895934 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2443 5895934 : Handle<Object> receiver = args.at(3);
2444 5895934 : Handle<Name> key = args.at<Name>(4);
2445 5895934 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2446 5895934 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2447 5895934 : if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
2448 4204991 : StoreICNexus nexus(vector, vector_slot);
2449 8409983 : StoreIC ic(isolate, &nexus);
2450 4204991 : ic.UpdateState(receiver, key);
2451 12614974 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2452 1690942 : } else if (IsStoreGlobalICKind(kind)) {
2453 1690942 : StoreICNexus nexus(vector, vector_slot);
2454 3381884 : StoreGlobalIC ic(isolate, &nexus);
2455 1690942 : ic.UpdateState(receiver, key);
2456 5072826 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2457 : } else {
2458 : DCHECK(IsKeyedStoreICKind(kind));
2459 0 : KeyedStoreICNexus nexus(vector, vector_slot);
2460 0 : KeyedStoreIC ic(isolate, &nexus);
2461 0 : ic.UpdateState(receiver, key);
2462 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2463 5895934 : }
2464 : }
2465 :
2466 : // Used from ic-<arch>.cc.
2467 1405076 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2468 702538 : HandleScope scope(isolate);
2469 : DCHECK_EQ(5, args.length());
2470 : // Runtime functions don't follow the IC's calling convention.
2471 702538 : Handle<Object> value = args.at(0);
2472 702538 : Handle<Smi> slot = args.at<Smi>(1);
2473 702538 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2474 702538 : Handle<Object> receiver = args.at(3);
2475 702538 : Handle<Object> key = args.at(4);
2476 702538 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2477 1405076 : KeyedStoreICNexus nexus(vector, vector_slot);
2478 1405076 : KeyedStoreIC ic(isolate, &nexus);
2479 702538 : ic.UpdateState(receiver, key);
2480 2107614 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2481 : }
2482 :
2483 :
2484 2036558 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2485 1018279 : HandleScope scope(isolate);
2486 : DCHECK_EQ(5, args.length());
2487 : // Runtime functions don't follow the IC's calling convention.
2488 1018279 : Handle<Object> value = args.at(0);
2489 1018279 : Handle<Smi> slot = args.at<Smi>(1);
2490 1018279 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2491 1018279 : Handle<Object> object = args.at(3);
2492 1018279 : Handle<Object> key = args.at(4);
2493 1018279 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2494 1018279 : LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2495 2036558 : RETURN_RESULT_OR_FAILURE(
2496 : isolate,
2497 1018279 : Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2498 : }
2499 :
2500 :
2501 2622 : RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2502 1311 : HandleScope scope(isolate);
2503 : DCHECK_EQ(6, args.length());
2504 : // Runtime functions don't follow the IC's calling convention.
2505 1311 : Handle<Object> object = args.at(0);
2506 1311 : Handle<Object> key = args.at(1);
2507 1311 : Handle<Object> value = args.at(2);
2508 1311 : Handle<Map> map = args.at<Map>(3);
2509 1311 : Handle<Smi> slot = args.at<Smi>(4);
2510 1311 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2511 1311 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2512 1311 : LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2513 1311 : if (object->IsJSObject()) {
2514 : JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2515 1311 : map->elements_kind());
2516 : }
2517 2622 : RETURN_RESULT_OR_FAILURE(
2518 : isolate,
2519 1311 : Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
2520 : }
2521 :
2522 :
2523 437808 : MaybeHandle<Object> BinaryOpIC::Transition(
2524 : Handle<AllocationSite> allocation_site, Handle<Object> left,
2525 : Handle<Object> right) {
2526 2170408 : BinaryOpICState state(isolate(), extra_ic_state());
2527 :
2528 : // Compute the actual result using the builtin for the binary operation.
2529 : Handle<Object> result;
2530 437808 : switch (state.op()) {
2531 : default:
2532 0 : UNREACHABLE();
2533 : case Token::ADD:
2534 452106 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2535 : Object::Add(isolate(), left, right), Object);
2536 : break;
2537 : case Token::SUB:
2538 38648 : ASSIGN_RETURN_ON_EXCEPTION(
2539 : isolate(), result, Object::Subtract(isolate(), left, right), Object);
2540 : break;
2541 : case Token::MUL:
2542 86458 : ASSIGN_RETURN_ON_EXCEPTION(
2543 : isolate(), result, Object::Multiply(isolate(), left, right), Object);
2544 : break;
2545 : case Token::DIV:
2546 23202 : ASSIGN_RETURN_ON_EXCEPTION(
2547 : isolate(), result, Object::Divide(isolate(), left, right), Object);
2548 : break;
2549 : case Token::MOD:
2550 10376 : ASSIGN_RETURN_ON_EXCEPTION(
2551 : isolate(), result, Object::Modulus(isolate(), left, right), Object);
2552 : break;
2553 : case Token::BIT_OR:
2554 128256 : ASSIGN_RETURN_ON_EXCEPTION(
2555 : isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
2556 : break;
2557 : case Token::BIT_AND:
2558 39192 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2559 : Object::BitwiseAnd(isolate(), left, right),
2560 : Object);
2561 : break;
2562 : case Token::BIT_XOR:
2563 16552 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2564 : Object::BitwiseXor(isolate(), left, right),
2565 : Object);
2566 : break;
2567 : case Token::SAR:
2568 41772 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
2569 : Object::ShiftRight(isolate(), left, right),
2570 : Object);
2571 : break;
2572 : case Token::SHR:
2573 20614 : ASSIGN_RETURN_ON_EXCEPTION(
2574 : isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
2575 : Object);
2576 : break;
2577 : case Token::SHL:
2578 18440 : ASSIGN_RETURN_ON_EXCEPTION(
2579 : isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
2580 : break;
2581 : }
2582 :
2583 : // Do not try to update the target if the code was marked for lazy
2584 : // deoptimization. (Since we do not relocate addresses in these
2585 : // code objects, an attempt to access the target could fail.)
2586 433809 : if (AddressIsDeoptimizedCode()) {
2587 : return result;
2588 : }
2589 :
2590 : // Compute the new state.
2591 433805 : BinaryOpICState old_state(isolate(), target()->extra_ic_state());
2592 433805 : state.Update(left, right, result);
2593 :
2594 : // Check if we have a string operation here.
2595 : Handle<Code> new_target;
2596 867152 : if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
2597 : // Setup the allocation site on-demand.
2598 46824 : if (allocation_site.is_null()) {
2599 46366 : allocation_site = isolate()->factory()->NewAllocationSite();
2600 : }
2601 :
2602 : // Install the stub with an allocation site.
2603 : BinaryOpICWithAllocationSiteStub stub(isolate(), state);
2604 46824 : new_target = stub.GetCodeCopyFromTemplate(allocation_site);
2605 :
2606 : // Sanity check the trampoline stub.
2607 : DCHECK_EQ(*allocation_site, new_target->FindFirstAllocationSite());
2608 : } else {
2609 : // Install the generic stub.
2610 : BinaryOpICStub stub(isolate(), state);
2611 386981 : new_target = stub.GetCode();
2612 :
2613 : // Sanity check the generic stub.
2614 : DCHECK_NULL(new_target->FindFirstAllocationSite());
2615 : }
2616 : set_target(*new_target);
2617 :
2618 433805 : if (FLAG_ic_stats &
2619 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
2620 : auto ic_stats = ICStats::instance();
2621 0 : ic_stats->Begin();
2622 : ICInfo& ic_info = ic_stats->Current();
2623 0 : ic_info.type = "BinaryOpIC";
2624 0 : ic_info.state = old_state.ToString();
2625 : ic_info.state += " => ";
2626 0 : ic_info.state += state.ToString();
2627 0 : JavaScriptFrame::CollectTopFrameForICStats(isolate());
2628 0 : ic_stats->End();
2629 433805 : } else if (FLAG_ic_stats) {
2630 : int line;
2631 : int column;
2632 0 : Address pc = GetAbstractPC(&line, &column);
2633 0 : LOG(isolate(),
2634 : BinaryOpIC(pc, line, column, *new_target, old_state.ToString().c_str(),
2635 : state.ToString().c_str(),
2636 : allocation_site.is_null() ? nullptr : *allocation_site));
2637 : }
2638 :
2639 : // Patch the inlined smi code as necessary.
2640 1285248 : if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
2641 761632 : PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
2642 69156 : } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
2643 0 : PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
2644 : }
2645 :
2646 : return result;
2647 : }
2648 :
2649 :
2650 874694 : RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
2651 437347 : HandleScope scope(isolate);
2652 : DCHECK_EQ(2, args.length());
2653 : typedef BinaryOpDescriptor Descriptor;
2654 437347 : Handle<Object> left = args.at(Descriptor::kLeft);
2655 437347 : Handle<Object> right = args.at(Descriptor::kRight);
2656 874694 : BinaryOpIC ic(isolate);
2657 874694 : RETURN_RESULT_OR_FAILURE(
2658 437347 : isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
2659 : }
2660 :
2661 :
2662 922 : RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
2663 461 : HandleScope scope(isolate);
2664 : DCHECK_EQ(3, args.length());
2665 : typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
2666 : Handle<AllocationSite> allocation_site =
2667 461 : args.at<AllocationSite>(Descriptor::kAllocationSite);
2668 461 : Handle<Object> left = args.at(Descriptor::kLeft);
2669 461 : Handle<Object> right = args.at(Descriptor::kRight);
2670 922 : BinaryOpIC ic(isolate);
2671 922 : RETURN_RESULT_OR_FAILURE(isolate,
2672 461 : ic.Transition(allocation_site, left, right));
2673 : }
2674 :
2675 2 : Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
2676 : CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
2677 : CompareICState::UNINITIALIZED,
2678 : CompareICState::UNINITIALIZED);
2679 2 : Code* code = NULL;
2680 2 : CHECK(stub.FindCodeInCache(&code));
2681 2 : return code;
2682 : }
2683 :
2684 272912 : Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
2685 1071312 : HandleScope scope(isolate());
2686 : CompareICStub old_stub(target()->stub_key(), isolate());
2687 : CompareICState::State new_left =
2688 272912 : CompareICState::NewInputState(old_stub.left(), x);
2689 : CompareICState::State new_right =
2690 272912 : CompareICState::NewInputState(old_stub.right(), y);
2691 : CompareICState::State state = CompareICState::TargetState(
2692 : isolate(), old_stub.state(), old_stub.left(), old_stub.right(), op_,
2693 545824 : HasInlinedSmiCode(address()), x, y);
2694 272912 : CompareICStub stub(isolate(), op_, new_left, new_right, state);
2695 272912 : if (state == CompareICState::KNOWN_RECEIVER) {
2696 : stub.set_known_map(
2697 : Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate()));
2698 : }
2699 272912 : Handle<Code> new_target = stub.GetCode();
2700 : set_target(*new_target);
2701 :
2702 272912 : if (FLAG_ic_stats &
2703 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
2704 : auto ic_stats = ICStats::instance();
2705 0 : ic_stats->Begin();
2706 : ICInfo& ic_info = ic_stats->Current();
2707 0 : ic_info.type = "CompareIC";
2708 0 : JavaScriptFrame::CollectTopFrameForICStats(isolate());
2709 0 : ic_info.state = "((";
2710 0 : ic_info.state += CompareICState::GetStateName(old_stub.left());
2711 : ic_info.state += "+";
2712 0 : ic_info.state += CompareICState::GetStateName(old_stub.right());
2713 : ic_info.state += "=";
2714 0 : ic_info.state += CompareICState::GetStateName(old_stub.state());
2715 : ic_info.state += ")->(";
2716 0 : ic_info.state += CompareICState::GetStateName(new_left);
2717 : ic_info.state += "+";
2718 0 : ic_info.state += CompareICState::GetStateName(new_right);
2719 : ic_info.state += "=";
2720 0 : ic_info.state += CompareICState::GetStateName(state);
2721 : ic_info.state += "))#";
2722 0 : ic_info.state += Token::Name(op_);
2723 0 : ic_stats->End();
2724 272912 : } else if (FLAG_ic_stats) {
2725 : int line;
2726 : int column;
2727 0 : Address pc = GetAbstractPC(&line, &column);
2728 0 : LOG(isolate(),
2729 : CompareIC(pc, line, column, *stub.GetCode(), Token::Name(op_),
2730 : CompareICState::GetStateName(old_stub.left()),
2731 : CompareICState::GetStateName(old_stub.right()),
2732 : CompareICState::GetStateName(old_stub.state()),
2733 : CompareICState::GetStateName(new_left),
2734 : CompareICState::GetStateName(new_right),
2735 : CompareICState::GetStateName(state)));
2736 : }
2737 :
2738 : // Activate inlined smi code.
2739 272912 : if (old_stub.state() == CompareICState::UNINITIALIZED) {
2740 505152 : PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
2741 : }
2742 :
2743 272912 : return *new_target;
2744 : }
2745 :
2746 :
2747 : // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc.
2748 545824 : RUNTIME_FUNCTION(Runtime_CompareIC_Miss) {
2749 272912 : HandleScope scope(isolate);
2750 : DCHECK(args.length() == 3);
2751 545824 : CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
2752 545824 : return ic.UpdateCaches(args.at(0), args.at(1));
2753 : }
2754 :
2755 :
2756 0 : RUNTIME_FUNCTION(Runtime_Unreachable) {
2757 0 : UNREACHABLE();
2758 : CHECK(false);
2759 : return isolate->heap()->undefined_value();
2760 : }
2761 :
2762 :
2763 130693 : Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) {
2764 261386 : ToBooleanICStub stub(isolate(), extra_ic_state());
2765 130693 : ToBooleanHints old_hints = stub.hints();
2766 130693 : bool to_boolean_value = stub.UpdateStatus(object);
2767 130693 : ToBooleanHints new_hints = stub.hints();
2768 130693 : Handle<Code> code = stub.GetCode();
2769 : set_target(*code);
2770 :
2771 : // Note: Although a no-op transition is semantically OK, it is hinting at a
2772 : // bug somewhere in our state transition machinery.
2773 : DCHECK_NE(old_hints, new_hints);
2774 130693 : if (V8_UNLIKELY(FLAG_ic_stats)) {
2775 0 : if (FLAG_ic_stats &
2776 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
2777 : auto ic_stats = ICStats::instance();
2778 0 : ic_stats->Begin();
2779 : ICInfo& ic_info = ic_stats->Current();
2780 0 : ic_info.type = "ToBooleanIC";
2781 0 : ic_info.state = ToString(old_hints);
2782 : ic_info.state += "=>";
2783 0 : ic_info.state += ToString(new_hints);
2784 0 : ic_stats->End();
2785 : } else {
2786 : int line;
2787 : int column;
2788 0 : Address pc = GetAbstractPC(&line, &column);
2789 0 : LOG(isolate(),
2790 : ToBooleanIC(pc, line, column, *code, ToString(old_hints).c_str(),
2791 : ToString(new_hints).c_str()));
2792 : }
2793 : }
2794 :
2795 261386 : return isolate()->factory()->ToBoolean(to_boolean_value);
2796 : }
2797 :
2798 :
2799 261386 : RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) {
2800 : DCHECK(args.length() == 1);
2801 130693 : HandleScope scope(isolate);
2802 130693 : Handle<Object> object = args.at(0);
2803 261386 : ToBooleanIC ic(isolate);
2804 392079 : return *ic.ToBoolean(object);
2805 : }
2806 :
2807 :
2808 77105994 : RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2809 38552997 : Handle<JSObject> receiver = args.at<JSObject>(0);
2810 38552997 : Handle<JSObject> holder = args.at<JSObject>(1);
2811 38552997 : Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
2812 38552997 : Handle<Name> name = args.at<Name>(3);
2813 38552997 : Handle<Object> value = args.at(4);
2814 77105994 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
2815 38552997 : HandleScope scope(isolate);
2816 :
2817 38552997 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
2818 0 : RETURN_RESULT_OR_FAILURE(
2819 : isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
2820 : language_mode));
2821 : }
2822 :
2823 : Handle<AccessorInfo> callback(
2824 : callback_or_cell->IsWeakCell()
2825 37291104 : ? AccessorInfo::cast(WeakCell::cast(*callback_or_cell)->value())
2826 38552997 : : AccessorInfo::cast(*callback_or_cell));
2827 :
2828 : DCHECK(callback->IsCompatibleReceiver(*receiver));
2829 :
2830 38552997 : Address setter_address = v8::ToCData<Address>(callback->setter());
2831 : v8::AccessorNameSetterCallback fun =
2832 38552997 : FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address);
2833 : DCHECK(fun != NULL);
2834 :
2835 : Object::ShouldThrow should_throw =
2836 38552997 : is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
2837 : PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
2838 77105994 : *holder, should_throw);
2839 38552997 : custom_args.Call(fun, name, value);
2840 38552997 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2841 38552997 : return *value;
2842 : }
2843 :
2844 :
2845 : /**
2846 : * Loads a property with an interceptor performing post interceptor
2847 : * lookup if interceptor failed.
2848 : */
2849 589584 : RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2850 294792 : HandleScope scope(isolate);
2851 : DCHECK_EQ(5, args.length());
2852 294792 : Handle<Name> name = args.at<Name>(0);
2853 294792 : Handle<Object> receiver = args.at(1);
2854 294792 : Handle<JSObject> holder = args.at<JSObject>(2);
2855 :
2856 294792 : if (!receiver->IsJSReceiver()) {
2857 12 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2858 : isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2859 : }
2860 :
2861 294792 : InterceptorInfo* interceptor = holder->GetNamedInterceptor();
2862 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2863 589584 : *holder, Object::DONT_THROW);
2864 :
2865 : v8::GenericNamedPropertyGetterCallback getter =
2866 : v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
2867 294792 : interceptor->getter());
2868 294792 : Handle<Object> result = arguments.Call(getter, name);
2869 :
2870 294792 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2871 :
2872 294778 : if (!result.is_null()) return *result;
2873 :
2874 202749 : LookupIterator it(receiver, name, holder);
2875 : // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2876 608247 : while (it.state() != LookupIterator::INTERCEPTOR ||
2877 405498 : !it.GetHolder<JSObject>().is_identical_to(holder)) {
2878 : DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2879 0 : it.Next();
2880 : }
2881 : // Skip past the interceptor.
2882 202749 : it.Next();
2883 405498 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2884 :
2885 202735 : if (it.IsFound()) return *result;
2886 :
2887 7510 : Handle<Smi> slot = args.at<Smi>(3);
2888 7510 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2889 7510 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2890 7510 : FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2891 : // It could actually be any kind of load IC slot here but the predicate
2892 : // handles all the cases properly.
2893 7510 : if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
2894 7356 : return isolate->heap()->undefined_value();
2895 : }
2896 :
2897 : // Throw a reference error.
2898 462 : THROW_NEW_ERROR_RETURN_FAILURE(
2899 294792 : isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
2900 : }
2901 :
2902 :
2903 1274710 : RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
2904 637355 : HandleScope scope(isolate);
2905 : DCHECK_EQ(5, args.length());
2906 : // Runtime functions don't follow the IC's calling convention.
2907 637355 : Handle<Object> value = args.at(0);
2908 637355 : Handle<Smi> slot = args.at<Smi>(1);
2909 637355 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2910 637355 : Handle<JSObject> receiver = args.at<JSObject>(3);
2911 637355 : Handle<Name> name = args.at<Name>(4);
2912 637355 : FeedbackSlot vector_slot = vector->ToSlot(slot->value());
2913 637355 : LanguageMode language_mode = vector->GetLanguageMode(vector_slot);
2914 :
2915 : DCHECK(receiver->HasNamedInterceptor());
2916 637355 : InterceptorInfo* interceptor = receiver->GetNamedInterceptor();
2917 : DCHECK(!interceptor->non_masking());
2918 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2919 1274710 : *receiver, Object::DONT_THROW);
2920 :
2921 : v8::GenericNamedPropertySetterCallback setter =
2922 : v8::ToCData<v8::GenericNamedPropertySetterCallback>(
2923 637355 : interceptor->setter());
2924 637355 : Handle<Object> result = arguments.Call(setter, name, value);
2925 637355 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2926 637348 : if (!result.is_null()) return *value;
2927 :
2928 350294 : LookupIterator it(receiver, name, receiver);
2929 : // Skip past any access check on the receiver.
2930 350294 : if (it.state() == LookupIterator::ACCESS_CHECK) {
2931 : DCHECK(it.HasAccess());
2932 0 : it.Next();
2933 : }
2934 : // Skip past the interceptor on the receiver.
2935 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2936 350294 : it.Next();
2937 :
2938 350294 : MAYBE_RETURN(Object::SetProperty(&it, value, language_mode,
2939 : JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED),
2940 : isolate->heap()->exception());
2941 637355 : return *value;
2942 : }
2943 :
2944 :
2945 5208 : RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2946 : // TODO(verwaest): This should probably get the holder and receiver as input.
2947 2604 : HandleScope scope(isolate);
2948 2604 : Handle<JSObject> receiver = args.at<JSObject>(0);
2949 : DCHECK(args.smi_at(1) >= 0);
2950 2604 : uint32_t index = args.smi_at(1);
2951 :
2952 2604 : InterceptorInfo* interceptor = receiver->GetIndexedInterceptor();
2953 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2954 5208 : *receiver, Object::DONT_THROW);
2955 :
2956 : v8::IndexedPropertyGetterCallback getter =
2957 2604 : v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
2958 2604 : Handle<Object> result = arguments.Call(getter, index);
2959 :
2960 2604 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2961 :
2962 2604 : if (result.is_null()) {
2963 0 : LookupIterator it(isolate, receiver, index, receiver);
2964 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2965 0 : it.Next();
2966 0 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2967 : Object::GetProperty(&it));
2968 : }
2969 :
2970 2604 : return *result;
2971 : }
2972 : } // namespace internal
2973 : } // namespace v8
|