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-inl.h"
11 : #include "src/ast/ast.h"
12 : #include "src/base/bits.h"
13 : #include "src/code-factory.h"
14 : #include "src/conversions.h"
15 : #include "src/execution.h"
16 : #include "src/field-type.h"
17 : #include "src/frames-inl.h"
18 : #include "src/handles-inl.h"
19 : #include "src/ic/call-optimization.h"
20 : #include "src/ic/handler-configuration-inl.h"
21 : #include "src/ic/ic-inl.h"
22 : #include "src/ic/ic-stats.h"
23 : #include "src/ic/stub-cache.h"
24 : #include "src/isolate-inl.h"
25 : #include "src/objects/api-callbacks.h"
26 : #include "src/objects/data-handler-inl.h"
27 : #include "src/objects/hash-table-inl.h"
28 : #include "src/objects/heap-number-inl.h"
29 : #include "src/objects/js-array-inl.h"
30 : #include "src/objects/module-inl.h"
31 : #include "src/objects/struct-inl.h"
32 : #include "src/prototype.h"
33 : #include "src/runtime-profiler.h"
34 : #include "src/runtime/runtime-utils.h"
35 : #include "src/runtime/runtime.h"
36 : #include "src/tracing/trace-event.h"
37 : #include "src/tracing/tracing-category-observer.h"
38 :
39 : namespace v8 {
40 : namespace internal {
41 :
42 0 : char IC::TransitionMarkFromState(IC::State state) {
43 0 : switch (state) {
44 : case NO_FEEDBACK:
45 0 : UNREACHABLE();
46 : case UNINITIALIZED:
47 : return '0';
48 : case PREMONOMORPHIC:
49 0 : return '.';
50 : case MONOMORPHIC:
51 0 : return '1';
52 : case RECOMPUTE_HANDLER:
53 0 : return '^';
54 : case POLYMORPHIC:
55 0 : return 'P';
56 : case MEGAMORPHIC:
57 0 : return 'N';
58 : case GENERIC:
59 0 : return 'G';
60 : }
61 0 : UNREACHABLE();
62 : }
63 :
64 : namespace {
65 :
66 : const char* GetModifier(KeyedAccessLoadMode mode) {
67 0 : if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB";
68 : return "";
69 : }
70 :
71 : const char* GetModifier(KeyedAccessStoreMode mode) {
72 0 : switch (mode) {
73 : case STORE_NO_TRANSITION_HANDLE_COW:
74 : return ".COW";
75 : case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
76 : return ".STORE+COW";
77 : case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
78 : return ".IGNORE_OOB";
79 : default:
80 : break;
81 : }
82 : DCHECK(!IsCOWHandlingStoreMode(mode));
83 0 : return IsGrowStoreMode(mode) ? ".GROW" : "";
84 : }
85 :
86 : } // namespace
87 :
88 6584845 : void IC::TraceIC(const char* type, Handle<Object> name) {
89 6584845 : if (FLAG_ic_stats) {
90 6584845 : if (AddressIsDeoptimizedCode()) return;
91 0 : State new_state = nexus()->StateFromFeedback();
92 0 : TraceIC(type, name, state(), new_state);
93 : }
94 : }
95 :
96 0 : void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
97 0 : State new_state) {
98 0 : if (V8_LIKELY(!FLAG_ic_stats)) return;
99 :
100 0 : Map map;
101 0 : if (!receiver_map().is_null()) {
102 0 : map = *receiver_map();
103 : }
104 :
105 : const char* modifier = "";
106 0 : if (IsKeyedLoadIC()) {
107 0 : KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
108 : modifier = GetModifier(mode);
109 0 : } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind())) {
110 0 : KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
111 : modifier = GetModifier(mode);
112 : }
113 :
114 0 : bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind());
115 :
116 0 : if (!(FLAG_ic_stats &
117 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
118 0 : LOG(isolate(), ICEvent(type, keyed_prefix, map, *name,
119 : TransitionMarkFromState(old_state),
120 : TransitionMarkFromState(new_state), modifier,
121 : slow_stub_reason_));
122 : return;
123 : }
124 :
125 0 : ICStats::instance()->Begin();
126 : ICInfo& ic_info = ICStats::instance()->Current();
127 0 : ic_info.type = keyed_prefix ? "Keyed" : "";
128 : ic_info.type += type;
129 :
130 : Object maybe_function =
131 0 : Object(Memory<Address>(fp_ + JavaScriptFrameConstants::kFunctionOffset));
132 : DCHECK(maybe_function->IsJSFunction());
133 0 : JSFunction function = JSFunction::cast(maybe_function);
134 : int code_offset = 0;
135 0 : if (function->IsInterpreted()) {
136 0 : code_offset = InterpretedFrame::GetBytecodeOffset(fp());
137 : } else {
138 0 : code_offset = static_cast<int>(pc() - function->code()->InstructionStart());
139 : }
140 : JavaScriptFrame::CollectFunctionAndOffsetForICStats(
141 0 : function, function->abstract_code(), code_offset);
142 :
143 : // Reserve enough space for IC transition state, the longest length is 17.
144 0 : ic_info.state.reserve(17);
145 : ic_info.state = "(";
146 0 : ic_info.state += TransitionMarkFromState(old_state);
147 : ic_info.state += "->";
148 0 : ic_info.state += TransitionMarkFromState(new_state);
149 : ic_info.state += modifier;
150 : ic_info.state += ")";
151 0 : ic_info.map = reinterpret_cast<void*>(map.ptr());
152 0 : if (!map.is_null()) {
153 0 : ic_info.is_dictionary_map = map->is_dictionary_map();
154 0 : ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
155 0 : ic_info.instance_type = std::to_string(map->instance_type());
156 : }
157 : // TODO(lpy) Add name as key field in ICStats.
158 0 : ICStats::instance()->End();
159 : }
160 :
161 6853607 : IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
162 : FeedbackSlotKind kind)
163 : : isolate_(isolate),
164 : vector_set_(false),
165 : kind_(kind),
166 : target_maps_set_(false),
167 : slow_stub_reason_(nullptr),
168 13707214 : nexus_(vector, slot) {
169 : // To improve the performance of the (much used) IC code, we unfold a few
170 : // levels of the stack frame iteration code. This yields a ~35% speedup when
171 : // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
172 6853648 : const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
173 : Address* constant_pool = nullptr;
174 : if (FLAG_enable_embedded_constant_pool) {
175 : constant_pool = reinterpret_cast<Address*>(
176 : entry + ExitFrameConstants::kConstantPoolOffset);
177 : }
178 : Address* pc_address =
179 6853648 : reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
180 6853648 : Address fp = Memory<Address>(entry + ExitFrameConstants::kCallerFPOffset);
181 : #ifdef DEBUG
182 : StackFrameIterator it(isolate);
183 : for (int i = 0; i < 1; i++) it.Advance();
184 : StackFrame* frame = it.frame();
185 : DCHECK(fp == frame->fp() && pc_address == frame->pc_address());
186 : #endif
187 : // For interpreted functions, some bytecode handlers construct a
188 : // frame. We have to skip the constructed frame to find the interpreted
189 : // function's frame. Check if the there is an additional frame, and if there
190 : // is skip this frame. However, the pc should not be updated. The call to
191 : // ICs happen from bytecode handlers.
192 : intptr_t frame_marker =
193 13707296 : Memory<intptr_t>(fp + TypedFrameConstants::kFrameTypeOffset);
194 6853648 : if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
195 6161433 : fp = Memory<Address>(fp + TypedFrameConstants::kCallerFPOffset);
196 : }
197 6853648 : fp_ = fp;
198 : if (FLAG_enable_embedded_constant_pool) {
199 : constant_pool_address_ = constant_pool;
200 : }
201 6853648 : pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
202 : DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind());
203 6853648 : state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.StateFromFeedback();
204 6853613 : old_state_ = state_;
205 6853613 : }
206 :
207 9522033 : JSFunction IC::GetHostFunction() const {
208 : // Compute the JavaScript frame for the frame pointer of this IC
209 : // structure. We need this to be able to find the function
210 : // corresponding to the frame.
211 2450144 : StackFrameIterator it(isolate());
212 9522041 : while (it.frame()->fp() != this->fp()) it.Advance();
213 : JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
214 : // Find the function on the stack and both the active code for the
215 : // function and the original code.
216 4900379 : return frame->function();
217 : }
218 :
219 6739621 : static void LookupForRead(Isolate* isolate, LookupIterator* it) {
220 6763911 : for (; it->IsFound(); it->Next()) {
221 3133004 : switch (it->state()) {
222 : case LookupIterator::NOT_FOUND:
223 : case LookupIterator::TRANSITION:
224 0 : UNREACHABLE();
225 : case LookupIterator::JSPROXY:
226 : return;
227 : case LookupIterator::INTERCEPTOR: {
228 : // If there is a getter, return; otherwise loop to perform the lookup.
229 : Handle<JSObject> holder = it->GetHolder<JSObject>();
230 2708 : if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) {
231 : return;
232 : }
233 : break;
234 : }
235 : case LookupIterator::ACCESS_CHECK:
236 : // ICs know how to perform access checks on global proxies.
237 48700 : if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
238 : break;
239 : }
240 : return;
241 : case LookupIterator::ACCESSOR:
242 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
243 : case LookupIterator::DATA:
244 : return;
245 : }
246 : }
247 : }
248 :
249 616553 : bool IC::ShouldRecomputeHandler(Handle<String> name) {
250 387972 : if (!RecomputeHandlerForName(name)) return false;
251 :
252 : // This is a contextual access, always just update the handler and stay
253 : // monomorphic.
254 379857 : if (IsGlobalIC()) return true;
255 :
256 350519 : maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
257 :
258 : // The current map wasn't handled yet. There's no reason to stay monomorphic,
259 : // *unless* we're moving from a deprecated map to its replacement, or
260 : // to a more general elements kind.
261 : // TODO(verwaest): Check if the current map is actually what the old map
262 : // would transition to.
263 350518 : if (maybe_handler_.is_null()) {
264 337232 : if (!receiver_map()->IsJSObjectMap()) return false;
265 329281 : Map first_map = FirstTargetMap();
266 329282 : if (first_map.is_null()) return false;
267 : Handle<Map> old_map(first_map, isolate());
268 228580 : if (old_map->is_deprecated()) return true;
269 : return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
270 444418 : receiver_map()->elements_kind());
271 : }
272 :
273 : return true;
274 : }
275 :
276 387973 : bool IC::RecomputeHandlerForName(Handle<Object> name) {
277 387973 : if (is_keyed()) {
278 : // Determine whether the failure is due to a name failure.
279 27841 : if (!name->IsName()) return false;
280 9863 : Name stub_name = nexus()->FindFirstName();
281 9863 : if (*name != stub_name) return false;
282 : }
283 :
284 : return true;
285 : }
286 :
287 :
288 13400378 : void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
289 6684306 : if (state() == NO_FEEDBACK) return;
290 6684313 : update_receiver_map(receiver);
291 13368700 : if (!name->IsString()) return;
292 6327980 : if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
293 776182 : if (receiver->IsNullOrUndefined(isolate())) return;
294 :
295 : // Remove the target from the code cache if it became invalid
296 : // because of changes in the prototype chain to avoid hitting it
297 : // again.
298 387971 : if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
299 : MarkRecomputeHandler(name);
300 : }
301 : }
302 :
303 1383 : MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object,
304 2766 : Handle<Object> key) {
305 : HandleScope scope(isolate());
306 2766 : THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
307 : }
308 :
309 :
310 344664 : MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
311 : HandleScope scope(isolate());
312 344664 : THROW_NEW_ERROR(
313 : isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
314 : }
315 :
316 : // static
317 2450185 : void IC::OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
318 : JSFunction host_function, const char* reason) {
319 2450185 : FeedbackVector vector = nexus->vector();
320 2450185 : FeedbackSlot slot = nexus->slot();
321 2450185 : OnFeedbackChanged(isolate, vector, slot, host_function, reason);
322 2450182 : }
323 :
324 : // static
325 4955316 : void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector vector,
326 : FeedbackSlot slot, JSFunction host_function,
327 : const char* reason) {
328 2477658 : if (FLAG_trace_opt_verbose) {
329 : // TODO(leszeks): The host function is only needed for this print, we could
330 : // remove it as a parameter if we're of with removing this trace (or only
331 : // tracing the feedback vector, not the function name).
332 0 : if (vector->profiler_ticks() != 0) {
333 0 : PrintF("[resetting ticks for ");
334 0 : host_function->ShortPrint();
335 : PrintF(" due from %d due to IC change: %s]\n", vector->profiler_ticks(),
336 0 : reason);
337 : }
338 : }
339 : vector->set_profiler_ticks(0);
340 :
341 : #ifdef V8_TRACE_FEEDBACK_UPDATES
342 : if (FLAG_trace_feedback_updates) {
343 : int slot_count = vector->metadata()->slot_count();
344 :
345 : StdoutStream os;
346 : if (slot.IsInvalid()) {
347 : os << "[Feedback slots in ";
348 : } else {
349 : os << "[Feedback slot " << slot.ToInt() << "/" << slot_count << " in ";
350 : }
351 : vector->shared_function_info()->ShortPrint(os);
352 : if (slot.IsInvalid()) {
353 : os << " updated - ";
354 : } else {
355 : os << " updated to ";
356 : vector->FeedbackSlotPrint(os, slot);
357 : os << " - ";
358 : }
359 : os << reason << "]" << std::endl;
360 : }
361 : #endif
362 :
363 : isolate->runtime_profiler()->NotifyICChanged();
364 : // TODO(2029): When an optimized function is patched, it would
365 : // be nice to propagate the corresponding type information to its
366 : // unoptimized version for the benefit of later inlining.
367 2477658 : }
368 :
369 6859192 : static bool MigrateDeprecated(Handle<Object> object) {
370 13718437 : if (!object->IsJSObject()) return false;
371 6754369 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
372 6754367 : if (!receiver->map()->is_deprecated()) return false;
373 1599 : JSObject::MigrateInstance(Handle<JSObject>::cast(object));
374 1599 : return true;
375 : }
376 :
377 93378 : bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
378 : DCHECK_EQ(MEGAMORPHIC, new_state);
379 : DCHECK_IMPLIES(!is_keyed(), key->IsName());
380 : // Even though we don't change the feedback data, we still want to reset the
381 : // profiler ticks. Real-world observations suggest that optimizing these
382 : // functions doesn't improve performance.
383 : bool changed =
384 93378 : nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
385 46689 : vector_set_ = true;
386 93378 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Megamorphic");
387 46689 : return changed;
388 : }
389 :
390 1116527 : void IC::ConfigureVectorState(Handle<Map> map) {
391 558254 : nexus()->ConfigurePremonomorphic(map);
392 558273 : vector_set_ = true;
393 1116546 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Premonomorphic");
394 558272 : }
395 :
396 0 : void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
397 : Handle<Object> handler) {
398 329798 : ConfigureVectorState(name, map, MaybeObjectHandle(handler));
399 0 : }
400 :
401 1613347 : void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
402 3226736 : const MaybeObjectHandle& handler) {
403 1613347 : if (IsGlobalIC()) {
404 44756 : nexus()->ConfigureHandlerMode(handler);
405 : } else {
406 : // Non-keyed ICs don't track the name explicitly.
407 1568591 : if (!is_keyed()) name = Handle<Name>::null();
408 1568591 : nexus()->ConfigureMonomorphic(name, map, handler);
409 : }
410 :
411 1613364 : vector_set_ = true;
412 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(),
413 3226736 : IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
414 1613370 : }
415 :
416 231848 : void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
417 231853 : MaybeObjectHandles* handlers) {
418 : DCHECK(!IsGlobalIC());
419 : // Non-keyed ICs don't track the name explicitly.
420 231848 : if (!is_keyed()) name = Handle<Name>::null();
421 231848 : nexus()->ConfigurePolymorphic(name, maps, handlers);
422 :
423 231854 : vector_set_ = true;
424 463707 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Polymorphic");
425 231854 : }
426 :
427 3358695 : MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
428 14771895 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
429 :
430 : // If the object is undefined or null it's illegal to try to get any
431 : // of its properties; throw a TypeError in that case.
432 6717406 : if (object->IsNullOrUndefined(isolate())) {
433 2052 : if (use_ic && state() != PREMONOMORPHIC) {
434 : // Ensure the IC state progresses.
435 963 : TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
436 963 : update_receiver_map(object);
437 963 : PatchCache(name, slow_stub());
438 963 : TraceIC("LoadIC", name);
439 : }
440 :
441 1026 : if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
442 167 : return Runtime::ThrowIteratorError(isolate(), object);
443 : }
444 859 : return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
445 : }
446 :
447 3357677 : if (MigrateDeprecated(object)) use_ic = false;
448 :
449 3357680 : if (state() != UNINITIALIZED) {
450 1260584 : JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
451 1260572 : update_receiver_map(object);
452 : }
453 : // Named lookup in the object.
454 3357672 : LookupIterator it(isolate(), object, name);
455 3357675 : LookupForRead(isolate(), &it);
456 :
457 3357669 : if (name->IsPrivate()) {
458 15467 : if (name->IsPrivateName() && !it.IsFound()) {
459 : Handle<String> name_string(String::cast(Symbol::cast(*name)->name()),
460 594 : isolate());
461 : return TypeError(MessageTemplate::kInvalidPrivateFieldRead, object,
462 297 : name_string);
463 : }
464 :
465 : // IC handling of private symbols/fields lookup on JSProxy is not
466 : // supported.
467 30340 : if (object->IsJSProxy()) {
468 : use_ic = false;
469 : }
470 : }
471 :
472 3606015 : if (it.IsFound() || !ShouldThrowReferenceError()) {
473 : // Update inline cache and stub cache.
474 3185675 : if (use_ic) UpdateCaches(&it);
475 :
476 : // Get the property.
477 : Handle<Object> result;
478 :
479 6371390 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
480 : Object);
481 3184585 : if (it.IsFound()) {
482 3107399 : return result;
483 77186 : } else if (!ShouldThrowReferenceError()) {
484 77073 : LOG(isolate(), SuspectReadEvent(*name, *object));
485 77073 : return result;
486 : }
487 : }
488 171802 : return ReferenceError(name);
489 : }
490 :
491 2072876 : MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
492 6517537 : Handle<JSGlobalObject> global = isolate()->global_object();
493 :
494 4145735 : if (name->IsString()) {
495 : // Look up in script context table.
496 2072869 : Handle<String> str_name = Handle<String>::cast(name);
497 : Handle<ScriptContextTable> script_contexts(
498 4145738 : global->native_context()->script_context_table(), isolate());
499 :
500 : ScriptContextTable::LookupResult lookup_result;
501 2072871 : if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
502 : &lookup_result)) {
503 : Handle<Context> script_context = ScriptContextTable::GetContext(
504 149718 : isolate(), script_contexts, lookup_result.context_index);
505 :
506 : Handle<Object> result(script_context->get(lookup_result.slot_index),
507 224576 : isolate());
508 :
509 149719 : if (result->IsTheHole(isolate())) {
510 : // Do not install stubs and stay pre-monomorphic for
511 : // uninitialized accesses.
512 515 : return ReferenceError(name);
513 : }
514 :
515 74346 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
516 74346 : if (use_ic) {
517 74345 : if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
518 74345 : lookup_result.slot_index)) {
519 74344 : TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
520 : } else {
521 : // Given combination of indices can't be encoded, so use slow stub.
522 0 : TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
523 0 : PatchCache(name, slow_stub());
524 : }
525 74344 : TraceIC("LoadGlobalIC", name);
526 : }
527 74342 : return result;
528 : }
529 : }
530 1998013 : return LoadIC::Load(global, name);
531 : }
532 :
533 23533 : static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
534 : Handle<Map> new_receiver_map) {
535 : DCHECK(!new_receiver_map.is_null());
536 82923 : for (Handle<Map> map : *receiver_maps) {
537 80124 : if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
538 : return false;
539 : }
540 : }
541 19328 : receiver_maps->push_back(new_receiver_map);
542 19328 : return true;
543 : }
544 :
545 363003 : bool IC::UpdatePolymorphicIC(Handle<Name> name,
546 114132 : const MaybeObjectHandle& handler) {
547 : DCHECK(IsHandler(*handler));
548 376073 : if (is_keyed() && state() != RECOMPUTE_HANDLER) {
549 25828 : if (nexus()->FindFirstName() != *name) return false;
550 : }
551 354555 : Handle<Map> map = receiver_map();
552 : MapHandles maps;
553 : MaybeObjectHandles handlers;
554 :
555 354555 : TargetMaps(&maps);
556 709140 : int number_of_maps = static_cast<int>(maps.size());
557 : int deprecated_maps = 0;
558 : int handler_to_overwrite = -1;
559 354570 : if (!nexus()->FindHandlers(&handlers, number_of_maps)) return false;
560 :
561 405369 : for (int i = 0; i < number_of_maps; i++) {
562 810799 : Handle<Map> current_map = maps.at(i);
563 405404 : if (current_map->is_deprecated()) {
564 : // Filter out deprecated maps to ensure their instances get migrated.
565 8285 : ++deprecated_maps;
566 397119 : } else if (map.is_identical_to(current_map)) {
567 : // If both map and handler stayed the same (and the name is also the
568 : // same as checked above, for keyed accesses), we're not progressing
569 : // in the lattice and need to go MEGAMORPHIC instead. There's one
570 : // exception to this rule, which is when we're in RECOMPUTE_HANDLER
571 : // state, there we allow to migrate to a new handler.
572 25723 : if (handler.is_identical_to(handlers[i]) &&
573 : state() != RECOMPUTE_HANDLER) {
574 : return false;
575 : }
576 : // If the receiver type is already in the polymorphic IC, this indicates
577 : // there was a prototoype chain failure. In that case, just overwrite the
578 : // handler.
579 : handler_to_overwrite = i;
580 768100 : } else if (handler_to_overwrite == -1 &&
581 383663 : IsTransitionOfMonomorphicTarget(*current_map, *map)) {
582 : handler_to_overwrite = i;
583 : }
584 : }
585 :
586 : int number_of_valid_maps =
587 354213 : number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
588 :
589 354213 : if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
590 441660 : if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
591 : return false;
592 : }
593 :
594 : number_of_valid_maps++;
595 340955 : if (number_of_valid_maps == 1) {
596 125765 : ConfigureVectorState(name, receiver_map(), handler);
597 : } else {
598 222462 : if (is_keyed() && nexus()->FindFirstName() != *name) return false;
599 215185 : if (handler_to_overwrite >= 0) {
600 3018 : handlers[handler_to_overwrite] = handler;
601 1509 : if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
602 1127 : maps[handler_to_overwrite] = map;
603 : }
604 : } else {
605 213676 : maps.push_back(map);
606 213679 : handlers.push_back(handler);
607 : }
608 :
609 215190 : ConfigureVectorState(name, maps, &handlers);
610 : }
611 :
612 : return true;
613 : }
614 :
615 0 : void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
616 : Handle<Name> name) {
617 : DCHECK(IsHandler(*handler));
618 1157247 : ConfigureVectorState(name, receiver_map(), handler);
619 0 : }
620 :
621 :
622 12845 : void IC::CopyICToMegamorphicCache(Handle<Name> name) {
623 : MapHandles maps;
624 : MaybeObjectHandles handlers;
625 12845 : TargetMaps(&maps);
626 38535 : if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return;
627 113152 : for (int i = 0; i < static_cast<int>(maps.size()); i++) {
628 100621 : UpdateMegamorphicCache(maps.at(i), name, handlers.at(i));
629 : }
630 : }
631 :
632 406334 : bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) {
633 391224 : if (source_map.is_null()) return true;
634 391227 : if (target_map.is_null()) return false;
635 391231 : if (source_map->is_abandoned_prototype_map()) return false;
636 : ElementsKind target_elements_kind = target_map->elements_kind();
637 : bool more_general_transition = IsMoreGeneralElementsKindTransition(
638 779574 : source_map->elements_kind(), target_elements_kind);
639 : Map transitioned_map;
640 389785 : if (more_general_transition) {
641 : MapHandles map_list;
642 45330 : map_list.push_back(handle(target_map, isolate_));
643 : transitioned_map =
644 15110 : source_map->FindElementsKindTransitionedMap(isolate(), map_list);
645 : }
646 389784 : return transitioned_map == target_map;
647 : }
648 :
649 0 : void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
650 1262859 : PatchCache(name, MaybeObjectHandle(handler));
651 0 : }
652 :
653 2162844 : void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
654 : DCHECK(IsHandler(*handler));
655 : // Currently only load and store ICs support non-code handlers.
656 : DCHECK(IsAnyLoad() || IsAnyStore());
657 2153630 : switch (state()) {
658 : case NO_FEEDBACK:
659 : break;
660 : case UNINITIALIZED:
661 : case PREMONOMORPHIC:
662 : UpdateMonomorphicIC(handler, name);
663 : break;
664 : case RECOMPUTE_HANDLER:
665 : case MONOMORPHIC:
666 240027 : if (IsGlobalIC()) {
667 : UpdateMonomorphicIC(handler, name);
668 : break;
669 : }
670 : V8_FALLTHROUGH;
671 : case POLYMORPHIC:
672 363004 : if (UpdatePolymorphicIC(name, handler)) break;
673 31273 : if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
674 12845 : CopyICToMegamorphicCache(name);
675 : }
676 22059 : ConfigureVectorState(MEGAMORPHIC, name);
677 : V8_FALLTHROUGH;
678 : case MEGAMORPHIC:
679 655449 : UpdateMegamorphicCache(receiver_map(), name, handler);
680 : // Indicate that we've handled this case.
681 655449 : vector_set_ = true;
682 655449 : break;
683 : case GENERIC:
684 0 : UNREACHABLE();
685 : break;
686 : }
687 2153672 : }
688 :
689 8094643 : void LoadIC::UpdateCaches(LookupIterator* lookup) {
690 8268941 : if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
691 : // This is the first time we execute this inline cache. Set the target to
692 : // the pre monomorphic stub to delay setting the monomorphic state.
693 99012 : TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
694 99004 : ConfigureVectorState(receiver_map());
695 99004 : TraceIC("LoadIC", lookup->name());
696 99004 : return;
697 : }
698 :
699 : Handle<Object> code;
700 3085127 : if (lookup->state() == LookupIterator::ACCESS_CHECK) {
701 35 : code = slow_stub();
702 3085092 : } else if (!lookup->IsFound()) {
703 74972 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
704 74972 : Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
705 : code = LoadHandler::LoadFullChain(
706 : isolate(), receiver_map(),
707 74971 : MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
708 : } else {
709 3010120 : if (IsLoadGlobalIC()) {
710 1825385 : if (lookup->TryLookupCachedProperty()) {
711 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
712 : }
713 3649084 : if (lookup->state() == LookupIterator::DATA &&
714 : lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
715 : DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
716 : // Now update the cell in the feedback vector.
717 1823269 : nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
718 1823272 : TraceIC("LoadGlobalIC", lookup->name());
719 1823271 : return;
720 : }
721 : }
722 1186854 : code = ComputeHandler(lookup);
723 : }
724 :
725 1261851 : PatchCache(lookup->name(), code);
726 1261887 : TraceIC("LoadIC", lookup->name());
727 : }
728 :
729 705759 : StubCache* IC::stub_cache() {
730 705759 : if (IsAnyLoad()) {
731 319721 : return isolate()->load_stub_cache();
732 : } else {
733 : DCHECK(IsAnyStore());
734 386038 : return isolate()->store_stub_cache();
735 : }
736 : }
737 :
738 705760 : void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
739 : const MaybeObjectHandle& handler) {
740 1411519 : stub_cache()->Set(*name, *map, *handler);
741 705760 : }
742 :
743 0 : void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
744 : DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
745 0 : if (V8_LIKELY(!FLAG_runtime_stats)) return;
746 0 : if (IsAnyLoad()) {
747 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
748 : } else {
749 : DCHECK(IsAnyStore());
750 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
751 : }
752 : }
753 :
754 3517006 : Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
755 : Handle<Object> receiver = lookup->GetReceiver();
756 3059823 : ReadOnlyRoots roots(isolate());
757 2411344 : if (receiver->IsString() && *lookup->name() == roots.length_string()) {
758 9682 : TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
759 9682 : return BUILTIN_CODE(isolate(), LoadIC_StringLength);
760 : }
761 :
762 2356422 : if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) {
763 81 : TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
764 81 : return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
765 : }
766 :
767 : // Use specialized code for getting prototype of functions.
768 3612629 : if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() &&
769 1190377 : !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
770 : Handle<Code> stub;
771 12036 : TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
772 12036 : return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
773 : }
774 :
775 1165072 : Handle<Map> map = receiver_map();
776 : Handle<JSObject> holder;
777 : bool receiver_is_holder;
778 1165072 : if (lookup->state() != LookupIterator::JSPROXY) {
779 : holder = lookup->GetHolder<JSObject>();
780 : receiver_is_holder = receiver.is_identical_to(holder);
781 : }
782 :
783 1165069 : switch (lookup->state()) {
784 : case LookupIterator::INTERCEPTOR: {
785 857 : Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
786 :
787 857 : if (holder->GetNamedInterceptor()->non_masking()) {
788 : MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
789 72 : if (!receiver_is_holder || IsLoadGlobalIC()) {
790 24 : holder_ref = MaybeObjectHandle::Weak(holder);
791 : }
792 48 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
793 : return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
794 48 : smi_handler);
795 : }
796 :
797 809 : if (receiver_is_holder) {
798 : DCHECK(map->has_named_interceptor());
799 636 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
800 636 : return smi_handler;
801 : }
802 :
803 173 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
804 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
805 173 : smi_handler);
806 : }
807 :
808 : case LookupIterator::ACCESSOR: {
809 : // Use simple field loads for some well-known callback properties.
810 : // The method will only return true for absolute truths based on the
811 : // receiver maps.
812 : FieldIndex index;
813 155216 : if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
814 : &index)) {
815 59978 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
816 59978 : return LoadHandler::LoadField(isolate(), index);
817 : }
818 190476 : if (holder->IsJSModuleNamespace()) {
819 : Handle<ObjectHashTable> exports(
820 59547 : Handle<JSModuleNamespace>::cast(holder)->module()->exports(),
821 39698 : isolate());
822 39698 : int entry = exports->FindEntry(roots, lookup->name(),
823 59547 : Smi::ToInt(lookup->name()->GetHash()));
824 : // We found the accessor, so the entry must exist.
825 : DCHECK_NE(entry, ObjectHashTable::kNotFound);
826 : int index = ObjectHashTable::EntryToValueIndex(entry);
827 19849 : return LoadHandler::LoadModuleExport(isolate(), index);
828 : }
829 :
830 75389 : Handle<Object> accessors = lookup->GetAccessors();
831 150778 : if (accessors->IsAccessorPair()) {
832 69247 : if (lookup->TryLookupCachedProperty()) {
833 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
834 19 : return ComputeHandler(lookup);
835 : }
836 :
837 : Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
838 138456 : isolate());
839 139512 : if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
840 270 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
841 270 : return slow_stub();
842 : }
843 :
844 207132 : if (getter->IsFunctionTemplateInfo() &&
845 69216 : FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) {
846 : // Do not install an IC if the api function has a breakpoint.
847 10 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
848 10 : return slow_stub();
849 : }
850 :
851 : Handle<Smi> smi_handler;
852 :
853 68948 : CallOptimization call_optimization(isolate(), getter);
854 68948 : if (call_optimization.is_simple_api_call()) {
855 12000 : if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
856 11894 : !holder->HasFastProperties()) {
857 69 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
858 69 : return slow_stub();
859 : }
860 :
861 : CallOptimization::HolderLookup holder_lookup;
862 3931 : call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
863 :
864 : smi_handler = LoadHandler::LoadApiGetter(
865 7862 : isolate(), holder_lookup == CallOptimization::kHolderIsReceiver);
866 :
867 : Handle<Context> context(
868 3931 : call_optimization.GetAccessorContext(holder->map()), isolate());
869 :
870 3935 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
871 : return LoadHandler::LoadFromPrototype(
872 : isolate(), map, holder, smi_handler,
873 : MaybeObjectHandle::Weak(call_optimization.api_call_info()),
874 3931 : MaybeObjectHandle::Weak(context));
875 : }
876 :
877 64948 : if (holder->HasFastProperties()) {
878 : smi_handler =
879 119468 : LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
880 :
881 59734 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
882 59734 : if (receiver_is_holder) return smi_handler;
883 44702 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
884 10428 : } else if (holder->IsJSGlobalObject()) {
885 937 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
886 937 : smi_handler = LoadHandler::LoadGlobal(isolate());
887 : return LoadHandler::LoadFromPrototype(
888 : isolate(), map, holder, smi_handler,
889 1874 : MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
890 : } else {
891 4277 : smi_handler = LoadHandler::LoadNormal(isolate());
892 :
893 4277 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
894 4277 : if (receiver_is_holder) return smi_handler;
895 63 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
896 : }
897 :
898 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
899 44765 : smi_handler);
900 : }
901 :
902 6142 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
903 :
904 18426 : if (v8::ToCData<Address>(info->getter()) == kNullAddress ||
905 12272 : !AccessorInfo::IsCompatibleReceiverMap(info, map) ||
906 23968 : !holder->HasFastProperties() ||
907 6234 : (info->is_sloppy() && !receiver->IsJSReceiver())) {
908 588 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
909 588 : return slow_stub();
910 : }
911 :
912 : Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
913 11108 : isolate(), lookup->GetAccessorIndex());
914 5558 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
915 5554 : if (receiver_is_holder) return smi_handler;
916 303 : TRACE_HANDLER_STATS(isolate(),
917 : LoadIC_LoadNativeDataPropertyFromPrototypeDH);
918 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
919 303 : smi_handler);
920 : }
921 :
922 : case LookupIterator::DATA: {
923 : DCHECK_EQ(kData, lookup->property_details().kind());
924 : Handle<Smi> smi_handler;
925 1003700 : if (lookup->is_dictionary_holder()) {
926 38546 : if (holder->IsJSGlobalObject()) {
927 : // TODO(verwaest): Also supporting the global object as receiver is a
928 : // workaround for code that leaks the global object.
929 11721 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
930 11721 : smi_handler = LoadHandler::LoadGlobal(isolate());
931 : return LoadHandler::LoadFromPrototype(
932 : isolate(), map, holder, smi_handler,
933 23442 : MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
934 : }
935 :
936 7552 : smi_handler = LoadHandler::LoadNormal(isolate());
937 7552 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
938 7552 : if (receiver_is_holder) return smi_handler;
939 3715 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
940 :
941 984433 : } else if (lookup->property_details().location() == kField) {
942 563152 : FieldIndex field = lookup->GetFieldIndex();
943 563154 : smi_handler = LoadHandler::LoadField(isolate(), field);
944 563152 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
945 563151 : if (receiver_is_holder) return smi_handler;
946 16665 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
947 : } else {
948 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
949 : smi_handler =
950 842553 : LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
951 421278 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
952 421277 : if (receiver_is_holder) return smi_handler;
953 286758 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
954 : }
955 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
956 307138 : smi_handler);
957 : }
958 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
959 45 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
960 45 : return LoadHandler::LoadNonExistent(isolate());
961 : case LookupIterator::JSPROXY: {
962 : Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
963 : bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy);
964 5251 : Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
965 5251 : if (receiver_is_holder_proxy) {
966 4476 : return smi_handler;
967 : }
968 : return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
969 775 : smi_handler);
970 : }
971 : case LookupIterator::ACCESS_CHECK:
972 : case LookupIterator::NOT_FOUND:
973 : case LookupIterator::TRANSITION:
974 0 : UNREACHABLE();
975 : }
976 :
977 0 : return Handle<Code>::null();
978 : }
979 :
980 375579 : static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
981 : // This helper implements a few common fast cases for converting
982 : // non-smi keys of keyed loads/stores to a smi or a string.
983 751158 : if (key->IsHeapNumber()) {
984 3908 : double value = Handle<HeapNumber>::cast(key)->value();
985 1954 : if (std::isnan(value)) {
986 : key = isolate->factory()->NaN_string();
987 : } else {
988 : // Check bounds first to avoid undefined behavior in the conversion
989 : // to int.
990 1693 : if (value <= Smi::kMaxValue && value >= Smi::kMinValue) {
991 : int int_value = FastD2I(value);
992 779 : if (value == int_value) {
993 : key = handle(Smi::FromInt(int_value), isolate);
994 : }
995 : }
996 : }
997 747250 : } else if (key->IsString()) {
998 44533 : key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
999 : }
1000 375579 : return key;
1001 : }
1002 :
1003 520 : bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) {
1004 520 : const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map);
1005 520 : if (handler.is_null()) return false;
1006 520 : return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD;
1007 : }
1008 :
1009 137110 : void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
1010 : KeyedAccessLoadMode load_mode) {
1011 155745 : Handle<Map> receiver_map(receiver->map(), isolate());
1012 : DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
1013 : MapHandles target_receiver_maps;
1014 137110 : TargetMaps(&target_receiver_maps);
1015 :
1016 137110 : if (target_receiver_maps.empty()) {
1017 118412 : Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1018 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1019 : }
1020 :
1021 79375 : for (Handle<Map> map : target_receiver_maps) {
1022 30370 : if (map.is_null()) continue;
1023 30370 : if (map->instance_type() == JS_VALUE_TYPE) {
1024 : set_slow_stub_reason("JSValue");
1025 : return;
1026 : }
1027 30361 : if (map->instance_type() == JS_PROXY_TYPE) {
1028 : set_slow_stub_reason("JSProxy");
1029 : return;
1030 : }
1031 : }
1032 :
1033 : // The first time a receiver is seen that is a transitioned version of the
1034 : // previous monomorphic receiver type, assume the new ElementsKind is the
1035 : // monomorphic type. This benefits global arrays that only transition
1036 : // once, and all call sites accessing them are faster if they remain
1037 : // monomorphic. If this optimistic assumption is not true, the IC will
1038 : // miss again and it will become polymorphic and support both the
1039 : // untransitioned and transitioned maps.
1040 55172 : if (state() == MONOMORPHIC && !receiver->IsString() &&
1041 61384 : !receiver->IsJSProxy() &&
1042 : IsMoreGeneralElementsKindTransition(
1043 : target_receiver_maps.at(0)->elements_kind(),
1044 54806 : Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1045 2578 : Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1046 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1047 : }
1048 :
1049 : DCHECK(state() != GENERIC);
1050 :
1051 : // Determine the list of receiver maps that this call site has seen,
1052 : // adding the map that was just encountered.
1053 16057 : if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1054 : // If the {receiver_map} previously had a handler that didn't handle
1055 : // out-of-bounds access, but can generally handle it, we can just go
1056 : // on and update the handler appropriately below.
1057 2971 : if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS ||
1058 520 : !CanChangeToAllowOutOfBounds(receiver_map)) {
1059 : // If the miss wasn't due to an unseen map, a polymorphic stub
1060 : // won't help, use the generic stub.
1061 : set_slow_stub_reason("same map added twice");
1062 : return;
1063 : }
1064 : }
1065 :
1066 : // If the maximum number of receiver maps has been exceeded, use the generic
1067 : // version of the IC.
1068 28226 : if (target_receiver_maps.size() > kMaxKeyedPolymorphism) {
1069 : set_slow_stub_reason("max polymorph exceeded");
1070 : return;
1071 : }
1072 :
1073 : MaybeObjectHandles handlers;
1074 12408 : handlers.reserve(target_receiver_maps.size());
1075 12408 : LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1076 : DCHECK_LE(1, target_receiver_maps.size());
1077 24816 : if (target_receiver_maps.size() == 1) {
1078 1018 : ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1079 : } else {
1080 11899 : ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1081 : }
1082 : }
1083 :
1084 151313 : Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
1085 : KeyedAccessLoadMode load_mode) {
1086 151421 : if (receiver_map->has_indexed_interceptor() &&
1087 151421 : !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
1088 466654 : isolate()) &&
1089 151397 : !receiver_map->GetIndexedInterceptor()->non_masking()) {
1090 : // TODO(jgruber): Update counter name.
1091 84 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1092 84 : return BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
1093 : }
1094 : InstanceType instance_type = receiver_map->instance_type();
1095 151230 : if (instance_type < FIRST_NONSTRING_TYPE) {
1096 1227 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1097 1227 : return LoadHandler::LoadIndexedString(isolate(), load_mode);
1098 : }
1099 150003 : if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1100 0 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1101 0 : return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
1102 : }
1103 150003 : if (instance_type == JS_PROXY_TYPE) {
1104 144 : return LoadHandler::LoadProxy(isolate());
1105 : }
1106 :
1107 : ElementsKind elements_kind = receiver_map->elements_kind();
1108 149858 : if (IsSloppyArgumentsElementsKind(elements_kind)) {
1109 : // TODO(jgruber): Update counter name.
1110 1754 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1111 1754 : return BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
1112 : }
1113 148104 : bool is_js_array = instance_type == JS_ARRAY_TYPE;
1114 148104 : if (elements_kind == DICTIONARY_ELEMENTS) {
1115 4306 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1116 : return LoadHandler::LoadElement(isolate(), elements_kind, false,
1117 8612 : is_js_array, load_mode);
1118 : }
1119 : DCHECK(IsFastElementsKind(elements_kind) ||
1120 : IsFixedTypedArrayElementsKind(elements_kind));
1121 : // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind).
1122 : bool convert_hole_to_undefined =
1123 156321 : is_js_array && elements_kind == HOLEY_ELEMENTS &&
1124 156321 : *receiver_map ==
1125 168844 : isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind);
1126 143798 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1127 : return LoadHandler::LoadElement(isolate(), elements_kind,
1128 : convert_hole_to_undefined, is_js_array,
1129 287596 : load_mode);
1130 : }
1131 :
1132 12408 : void KeyedLoadIC::LoadElementPolymorphicHandlers(
1133 : MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1134 : KeyedAccessLoadMode load_mode) {
1135 : // Filter out deprecated maps to ensure their instances get migrated.
1136 : receiver_maps->erase(
1137 : std::remove_if(
1138 : receiver_maps->begin(), receiver_maps->end(),
1139 60716 : [](const Handle<Map>& map) { return map->is_deprecated(); }),
1140 12408 : receiver_maps->end());
1141 :
1142 55138 : for (Handle<Map> receiver_map : *receiver_maps) {
1143 : // Mark all stable receiver maps that have elements kind transition map
1144 : // among receiver_maps as unstable because the optimizing compilers may
1145 : // generate an elements kind transition for this kind of receivers.
1146 30323 : if (receiver_map->is_stable()) {
1147 : Map tmap = receiver_map->FindElementsKindTransitionedMap(isolate(),
1148 37675 : *receiver_maps);
1149 18828 : if (!tmap.is_null()) {
1150 18 : receiver_map->NotifyLeafMapLayoutChange(isolate());
1151 : }
1152 : }
1153 : handlers->push_back(
1154 60647 : MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode)));
1155 : }
1156 12408 : }
1157 :
1158 : namespace {
1159 :
1160 146227 : bool ConvertKeyToIndex(Handle<Object> receiver, Handle<Object> key,
1161 : uint32_t* index, InlineCacheState state) {
1162 146227 : if (!FLAG_use_ic || state == NO_FEEDBACK) return false;
1163 584685 : if (receiver->IsAccessCheckNeeded() || receiver->IsJSValue()) return false;
1164 :
1165 : // For regular JSReceiver or String receivers, the {key} must be a positive
1166 : // array index.
1167 297542 : if (receiver->IsJSReceiver() || receiver->IsString()) {
1168 287676 : if (key->ToArrayIndex(index)) return true;
1169 : }
1170 : // For JSTypedArray receivers, we can also support negative keys, which we
1171 : // just map into the [2**31, 2**32 - 1] range via a bit_cast. This is valid
1172 : // because JSTypedArray::length is always a Smi, so such keys will always
1173 : // be detected as OOB.
1174 17440 : if (receiver->IsJSTypedArray()) {
1175 : int32_t signed_index;
1176 369 : if (key->ToInt32(&signed_index)) {
1177 198 : *index = bit_cast<uint32_t>(signed_index);
1178 198 : return true;
1179 : }
1180 : }
1181 : return false;
1182 : }
1183 :
1184 449688 : bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) {
1185 449688 : uint32_t length = 0;
1186 899380 : if (receiver->IsJSArray()) {
1187 781013 : JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1188 118366 : } else if (receiver->IsString()) {
1189 1165 : length = String::cast(*receiver)->length();
1190 116036 : } else if (receiver->IsJSObject()) {
1191 115658 : length = JSObject::cast(*receiver)->elements()->length();
1192 : } else {
1193 : return false;
1194 : }
1195 449499 : return index >= length;
1196 : }
1197 :
1198 137109 : KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
1199 : uint32_t index) {
1200 137109 : if (IsOutOfBoundsAccess(receiver, index)) {
1201 9270 : if (receiver->IsJSTypedArray()) {
1202 : // For JSTypedArray we never lookup elements in the prototype chain.
1203 : return LOAD_IGNORE_OUT_OF_BOUNDS;
1204 : }
1205 :
1206 : // For other {receiver}s we need to check the "no elements" protector.
1207 3694 : if (isolate->IsNoElementsProtectorIntact()) {
1208 6902 : if (receiver->IsString()) {
1209 : // ToObject(receiver) will have the initial String.prototype.
1210 : return LOAD_IGNORE_OUT_OF_BOUNDS;
1211 : }
1212 6616 : if (receiver->IsJSObject()) {
1213 : // For other JSObjects (including JSArrays) we can only continue if
1214 : // the {receiver}s prototype is either the initial Object.prototype
1215 : // or the initial Array.prototype, which are both guarded by the
1216 : // "no elements" protector checked above.
1217 : Handle<Object> receiver_prototype(
1218 : JSObject::cast(*receiver)->map()->prototype(), isolate);
1219 3308 : if (isolate->IsInAnyContext(*receiver_prototype,
1220 5485 : Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1221 : isolate->IsInAnyContext(*receiver_prototype,
1222 2177 : Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
1223 : return LOAD_IGNORE_OUT_OF_BOUNDS;
1224 : }
1225 : }
1226 : }
1227 : }
1228 : return STANDARD_LOAD;
1229 : }
1230 :
1231 : } // namespace
1232 :
1233 215089 : MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1234 : Handle<Object> key) {
1235 215089 : if (MigrateDeprecated(object)) {
1236 : Handle<Object> result;
1237 781902 : ASSIGN_RETURN_ON_EXCEPTION(
1238 : isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1239 : Object);
1240 139 : return result;
1241 : }
1242 :
1243 : Handle<Object> load_handle;
1244 :
1245 : // Check for non-string values that can be converted into an
1246 : // internalized string directly or is representable as a smi.
1247 214950 : key = TryConvertKey(key, isolate());
1248 :
1249 : uint32_t index;
1250 466121 : if ((key->IsInternalizedString() &&
1251 649330 : !String::cast(*key)->AsArrayIndex(&index)) ||
1252 398159 : key->IsSymbol()) {
1253 137446 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1254 : LoadIC::Load(object, Handle<Name>::cast(key)),
1255 : Object);
1256 146227 : } else if (ConvertKeyToIndex(object, key, &index, state())) {
1257 274218 : KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index);
1258 137109 : UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode);
1259 137110 : if (is_vector_set()) {
1260 133398 : TraceIC("LoadIC", key);
1261 : }
1262 : }
1263 :
1264 214339 : if (vector_needs_update()) {
1265 12857 : ConfigureVectorState(MEGAMORPHIC, key);
1266 12857 : TraceIC("LoadIC", key);
1267 : }
1268 :
1269 214339 : if (!load_handle.is_null()) return load_handle;
1270 :
1271 : Handle<Object> result;
1272 292456 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1273 : Runtime::GetObjectProperty(isolate(), object, key),
1274 : Object);
1275 145925 : return result;
1276 : }
1277 :
1278 7484798 : bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1279 : StoreOrigin store_origin) {
1280 : // Disable ICs for non-JSObjects for now.
1281 : Handle<Object> object = it->GetReceiver();
1282 4988847 : if (object->IsJSProxy()) return true;
1283 4988550 : if (!object->IsJSObject()) return false;
1284 2493938 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1285 : DCHECK(!receiver->map()->is_deprecated());
1286 :
1287 2493937 : if (it->state() != LookupIterator::TRANSITION) {
1288 2498942 : for (; it->IsFound(); it->Next()) {
1289 2025964 : switch (it->state()) {
1290 : case LookupIterator::NOT_FOUND:
1291 : case LookupIterator::TRANSITION:
1292 0 : UNREACHABLE();
1293 : case LookupIterator::JSPROXY:
1294 : return true;
1295 : case LookupIterator::INTERCEPTOR: {
1296 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1297 283 : InterceptorInfo info = holder->GetNamedInterceptor();
1298 283 : if (it->HolderIsReceiverOrHiddenPrototype()) {
1299 741 : return !info->non_masking() && receiver.is_identical_to(holder) &&
1300 1125 : !info->setter()->IsUndefined(isolate());
1301 108 : } else if (!info->getter()->IsUndefined(isolate()) ||
1302 36 : !info->query()->IsUndefined(isolate())) {
1303 : return false;
1304 : }
1305 0 : break;
1306 : }
1307 : case LookupIterator::ACCESS_CHECK:
1308 5036 : if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1309 : break;
1310 : case LookupIterator::ACCESSOR:
1311 228896 : return !it->IsReadOnly();
1312 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1313 90 : return false;
1314 : case LookupIterator::DATA: {
1315 1793970 : if (it->IsReadOnly()) return false;
1316 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1317 1780817 : if (receiver.is_identical_to(holder)) {
1318 1774913 : it->PrepareForDataProperty(value);
1319 : // The previous receiver map might just have been deprecated,
1320 : // so reload it.
1321 1774917 : update_receiver_map(receiver);
1322 1774919 : return true;
1323 : }
1324 :
1325 : // Receiver != holder.
1326 11808 : if (receiver->IsJSGlobalProxy()) {
1327 631 : PrototypeIterator iter(isolate(), receiver);
1328 : return it->GetHolder<Object>().is_identical_to(
1329 : PrototypeIterator::GetCurrent(iter));
1330 : }
1331 :
1332 5273 : if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1333 :
1334 5273 : if (it->ExtendingNonExtensible(receiver)) return false;
1335 : it->PrepareTransitionToDataProperty(receiver, value, NONE,
1336 5273 : store_origin);
1337 5273 : return it->IsCacheableTransition();
1338 : }
1339 : }
1340 : }
1341 : }
1342 :
1343 470475 : receiver = it->GetStoreTarget<JSObject>();
1344 470475 : if (it->ExtendingNonExtensible(receiver)) return false;
1345 470403 : it->PrepareTransitionToDataProperty(receiver, value, NONE, store_origin);
1346 470402 : return it->IsCacheableTransition();
1347 : }
1348 :
1349 1645920 : MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
1350 : Handle<Object> value) {
1351 : DCHECK(name->IsString());
1352 :
1353 : // Look up in script context table.
1354 1645920 : Handle<String> str_name = Handle<String>::cast(name);
1355 3292025 : Handle<JSGlobalObject> global = isolate()->global_object();
1356 : Handle<ScriptContextTable> script_contexts(
1357 3291840 : global->native_context()->script_context_table(), isolate());
1358 :
1359 : ScriptContextTable::LookupResult lookup_result;
1360 1645920 : if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
1361 : &lookup_result)) {
1362 : Handle<Context> script_context = ScriptContextTable::GetContext(
1363 130 : isolate(), script_contexts, lookup_result.context_index);
1364 65 : if (lookup_result.mode == VariableMode::kConst) {
1365 20 : return TypeError(MessageTemplate::kConstAssign, global, name);
1366 : }
1367 :
1368 : Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
1369 135 : isolate());
1370 :
1371 90 : if (previous_value->IsTheHole(isolate())) {
1372 : // Do not install stubs and stay pre-monomorphic for
1373 : // uninitialized accesses.
1374 15 : return ReferenceError(name);
1375 : }
1376 :
1377 30 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1378 30 : if (use_ic) {
1379 30 : if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
1380 30 : lookup_result.slot_index)) {
1381 30 : TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1382 : } else {
1383 : // Given combination of indices can't be encoded, so use slow stub.
1384 0 : TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1385 0 : PatchCache(name, slow_stub());
1386 : }
1387 30 : TraceIC("StoreGlobalIC", name);
1388 : }
1389 :
1390 90 : script_context->set(lookup_result.slot_index, *value);
1391 30 : return value;
1392 : }
1393 :
1394 1645855 : return StoreIC::Store(global, name, value);
1395 : }
1396 :
1397 2954317 : MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1398 : Handle<Object> value,
1399 2954134 : StoreOrigin store_origin) {
1400 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
1401 : // might deprecate the current map again, if value does not fit.
1402 2954317 : if (MigrateDeprecated(object)) {
1403 : Handle<Object> result;
1404 12694933 : ASSIGN_RETURN_ON_EXCEPTION(
1405 : isolate(), result,
1406 : Object::SetProperty(isolate(), object, name, value, language_mode()),
1407 : Object);
1408 54 : return result;
1409 : }
1410 :
1411 2954266 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1412 : // If the object is undefined or null it's illegal to try to set any
1413 : // properties on it; throw a TypeError in that case.
1414 5908535 : if (object->IsNullOrUndefined(isolate())) {
1415 90 : if (use_ic && state() != PREMONOMORPHIC) {
1416 : // Ensure the IC state progresses.
1417 45 : TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1418 45 : update_receiver_map(object);
1419 45 : PatchCache(name, slow_stub());
1420 45 : TraceIC("StoreIC", name);
1421 : }
1422 45 : return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1423 : }
1424 :
1425 2954228 : if (state() != UNINITIALIZED) {
1426 877627 : JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1427 : }
1428 2954231 : LookupIterator it(isolate(), object, name);
1429 :
1430 2954227 : if (name->IsPrivate()) {
1431 1920 : if (name->IsPrivateName() && !it.IsFound()) {
1432 : Handle<String> name_string(String::cast(Symbol::cast(*name)->name()),
1433 324 : isolate());
1434 : return TypeError(MessageTemplate::kInvalidPrivateFieldWrite, object,
1435 162 : name_string);
1436 : }
1437 :
1438 : // IC handling of private fields/symbols stores on JSProxy is not
1439 : // supported.
1440 3516 : if (object->IsJSProxy()) {
1441 : use_ic = false;
1442 : }
1443 : }
1444 2954066 : if (use_ic) UpdateCaches(&it, value, store_origin);
1445 :
1446 2954080 : MAYBE_RETURN_NULL(
1447 : Object::SetProperty(&it, value, language_mode(), store_origin));
1448 2940242 : return value;
1449 : }
1450 :
1451 4598874 : void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1452 : StoreOrigin store_origin) {
1453 7505341 : if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
1454 : // This is the first time we execute this inline cache. Transition
1455 : // to premonomorphic state to delay setting the monomorphic state.
1456 459245 : TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1457 459245 : ConfigureVectorState(receiver_map());
1458 459259 : TraceIC("StoreIC", lookup->name());
1459 2522156 : return;
1460 : }
1461 :
1462 : MaybeObjectHandle handler;
1463 2494423 : if (LookupForWrite(lookup, value, store_origin)) {
1464 2475581 : if (IsStoreGlobalIC()) {
1465 3248846 : if (lookup->state() == LookupIterator::DATA &&
1466 : lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1467 : DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1468 : // Now update the cell in the feedback vector.
1469 1603640 : nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1470 1603640 : TraceIC("StoreGlobalIC", lookup->name());
1471 1603640 : return;
1472 : }
1473 : }
1474 871941 : handler = ComputeHandler(lookup);
1475 : } else {
1476 : set_slow_stub_reason("LookupForWrite said 'false'");
1477 : // TODO(marja): change slow_stub to return MaybeObjectHandle.
1478 18841 : handler = MaybeObjectHandle(slow_stub());
1479 : }
1480 :
1481 890778 : PatchCache(lookup->name(), handler);
1482 890787 : TraceIC("StoreIC", lookup->name());
1483 : }
1484 :
1485 871937 : MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
1486 871937 : switch (lookup->state()) {
1487 : case LookupIterator::TRANSITION: {
1488 470738 : Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1489 941478 : if (store_target->IsJSGlobalObject()) {
1490 1339279 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1491 :
1492 84284 : if (receiver_map()->IsJSGlobalObject()) {
1493 : DCHECK(IsStoreGlobalIC());
1494 : #ifdef DEBUG
1495 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1496 : DCHECK_EQ(*lookup->GetReceiver(), *holder);
1497 : DCHECK_EQ(*store_target, *holder);
1498 : #endif
1499 0 : return StoreHandler::StoreGlobal(lookup->transition_cell());
1500 : }
1501 :
1502 42142 : Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
1503 : Handle<Object> handler = StoreHandler::StoreThroughPrototype(
1504 : isolate(), receiver_map(), store_target, smi_handler,
1505 42142 : MaybeObjectHandle::Weak(lookup->transition_cell()));
1506 42142 : return MaybeObjectHandle(handler);
1507 : }
1508 : // Dictionary-to-fast transitions are not expected and not supported.
1509 : DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
1510 : !receiver_map()->is_dictionary_map());
1511 :
1512 : DCHECK(lookup->IsCacheableTransition());
1513 :
1514 428596 : return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
1515 : }
1516 :
1517 : case LookupIterator::INTERCEPTOR: {
1518 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1519 : USE(holder);
1520 :
1521 : DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1522 : // TODO(jgruber): Update counter name.
1523 170 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1524 170 : return MaybeObjectHandle(BUILTIN_CODE(isolate(), StoreInterceptorIC));
1525 : }
1526 :
1527 : case LookupIterator::ACCESSOR: {
1528 : // This is currently guaranteed by checks in StoreIC::Store.
1529 228806 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1530 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1531 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1532 :
1533 228806 : if (!holder->HasFastProperties()) {
1534 : set_slow_stub_reason("accessor on slow map");
1535 498 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1536 498 : return MaybeObjectHandle(slow_stub());
1537 : }
1538 228308 : Handle<Object> accessors = lookup->GetAccessors();
1539 456616 : if (accessors->IsAccessorInfo()) {
1540 91261 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1541 91261 : if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
1542 : set_slow_stub_reason("setter == kNullAddress");
1543 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1544 0 : return MaybeObjectHandle(slow_stub());
1545 : }
1546 182428 : if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1547 91167 : !lookup->HolderIsReceiverOrHiddenPrototype()) {
1548 : set_slow_stub_reason("special data property in prototype chain");
1549 27 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1550 27 : return MaybeObjectHandle(slow_stub());
1551 : }
1552 91234 : if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) {
1553 : set_slow_stub_reason("incompatible receiver type");
1554 12 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1555 12 : return MaybeObjectHandle(slow_stub());
1556 : }
1557 :
1558 : Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
1559 182444 : isolate(), lookup->GetAccessorIndex());
1560 91222 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
1561 91222 : if (receiver.is_identical_to(holder)) {
1562 91184 : return MaybeObjectHandle(smi_handler);
1563 : }
1564 38 : TRACE_HANDLER_STATS(isolate(),
1565 : StoreIC_StoreNativeDataPropertyOnPrototypeDH);
1566 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1567 38 : isolate(), receiver_map(), holder, smi_handler));
1568 :
1569 274094 : } else if (accessors->IsAccessorPair()) {
1570 274094 : Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1571 274094 : isolate());
1572 292388 : if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1573 : set_slow_stub_reason("setter not a function");
1574 8901 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1575 8901 : return MaybeObjectHandle(slow_stub());
1576 : }
1577 :
1578 384684 : if (setter->IsFunctionTemplateInfo() &&
1579 128392 : FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) {
1580 : // Do not install an IC if the api function has a breakpoint.
1581 10 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1582 10 : return MaybeObjectHandle(slow_stub());
1583 : }
1584 :
1585 128136 : CallOptimization call_optimization(isolate(), setter);
1586 128136 : if (call_optimization.is_simple_api_call()) {
1587 408 : if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1588 : CallOptimization::HolderLookup holder_lookup;
1589 : call_optimization.LookupHolderOfExpectedType(receiver_map(),
1590 360 : &holder_lookup);
1591 :
1592 : Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
1593 : isolate(),
1594 720 : holder_lookup == CallOptimization::kHolderIsReceiver);
1595 :
1596 : Handle<Context> context(
1597 360 : call_optimization.GetAccessorContext(holder->map()), isolate());
1598 360 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
1599 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1600 : isolate(), receiver_map(), holder, smi_handler,
1601 : MaybeObjectHandle::Weak(call_optimization.api_call_info()),
1602 360 : MaybeObjectHandle::Weak(context)));
1603 : }
1604 : set_slow_stub_reason("incompatible receiver");
1605 48 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1606 48 : return MaybeObjectHandle(slow_stub());
1607 255456 : } else if (setter->IsFunctionTemplateInfo()) {
1608 : set_slow_stub_reason("setter non-simple template");
1609 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1610 0 : return MaybeObjectHandle(slow_stub());
1611 : }
1612 :
1613 : Handle<Smi> smi_handler =
1614 255456 : StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex());
1615 :
1616 127728 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
1617 127728 : if (receiver.is_identical_to(holder)) {
1618 491 : return MaybeObjectHandle(smi_handler);
1619 : }
1620 127237 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
1621 :
1622 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1623 127237 : isolate(), receiver_map(), holder, smi_handler));
1624 : }
1625 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1626 0 : return MaybeObjectHandle(slow_stub());
1627 : }
1628 :
1629 : case LookupIterator::DATA: {
1630 : // This is currently guaranteed by checks in StoreIC::Store.
1631 171863 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1632 : USE(receiver);
1633 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1634 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1635 :
1636 : DCHECK_EQ(kData, lookup->property_details().kind());
1637 171863 : if (lookup->is_dictionary_holder()) {
1638 12274 : if (holder->IsJSGlobalObject()) {
1639 590 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
1640 : return MaybeObjectHandle(
1641 590 : StoreHandler::StoreGlobal(lookup->GetPropertyCell()));
1642 : }
1643 5547 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
1644 : DCHECK(holder.is_identical_to(receiver));
1645 5547 : return MaybeObjectHandle(StoreHandler::StoreNormal(isolate()));
1646 : }
1647 :
1648 : // -------------- Fields --------------
1649 165726 : if (lookup->property_details().location() == kField) {
1650 165690 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
1651 165690 : int descriptor = lookup->GetFieldDescriptorIndex();
1652 165690 : FieldIndex index = lookup->GetFieldIndex();
1653 : PropertyConstness constness = lookup->constness();
1654 165692 : if (constness == PropertyConstness::kConst &&
1655 0 : IsStoreOwnICKind(nexus()->kind())) {
1656 : // StoreOwnICs are used for initializing object literals therefore
1657 : // we must store the value unconditionally even to
1658 : // VariableMode::kConst fields.
1659 : constness = PropertyConstness::kMutable;
1660 : }
1661 : return MaybeObjectHandle(StoreHandler::StoreField(
1662 165692 : isolate(), descriptor, index, constness, lookup->representation()));
1663 : }
1664 :
1665 : // -------------- Constant properties --------------
1666 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
1667 : set_slow_stub_reason("constant property");
1668 36 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1669 36 : return MaybeObjectHandle(slow_stub());
1670 : }
1671 : case LookupIterator::JSPROXY: {
1672 : Handle<JSReceiver> receiver =
1673 360 : Handle<JSReceiver>::cast(lookup->GetReceiver());
1674 360 : Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
1675 : return MaybeObjectHandle(StoreHandler::StoreProxy(
1676 360 : isolate(), receiver_map(), holder, receiver));
1677 : }
1678 :
1679 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1680 : case LookupIterator::ACCESS_CHECK:
1681 : case LookupIterator::NOT_FOUND:
1682 0 : UNREACHABLE();
1683 : }
1684 0 : return MaybeObjectHandle();
1685 : }
1686 :
1687 215040 : void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
1688 : KeyedAccessStoreMode store_mode,
1689 : bool receiver_was_cow) {
1690 : MapHandles target_receiver_maps;
1691 226893 : TargetMaps(&target_receiver_maps);
1692 215041 : if (target_receiver_maps.empty()) {
1693 : Handle<Map> monomorphic_map =
1694 203178 : ComputeTransitionedMap(receiver_map, store_mode);
1695 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1696 203177 : Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
1697 : return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
1698 : }
1699 :
1700 45213 : for (Handle<Map> map : target_receiver_maps) {
1701 33360 : if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
1702 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1703 : set_slow_stub_reason("JSValue");
1704 : return;
1705 : }
1706 : }
1707 :
1708 : // There are several special cases where an IC that is MONOMORPHIC can still
1709 : // transition to a different GetNonTransitioningStoreMode IC that handles a
1710 : // superset of the original IC. Handle those here if the receiver map hasn't
1711 : // changed or it has transitioned to a more general kind.
1712 : KeyedAccessStoreMode old_store_mode;
1713 : old_store_mode = GetKeyedAccessStoreMode();
1714 11853 : Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1715 11853 : if (state() == MONOMORPHIC) {
1716 : Handle<Map> transitioned_receiver_map = receiver_map;
1717 9217 : if (IsTransitionStoreMode(store_mode)) {
1718 : transitioned_receiver_map =
1719 2817 : ComputeTransitionedMap(receiver_map, store_mode);
1720 : }
1721 11839 : if ((receiver_map.is_identical_to(previous_receiver_map) &&
1722 16785 : IsTransitionStoreMode(store_mode)) ||
1723 : IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1724 7568 : *transitioned_receiver_map)) {
1725 : // If the "old" and "new" maps are in the same elements map family, or
1726 : // if they at least come from the same origin for a transitioning store,
1727 : // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1728 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1729 : Handle<Object> handler =
1730 5149 : StoreElementHandler(transitioned_receiver_map, store_mode);
1731 : ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
1732 : return;
1733 : }
1734 5041 : if (receiver_map.is_identical_to(previous_receiver_map) &&
1735 4912 : old_store_mode == STANDARD_STORE &&
1736 1688 : (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1737 1213 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1738 : store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1739 : // A "normal" IC that handles stores can switch to a version that can
1740 : // grow at the end of the array, handle OOB accesses or copy COW arrays
1741 : // and still stay MONOMORPHIC.
1742 484 : Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
1743 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1744 : }
1745 : }
1746 :
1747 : DCHECK(state() != GENERIC);
1748 :
1749 : bool map_added =
1750 6220 : AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1751 :
1752 6220 : if (IsTransitionStoreMode(store_mode)) {
1753 : Handle<Map> transitioned_receiver_map =
1754 1256 : ComputeTransitionedMap(receiver_map, store_mode);
1755 : map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1756 1256 : transitioned_receiver_map);
1757 : }
1758 :
1759 6220 : if (!map_added) {
1760 : // If the miss wasn't due to an unseen map, a polymorphic stub
1761 : // won't help, use the megamorphic stub which can handle everything.
1762 : set_slow_stub_reason("same map added twice");
1763 : return;
1764 : }
1765 :
1766 : // If the maximum number of receiver maps has been exceeded, use the
1767 : // megamorphic version of the IC.
1768 11156 : if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return;
1769 :
1770 : // Make sure all polymorphic handlers have the same store mode, otherwise the
1771 : // megamorphic stub must be used.
1772 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1773 4844 : if (old_store_mode != STANDARD_STORE) {
1774 744 : if (store_mode == STANDARD_STORE) {
1775 : store_mode = old_store_mode;
1776 479 : } else if (store_mode != old_store_mode) {
1777 : set_slow_stub_reason("store mode mismatch");
1778 : return;
1779 : }
1780 : }
1781 :
1782 : // If the store mode isn't the standard mode, make sure that all polymorphic
1783 : // receivers are either external arrays, or all "normal" arrays. Otherwise,
1784 : // use the megamorphic stub.
1785 4817 : if (store_mode != STANDARD_STORE) {
1786 : size_t external_arrays = 0;
1787 5035 : for (Handle<Map> map : target_receiver_maps) {
1788 2072 : if (map->has_fixed_typed_array_elements()) {
1789 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1790 306 : external_arrays++;
1791 : }
1792 : }
1793 1017 : if (external_arrays != 0 &&
1794 126 : external_arrays != target_receiver_maps.size()) {
1795 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1796 : set_slow_stub_reason(
1797 : "unsupported combination of external and normal arrays");
1798 : return;
1799 : }
1800 : }
1801 :
1802 : MaybeObjectHandles handlers;
1803 9580 : handlers.reserve(target_receiver_maps.size());
1804 4790 : StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
1805 9580 : if (target_receiver_maps.size() == 0) {
1806 : // Transition to PREMONOMORPHIC state here and remember a weak-reference
1807 : // to the {receiver_map} in case TurboFan sees this function before the
1808 : // IC can transition further.
1809 9 : ConfigureVectorState(receiver_map);
1810 4781 : } else if (target_receiver_maps.size() == 1) {
1811 36 : ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1812 : } else {
1813 4763 : ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1814 : }
1815 : }
1816 :
1817 :
1818 207250 : Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1819 : Handle<Map> map, KeyedAccessStoreMode store_mode) {
1820 207250 : switch (store_mode) {
1821 : case STORE_TRANSITION_TO_OBJECT:
1822 : case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1823 : ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1824 : ? HOLEY_ELEMENTS
1825 18622 : : PACKED_ELEMENTS;
1826 22387 : return Map::TransitionElementsTo(isolate(), map, kind);
1827 : }
1828 : case STORE_TRANSITION_TO_DOUBLE:
1829 : case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1830 : ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1831 : ? HOLEY_DOUBLE_ELEMENTS
1832 3765 : : PACKED_DOUBLE_ELEMENTS;
1833 7530 : return Map::TransitionElementsTo(isolate(), map, kind);
1834 : }
1835 : case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1836 : DCHECK(map->has_fixed_typed_array_elements());
1837 : V8_FALLTHROUGH;
1838 : case STORE_NO_TRANSITION_HANDLE_COW:
1839 : case STANDARD_STORE:
1840 : case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
1841 184863 : return map;
1842 : }
1843 0 : UNREACHABLE();
1844 : }
1845 :
1846 219194 : Handle<Object> KeyedStoreIC::StoreElementHandler(
1847 : Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1848 : DCHECK(store_mode == STANDARD_STORE ||
1849 : store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1850 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1851 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1852 : DCHECK_IMPLIES(
1853 : receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()),
1854 : IsStoreInArrayLiteralICKind(kind()));
1855 :
1856 219194 : if (receiver_map->IsJSProxyMap()) {
1857 472528 : return StoreHandler::StoreProxy(isolate());
1858 : }
1859 :
1860 : // TODO(ishell): move to StoreHandler::StoreElement().
1861 : Handle<Code> code;
1862 219124 : if (receiver_map->has_sloppy_arguments_elements()) {
1863 : // TODO(jgruber): Update counter name.
1864 0 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
1865 : code =
1866 0 : CodeFactory::KeyedStoreIC_SloppyArguments(isolate(), store_mode).code();
1867 241715 : } else if (receiver_map->has_fast_elements() ||
1868 : receiver_map->has_fixed_typed_array_elements()) {
1869 217693 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
1870 435384 : code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code();
1871 217691 : if (receiver_map->has_fixed_typed_array_elements()) return code;
1872 1431 : } else if (IsStoreInArrayLiteralICKind(kind())) {
1873 : // TODO(jgruber): Update counter name.
1874 36 : TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
1875 : code =
1876 72 : CodeFactory::StoreInArrayLiteralIC_Slow(isolate(), store_mode).code();
1877 : } else {
1878 : // TODO(jgruber): Update counter name.
1879 1395 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
1880 : DCHECK_EQ(DICTIONARY_ELEMENTS, receiver_map->elements_kind());
1881 2790 : code = CodeFactory::KeyedStoreIC_Slow(isolate(), store_mode).code();
1882 : }
1883 :
1884 197962 : if (IsStoreInArrayLiteralICKind(kind())) return code;
1885 :
1886 : Handle<Object> validity_cell =
1887 26995 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1888 53990 : if (validity_cell->IsSmi()) {
1889 : // There's no prototype validity cell to check, so we can just use the stub.
1890 51 : return code;
1891 : }
1892 26944 : Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0);
1893 26944 : handler->set_validity_cell(*validity_cell);
1894 53888 : handler->set_smi_handler(*code);
1895 26944 : return handler;
1896 : }
1897 :
1898 4790 : void KeyedStoreIC::StoreElementPolymorphicHandlers(
1899 : MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1900 : KeyedAccessStoreMode store_mode) {
1901 : DCHECK(store_mode == STANDARD_STORE ||
1902 : store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1903 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1904 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1905 :
1906 : // Filter out deprecated maps to ensure their instances get migrated.
1907 : receiver_maps->erase(
1908 : std::remove_if(
1909 : receiver_maps->begin(), receiver_maps->end(),
1910 24414 : [](const Handle<Map>& map) { return map->is_deprecated(); }),
1911 4790 : receiver_maps->end());
1912 :
1913 21706 : for (Handle<Map> receiver_map : *receiver_maps) {
1914 : Handle<Object> handler;
1915 : Handle<Map> transition;
1916 :
1917 36378 : if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
1918 51887 : receiver_map->DictionaryElementsInPrototypeChainOnly(isolate())) {
1919 : // TODO(mvstanton): Consider embedding store_mode in the state of the slow
1920 : // keyed store ic for uniformity.
1921 45 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
1922 45 : handler = slow_stub();
1923 :
1924 : } else {
1925 : {
1926 : Map tmap = receiver_map->FindElementsKindTransitionedMap(
1927 12081 : isolate(), *receiver_maps);
1928 12081 : if (!tmap.is_null()) {
1929 1696 : if (receiver_map->is_stable()) {
1930 36 : receiver_map->NotifyLeafMapLayoutChange(isolate());
1931 : }
1932 : transition = handle(tmap, isolate());
1933 : }
1934 : }
1935 :
1936 : // TODO(mvstanton): The code below is doing pessimistic elements
1937 : // transitions. I would like to stop doing that and rely on Allocation
1938 : // Site Tracking to do a better job of ensuring the data types are what
1939 : // they need to be. Not all the elements are in place yet, pessimistic
1940 : // elements transitions are still important for performance.
1941 12081 : if (!transition.is_null()) {
1942 1696 : TRACE_HANDLER_STATS(isolate(),
1943 : KeyedStoreIC_ElementsTransitionAndStoreStub);
1944 : handler = StoreHandler::StoreElementTransition(isolate(), receiver_map,
1945 1696 : transition, store_mode);
1946 : } else {
1947 10385 : handler = StoreElementHandler(receiver_map, store_mode);
1948 : }
1949 : }
1950 : DCHECK(!handler.is_null());
1951 12126 : handlers->push_back(MaybeObjectHandle(handler));
1952 : }
1953 4790 : }
1954 :
1955 :
1956 312578 : static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
1957 : uint32_t index, Handle<Object> value) {
1958 312578 : bool oob_access = IsOutOfBoundsAccess(receiver, index);
1959 : // Don't consider this a growing store if the store would send the receiver to
1960 : // dictionary mode.
1961 1040018 : bool allow_growth = receiver->IsJSArray() && oob_access &&
1962 414858 : !receiver->WouldConvertToSlowElements(index);
1963 312580 : if (allow_growth) {
1964 : // Handle growing array in stub if necessary.
1965 202794 : if (receiver->HasSmiElements()) {
1966 15576 : if (value->IsHeapNumber()) {
1967 : return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
1968 : }
1969 14662 : if (value->IsHeapObject()) {
1970 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1971 : }
1972 187218 : } else if (receiver->HasDoubleElements()) {
1973 2094 : if (!value->IsSmi() && !value->IsHeapNumber()) {
1974 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
1975 : }
1976 : }
1977 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1978 : } else {
1979 : // Handle only in-bounds elements accesses.
1980 422366 : if (receiver->HasSmiElements()) {
1981 334850 : if (value->IsHeapNumber()) {
1982 : return STORE_TRANSITION_TO_DOUBLE;
1983 329009 : } else if (value->IsHeapObject()) {
1984 : return STORE_TRANSITION_TO_OBJECT;
1985 : }
1986 87518 : } else if (receiver->HasDoubleElements()) {
1987 16458 : if (!value->IsSmi() && !value->IsHeapNumber()) {
1988 : return STORE_TRANSITION_TO_OBJECT;
1989 : }
1990 : }
1991 567471 : if (!FLAG_trace_external_array_abuse &&
1992 206798 : receiver->map()->has_fixed_typed_array_elements() && oob_access) {
1993 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1994 : }
1995 376792 : return receiver->elements()->IsCowArray() ? STORE_NO_TRANSITION_HANDLE_COW
1996 188396 : : STANDARD_STORE;
1997 : }
1998 : }
1999 :
2000 :
2001 160665 : MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2002 : Handle<Object> key,
2003 : Handle<Object> value) {
2004 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
2005 : // might deprecate the current map again, if value does not fit.
2006 160665 : if (MigrateDeprecated(object)) {
2007 : Handle<Object> result;
2008 948654 : ASSIGN_RETURN_ON_EXCEPTION(
2009 : isolate(), result,
2010 : Runtime::SetObjectProperty(isolate(), object, key, value,
2011 : language_mode(), StoreOrigin::kMaybeKeyed),
2012 : Object);
2013 36 : return result;
2014 : }
2015 :
2016 : // Check for non-string values that can be converted into an
2017 : // internalized string directly or is representable as a smi.
2018 160629 : key = TryConvertKey(key, isolate());
2019 :
2020 : Handle<Object> store_handle;
2021 :
2022 : uint32_t index;
2023 329831 : if ((key->IsInternalizedString() &&
2024 482803 : !String::cast(*key)->AsArrayIndex(&index)) ||
2025 313601 : key->IsSymbol()) {
2026 24550 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2027 : StoreIC::Store(object, Handle<Name>::cast(key),
2028 : value, StoreOrigin::kMaybeKeyed),
2029 : Object);
2030 11726 : if (vector_needs_update()) {
2031 18 : if (ConfigureVectorState(MEGAMORPHIC, key)) {
2032 : set_slow_stub_reason("unhandled internalized string key");
2033 18 : TraceIC("StoreIC", key);
2034 : }
2035 : }
2036 11726 : return store_handle;
2037 : }
2038 :
2039 148354 : JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
2040 :
2041 296708 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic &&
2042 1037732 : !object->IsStringWrapper() && !object->IsAccessCheckNeeded() &&
2043 296436 : !object->IsJSGlobalProxy();
2044 444266 : if (use_ic && !object->IsSmi()) {
2045 : // Don't use ICs for maps of the objects in Array's prototype chain. We
2046 : // expect to be able to trap element sets to objects with those maps in
2047 : // the runtime to enable optimization of element hole access.
2048 147542 : Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2049 147542 : if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) {
2050 : set_slow_stub_reason("map in array prototype");
2051 : use_ic = false;
2052 : }
2053 : }
2054 :
2055 : Handle<Map> old_receiver_map;
2056 : bool is_arguments = false;
2057 : bool key_is_valid_index = false;
2058 : KeyedAccessStoreMode store_mode = STANDARD_STORE;
2059 442618 : if (use_ic && object->IsJSReceiver()) {
2060 146479 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
2061 : old_receiver_map = handle(receiver->map(), isolate());
2062 292958 : is_arguments = receiver->IsJSArgumentsObject();
2063 292958 : bool is_proxy = receiver->IsJSProxy();
2064 : // For JSTypedArray {object}s we can handle negative indices as OOB
2065 : // accesses, since integer indexed properties are never looked up
2066 : // on the prototype chain. For this we simply map the negative {key}s
2067 : // to the [2**31,2**32-1] range, which is safe since JSTypedArray::length
2068 : // is always an unsigned Smi.
2069 : key_is_valid_index =
2070 437352 : key->IsSmi() && (Smi::ToInt(*key) >= 0 || object->IsJSTypedArray());
2071 146479 : if (!is_arguments && !is_proxy) {
2072 144826 : if (key_is_valid_index) {
2073 141629 : uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key));
2074 141629 : Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
2075 141629 : store_mode = GetStoreMode(receiver_object, index, value);
2076 : }
2077 : }
2078 : }
2079 :
2080 : DCHECK(store_handle.is_null());
2081 : bool receiver_was_cow =
2082 561927 : object->IsJSArray() &&
2083 382084 : Handle<JSArray>::cast(object)->elements()->IsCowArray();
2084 296708 : ASSIGN_RETURN_ON_EXCEPTION(
2085 : isolate(), store_handle,
2086 : Runtime::SetObjectProperty(isolate(), object, key, value, language_mode(),
2087 : StoreOrigin::kMaybeKeyed),
2088 : Object);
2089 :
2090 54405 : if (use_ic) {
2091 53203 : if (!old_receiver_map.is_null()) {
2092 52667 : if (is_arguments) {
2093 : set_slow_stub_reason("arguments receiver");
2094 51536 : } else if (key_is_valid_index) {
2095 48888 : if (old_receiver_map->is_abandoned_prototype_map()) {
2096 : set_slow_stub_reason("receiver with prototype map");
2097 48870 : } else if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly(
2098 48870 : isolate())) {
2099 : // We should go generic if receiver isn't a dictionary, but our
2100 : // prototype chain does have dictionary elements. This ensures that
2101 : // other non-dictionary receivers in the polymorphic case benefit
2102 : // from fast path keyed stores.
2103 44090 : UpdateStoreElement(old_receiver_map, store_mode, receiver_was_cow);
2104 : } else {
2105 : set_slow_stub_reason("dictionary or proxy prototype");
2106 : }
2107 : } else {
2108 : set_slow_stub_reason("non-smi-like key");
2109 : }
2110 : } else {
2111 : set_slow_stub_reason("non-JSObject receiver");
2112 : }
2113 : }
2114 :
2115 54405 : if (vector_needs_update()) {
2116 11755 : ConfigureVectorState(MEGAMORPHIC, key);
2117 : }
2118 54405 : TraceIC("StoreIC", key);
2119 :
2120 54405 : return store_handle;
2121 : }
2122 :
2123 : namespace {
2124 171076 : void StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
2125 : Handle<Object> index, Handle<Object> value) {
2126 : DCHECK(index->IsNumber());
2127 171076 : bool success = false;
2128 : LookupIterator it = LookupIterator::PropertyOrElement(
2129 171076 : isolate, array, index, &success, LookupIterator::OWN);
2130 : DCHECK(success);
2131 :
2132 342158 : CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE,
2133 : kThrowOnError)
2134 : .FromJust());
2135 171079 : }
2136 : } // namespace
2137 :
2138 170949 : void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
2139 : Handle<Object> value) {
2140 : DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate()));
2141 : DCHECK(index->IsNumber());
2142 :
2143 683802 : if (!FLAG_use_ic || state() == NO_FEEDBACK || MigrateDeprecated(array)) {
2144 0 : StoreOwnElement(isolate(), array, index, value);
2145 0 : TraceIC("StoreInArrayLiteralIC", index);
2146 170951 : return;
2147 : }
2148 :
2149 : // TODO(neis): Convert HeapNumber to Smi if possible?
2150 :
2151 : KeyedAccessStoreMode store_mode = STANDARD_STORE;
2152 341904 : if (index->IsSmi()) {
2153 : DCHECK_GE(Smi::ToInt(*index), 0);
2154 170950 : uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2155 170951 : store_mode = GetStoreMode(array, index32, value);
2156 : }
2157 :
2158 : Handle<Map> old_array_map(array->map(), isolate());
2159 170951 : bool array_was_cow = array->elements()->IsCowArray();
2160 170952 : StoreOwnElement(isolate(), array, index, value);
2161 :
2162 341904 : if (index->IsSmi()) {
2163 : DCHECK(!old_array_map->is_abandoned_prototype_map());
2164 170952 : UpdateStoreElement(old_array_map, store_mode, array_was_cow);
2165 : } else {
2166 : set_slow_stub_reason("index out of Smi range");
2167 : }
2168 :
2169 170951 : if (vector_needs_update()) {
2170 0 : ConfigureVectorState(MEGAMORPHIC, index);
2171 : }
2172 170951 : TraceIC("StoreInArrayLiteralIC", index);
2173 : }
2174 :
2175 : // ----------------------------------------------------------------------------
2176 : // Static IC stub generators.
2177 : //
2178 : //
2179 : namespace {
2180 :
2181 : // TODO(8580): Compute the language mode lazily to avoid the expensive
2182 : // computation of language mode here.
2183 3975866 : LanguageMode GetLanguageMode(Handle<FeedbackVector> vector, Context context) {
2184 3975867 : LanguageMode language_mode = vector->shared_function_info()->language_mode();
2185 3975869 : if (context->scope_info()->language_mode() > language_mode) {
2186 424 : return context->scope_info()->language_mode();
2187 : }
2188 : return language_mode;
2189 : }
2190 :
2191 : } // namespace
2192 :
2193 1291983 : RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2194 1291933 : HandleScope scope(isolate);
2195 : DCHECK_EQ(4, args.length());
2196 : // Runtime functions don't follow the IC's calling convention.
2197 1291945 : Handle<Object> receiver = args.at(0);
2198 1291956 : Handle<Name> key = args.at<Name>(1);
2199 1291965 : Handle<Smi> slot = args.at<Smi>(2);
2200 1291966 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2201 1291968 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2202 :
2203 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2204 2583929 : if (!maybe_vector->IsUndefined()) {
2205 : DCHECK(maybe_vector->IsFeedbackVector());
2206 1291961 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2207 : }
2208 : // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2209 : // LoadIC miss handler if the handler misses. Since the vector Nexus is
2210 : // set up outside the IC, handle that here.
2211 : // The only case where we call without a vector is from the LoadNamedProperty
2212 : // bytecode handler. Also, when there is no feedback vector, there is no
2213 : // difference between LoadProperty or LoadKeyed kind.
2214 : FeedbackSlotKind kind = FeedbackSlotKind::kLoadProperty;
2215 1291960 : if (!vector.is_null()) {
2216 1291961 : kind = vector->GetKind(vector_slot);
2217 : }
2218 1291948 : if (IsLoadICKind(kind)) {
2219 1291949 : LoadIC ic(isolate, vector, vector_slot, kind);
2220 1291955 : ic.UpdateState(receiver, key);
2221 3875892 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2222 :
2223 0 : } else if (IsLoadGlobalICKind(kind)) {
2224 : DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2225 0 : receiver = isolate->global_object();
2226 0 : LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2227 0 : ic.UpdateState(receiver, key);
2228 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2229 :
2230 : } else {
2231 : DCHECK(IsKeyedLoadICKind(kind));
2232 0 : KeyedLoadIC ic(isolate, vector, vector_slot, kind);
2233 0 : ic.UpdateState(receiver, key);
2234 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2235 1291962 : }
2236 : }
2237 :
2238 2072914 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2239 2072864 : HandleScope scope(isolate);
2240 : DCHECK_EQ(4, args.length());
2241 : // Runtime functions don't follow the IC's calling convention.
2242 2072870 : Handle<JSGlobalObject> global = isolate->global_object();
2243 2072854 : Handle<String> name = args.at<String>(0);
2244 2072858 : Handle<Smi> slot = args.at<Smi>(1);
2245 2072860 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2246 4145716 : CONVERT_INT32_ARG_CHECKED(typeof_value, 3);
2247 2072859 : TypeofMode typeof_mode = static_cast<TypeofMode>(typeof_value);
2248 2072861 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2249 :
2250 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2251 4145717 : if (!maybe_vector->IsUndefined()) {
2252 : DCHECK(maybe_vector->IsFeedbackVector());
2253 2072862 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2254 : }
2255 :
2256 : FeedbackSlotKind kind = (typeof_mode == TypeofMode::INSIDE_TYPEOF)
2257 : ? FeedbackSlotKind::kLoadGlobalInsideTypeof
2258 2072861 : : FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
2259 4145727 : LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2260 2072862 : ic.UpdateState(global, name);
2261 :
2262 : Handle<Object> result;
2263 4145750 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2264 2072869 : return *result;
2265 : }
2266 :
2267 784 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2268 784 : HandleScope scope(isolate);
2269 : DCHECK_EQ(3, args.length());
2270 1568 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2271 :
2272 784 : Handle<Context> native_context = isolate->native_context();
2273 : Handle<ScriptContextTable> script_contexts(
2274 1568 : native_context->script_context_table(), isolate);
2275 :
2276 : ScriptContextTable::LookupResult lookup_result;
2277 784 : if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2278 : &lookup_result)) {
2279 : Handle<Context> script_context = ScriptContextTable::GetContext(
2280 0 : isolate, script_contexts, lookup_result.context_index);
2281 : Handle<Object> result(script_context->get(lookup_result.slot_index),
2282 0 : isolate);
2283 0 : if (*result == ReadOnlyRoots(isolate).the_hole_value()) {
2284 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2285 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2286 : }
2287 : return *result;
2288 : }
2289 :
2290 1568 : Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2291 : Handle<Object> result;
2292 784 : bool is_found = false;
2293 1568 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2294 : isolate, result,
2295 : Runtime::GetObjectProperty(isolate, global, name, &is_found));
2296 784 : if (!is_found) {
2297 0 : Handle<Smi> slot = args.at<Smi>(1);
2298 0 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2299 0 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2300 0 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2301 : // It is actually a LoadGlobalICs here but the predicate handles this case
2302 : // properly.
2303 0 : if (LoadIC::ShouldThrowReferenceError(kind)) {
2304 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2305 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2306 : }
2307 : }
2308 784 : return *result;
2309 : }
2310 :
2311 215089 : RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2312 215089 : HandleScope scope(isolate);
2313 : DCHECK_EQ(4, args.length());
2314 : // Runtime functions don't follow the IC's calling convention.
2315 215089 : Handle<Object> receiver = args.at(0);
2316 215089 : Handle<Object> key = args.at(1);
2317 215089 : Handle<Smi> slot = args.at<Smi>(2);
2318 215090 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2319 :
2320 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2321 430180 : if (!maybe_vector->IsUndefined()) {
2322 : DCHECK(maybe_vector->IsFeedbackVector());
2323 215089 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2324 : }
2325 215089 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2326 430179 : KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadKeyed);
2327 215089 : ic.UpdateState(receiver, key);
2328 645269 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2329 : }
2330 :
2331 1296183 : RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2332 1296183 : HandleScope scope(isolate);
2333 : DCHECK_EQ(5, args.length());
2334 : // Runtime functions don't follow the IC's calling convention.
2335 1296189 : Handle<Object> value = args.at(0);
2336 1296191 : Handle<Smi> slot = args.at<Smi>(1);
2337 1296192 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2338 1296196 : Handle<Object> receiver = args.at(3);
2339 1296196 : Handle<Name> key = args.at<Name>(4);
2340 :
2341 1296195 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2342 1296194 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2343 1296193 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2344 1296198 : if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
2345 1296194 : StoreIC ic(isolate, vector, vector_slot, kind, language_mode);
2346 1296191 : ic.UpdateState(receiver, key);
2347 3888586 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2348 0 : } else if (IsStoreGlobalICKind(kind)) {
2349 : DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2350 0 : receiver = isolate->global_object();
2351 0 : StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
2352 0 : ic.UpdateState(receiver, key);
2353 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2354 : } else {
2355 : DCHECK(IsKeyedStoreICKind(kind));
2356 0 : KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
2357 0 : ic.UpdateState(receiver, key);
2358 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2359 1296193 : }
2360 : }
2361 :
2362 0 : RUNTIME_FUNCTION(Runtime_StoreICNoFeedback_Miss) {
2363 0 : HandleScope scope(isolate);
2364 : DCHECK_EQ(5, args.length());
2365 0 : Handle<Object> value = args.at(0);
2366 0 : Handle<Object> receiver = args.at(1);
2367 0 : Handle<Name> key = args.at<Name>(2);
2368 0 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
2369 0 : CONVERT_INT32_ARG_CHECKED(is_own_property_value, 4);
2370 : NamedPropertyType property_type =
2371 0 : static_cast<NamedPropertyType>(is_own_property_value);
2372 :
2373 : FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
2374 : ? FeedbackSlotKind::kStoreNamedStrict
2375 0 : : FeedbackSlotKind::kStoreNamedSloppy;
2376 0 : if (property_type == NamedPropertyType::kOwn) {
2377 : language_mode = LanguageMode::kStrict;
2378 : kind = FeedbackSlotKind::kStoreOwnNamed;
2379 : }
2380 : StoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
2381 0 : language_mode);
2382 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2383 : }
2384 :
2385 1645920 : RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2386 1645920 : HandleScope scope(isolate);
2387 : DCHECK_EQ(4, args.length());
2388 : // Runtime functions don't follow the IC's calling convention.
2389 1645920 : Handle<Object> value = args.at(0);
2390 1645920 : Handle<Smi> slot = args.at<Smi>(1);
2391 1645920 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2392 1645920 : Handle<Name> key = args.at<Name>(3);
2393 :
2394 1645920 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2395 1645920 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2396 1645920 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2397 3291840 : StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
2398 1645920 : Handle<JSGlobalObject> global = isolate->global_object();
2399 1645920 : ic.UpdateState(global, key);
2400 4937760 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2401 : }
2402 :
2403 0 : RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
2404 0 : HandleScope scope(isolate);
2405 : DCHECK_EQ(3, args.length());
2406 : // Runtime functions don't follow the IC's calling convention.
2407 0 : Handle<Object> value = args.at(0);
2408 0 : Handle<Name> key = args.at<Name>(1);
2409 0 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2);
2410 :
2411 : FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
2412 : ? FeedbackSlotKind::kStoreGlobalStrict
2413 0 : : FeedbackSlotKind::kStoreGlobalSloppy;
2414 : StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
2415 0 : language_mode);
2416 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2417 : }
2418 :
2419 7418 : RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
2420 7418 : HandleScope scope(isolate);
2421 : DCHECK_EQ(5, args.length());
2422 : // Runtime functions don't follow the IC's calling convention.
2423 7418 : Handle<Object> value = args.at(0);
2424 7418 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2425 14836 : CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
2426 :
2427 : #ifdef DEBUG
2428 : {
2429 : Handle<Smi> slot = args.at<Smi>(1);
2430 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2431 : FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2432 : DCHECK(IsStoreGlobalICKind(slot_kind));
2433 : Handle<Object> receiver = args.at(3);
2434 : DCHECK(receiver->IsJSGlobalProxy());
2435 : }
2436 : #endif
2437 :
2438 7418 : Handle<JSGlobalObject> global = isolate->global_object();
2439 7418 : Handle<Context> native_context = isolate->native_context();
2440 : Handle<ScriptContextTable> script_contexts(
2441 14836 : native_context->script_context_table(), isolate);
2442 :
2443 : ScriptContextTable::LookupResult lookup_result;
2444 7418 : if (ScriptContextTable::Lookup(isolate, script_contexts, name,
2445 : &lookup_result)) {
2446 : Handle<Context> script_context = ScriptContextTable::GetContext(
2447 18 : isolate, script_contexts, lookup_result.context_index);
2448 18 : if (lookup_result.mode == VariableMode::kConst) {
2449 18 : THROW_NEW_ERROR_RETURN_FAILURE(
2450 : isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
2451 : }
2452 :
2453 : Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
2454 27 : isolate);
2455 :
2456 18 : if (previous_value->IsTheHole(isolate)) {
2457 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2458 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2459 : }
2460 :
2461 27 : script_context->set(lookup_result.slot_index, *value);
2462 : return *value;
2463 : }
2464 :
2465 7400 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2466 14800 : RETURN_RESULT_OR_FAILURE(
2467 : isolate,
2468 : Runtime::SetObjectProperty(isolate, global, name, value, language_mode,
2469 7418 : StoreOrigin::kMaybeKeyed));
2470 : }
2471 :
2472 162309 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2473 162309 : HandleScope scope(isolate);
2474 : DCHECK_EQ(5, args.length());
2475 : // Runtime functions don't follow the IC's calling convention.
2476 162309 : Handle<Object> value = args.at(0);
2477 162309 : Handle<Smi> slot = args.at<Smi>(1);
2478 162309 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2479 162309 : Handle<Object> receiver = args.at(3);
2480 162309 : Handle<Object> key = args.at(4);
2481 :
2482 162309 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2483 162309 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2484 162309 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2485 :
2486 : // The elements store stubs miss into this function, but they are shared by
2487 : // different ICs.
2488 162309 : if (IsKeyedStoreICKind(kind)) {
2489 160665 : KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
2490 160665 : ic.UpdateState(receiver, key);
2491 481995 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2492 : } else {
2493 : DCHECK(IsStoreInArrayLiteralICKind(kind));
2494 : DCHECK(receiver->IsJSArray());
2495 : DCHECK(key->IsNumber());
2496 1644 : StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2497 1644 : ic.UpdateState(receiver, key);
2498 1644 : ic.Store(Handle<JSArray>::cast(receiver), key, value);
2499 1644 : return *value;
2500 162309 : }
2501 : }
2502 :
2503 0 : RUNTIME_FUNCTION(Runtime_KeyedStoreICNoFeedback_Miss) {
2504 0 : HandleScope scope(isolate);
2505 : DCHECK_EQ(4, args.length());
2506 : // Runtime functions don't follow the IC's calling convention.
2507 0 : Handle<Object> value = args.at(0);
2508 0 : Handle<Object> receiver = args.at(1);
2509 0 : Handle<Object> key = args.at(2);
2510 0 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
2511 :
2512 : FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
2513 : ? FeedbackSlotKind::kStoreKeyedStrict
2514 0 : : FeedbackSlotKind::kStoreKeyedSloppy;
2515 : KeyedStoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
2516 0 : language_mode);
2517 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2518 : }
2519 :
2520 169305 : RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
2521 169305 : HandleScope scope(isolate);
2522 : DCHECK_EQ(5, args.length());
2523 : // Runtime functions don't follow the IC's calling convention.
2524 169308 : Handle<Object> value = args.at(0);
2525 169308 : Handle<Smi> slot = args.at<Smi>(1);
2526 169308 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2527 169308 : Handle<Object> receiver = args.at(3);
2528 169308 : Handle<Object> key = args.at(4);
2529 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2530 338616 : if (!maybe_vector->IsUndefined()) {
2531 : DCHECK(maybe_vector->IsFeedbackVector());
2532 169308 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2533 : }
2534 : DCHECK(receiver->IsJSArray());
2535 : DCHECK(key->IsNumber());
2536 169308 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2537 338613 : StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2538 169306 : ic.Store(Handle<JSArray>::cast(receiver), key, value);
2539 169307 : return *value;
2540 : }
2541 :
2542 317557 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2543 317557 : HandleScope scope(isolate);
2544 : DCHECK_EQ(5, args.length());
2545 : // Runtime functions don't follow the IC's calling convention.
2546 317557 : Handle<Object> value = args.at(0);
2547 317557 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2548 317557 : Handle<Object> object = args.at(3);
2549 317557 : Handle<Object> key = args.at(4);
2550 317557 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2551 635114 : RETURN_RESULT_OR_FAILURE(
2552 : isolate,
2553 : Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
2554 317557 : StoreOrigin::kMaybeKeyed));
2555 : }
2556 :
2557 47 : RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
2558 47 : HandleScope scope(isolate);
2559 : DCHECK_EQ(3, args.length());
2560 : // Runtime functions don't follow the IC's calling convention.
2561 47 : Handle<Object> value = args.at(0);
2562 47 : Handle<Object> array = args.at(1);
2563 47 : Handle<Object> index = args.at(2);
2564 47 : StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value);
2565 47 : return *value;
2566 : }
2567 :
2568 225 : RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2569 225 : HandleScope scope(isolate);
2570 : DCHECK_EQ(6, args.length());
2571 : // Runtime functions don't follow the IC's calling convention.
2572 225 : Handle<Object> object = args.at(0);
2573 225 : Handle<Object> key = args.at(1);
2574 225 : Handle<Object> value = args.at(2);
2575 225 : Handle<Map> map = args.at<Map>(3);
2576 225 : Handle<Smi> slot = args.at<Smi>(4);
2577 225 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2578 225 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2579 225 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2580 :
2581 450 : if (object->IsJSObject()) {
2582 : JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2583 225 : map->elements_kind());
2584 : }
2585 :
2586 225 : if (IsStoreInArrayLiteralICKind(kind)) {
2587 80 : StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value);
2588 : return *value;
2589 : } else {
2590 : DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
2591 145 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2592 290 : RETURN_RESULT_OR_FAILURE(
2593 : isolate,
2594 : Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
2595 : StoreOrigin::kMaybeKeyed));
2596 225 : }
2597 : }
2598 :
2599 513 : static bool CanFastCloneObject(Handle<Map> map) {
2600 : DisallowHeapAllocation no_gc;
2601 513 : if (map->IsNullOrUndefinedMap()) return true;
2602 909 : if (!map->IsJSObjectMap() ||
2603 891 : !IsSmiOrObjectElementsKind(map->elements_kind()) ||
2604 891 : !map->OnlyHasSimpleProperties()) {
2605 : return false;
2606 : }
2607 :
2608 387 : DescriptorArray descriptors = map->instance_descriptors();
2609 1674 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
2610 477 : PropertyDetails details = descriptors->GetDetails(i);
2611 477 : Name key = descriptors->GetKey(i);
2612 1386 : if (details.kind() != kData || !details.IsEnumerable() ||
2613 450 : key->IsPrivateName()) {
2614 27 : return false;
2615 : }
2616 : }
2617 :
2618 : return true;
2619 : }
2620 :
2621 387 : static Handle<Map> FastCloneObjectMap(Isolate* isolate,
2622 : Handle<HeapObject> source, int flags) {
2623 : Handle<Map> source_map(source->map(), isolate);
2624 : SLOW_DCHECK(source->IsNullOrUndefined() || CanFastCloneObject(source_map));
2625 1161 : Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2626 387 : isolate);
2627 : DCHECK(constructor->has_initial_map());
2628 774 : Handle<Map> initial_map(constructor->initial_map(), isolate);
2629 : Handle<Map> map = initial_map;
2630 :
2631 1494 : if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() !=
2632 747 : initial_map->GetInObjectProperties()) {
2633 306 : int inobject_properties = source_map->GetInObjectProperties();
2634 : int instance_size =
2635 306 : JSObject::kHeaderSize + kTaggedSize * inobject_properties;
2636 306 : int unused = source_map->UnusedInObjectProperties();
2637 : DCHECK(instance_size <= JSObject::kMaxInstanceSize);
2638 : map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties,
2639 306 : unused);
2640 : }
2641 :
2642 387 : if (flags & ObjectLiteral::kHasNullPrototype) {
2643 0 : if (map.is_identical_to(initial_map)) {
2644 0 : map = Map::Copy(isolate, map, "ObjectWithNullProto");
2645 : }
2646 0 : Map::SetPrototype(isolate, map, isolate->factory()->null_value());
2647 : }
2648 :
2649 1134 : if (source->IsNullOrUndefined() || !source_map->NumberOfOwnDescriptors()) {
2650 126 : return map;
2651 : }
2652 :
2653 261 : if (map.is_identical_to(initial_map)) {
2654 18 : map = Map::Copy(isolate, map, "InitializeClonedDescriptors");
2655 : }
2656 :
2657 : Handle<DescriptorArray> source_descriptors(source_map->instance_descriptors(),
2658 522 : isolate);
2659 : int size = source_map->NumberOfOwnDescriptors();
2660 : int slack = 0;
2661 : Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone(
2662 261 : isolate, source_descriptors, size, slack);
2663 : Handle<LayoutDescriptor> layout =
2664 261 : LayoutDescriptor::New(isolate, map, descriptors, size);
2665 261 : map->InitializeDescriptors(isolate, *descriptors, *layout);
2666 261 : map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map);
2667 :
2668 : // Update bitfields
2669 : map->set_may_have_interesting_symbols(
2670 522 : source_map->may_have_interesting_symbols());
2671 :
2672 261 : return map;
2673 : }
2674 :
2675 126 : static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
2676 : Handle<HeapObject> source,
2677 : int flags) {
2678 : Handle<JSObject> new_object;
2679 126 : if (flags & ObjectLiteral::kHasNullPrototype) {
2680 0 : new_object = isolate->factory()->NewJSObjectWithNullProto();
2681 : } else {
2682 378 : Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2683 126 : isolate);
2684 126 : new_object = isolate->factory()->NewJSObject(constructor);
2685 : }
2686 :
2687 252 : if (source->IsNullOrUndefined()) {
2688 0 : return new_object;
2689 : }
2690 :
2691 126 : MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source,
2692 : nullptr, false),
2693 : MaybeHandle<JSObject>());
2694 90 : return new_object;
2695 : }
2696 :
2697 513 : RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
2698 513 : HandleScope scope(isolate);
2699 : DCHECK_EQ(4, args.length());
2700 513 : Handle<HeapObject> source = args.at<HeapObject>(0);
2701 513 : int flags = args.smi_at(1);
2702 :
2703 513 : MigrateDeprecated(source);
2704 :
2705 513 : FeedbackSlot slot = FeedbackVector::ToSlot(args.smi_at(2));
2706 513 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2707 1026 : if (maybe_vector->IsUndefined()) {
2708 0 : RETURN_RESULT_OR_FAILURE(isolate,
2709 : CloneObjectSlowPath(isolate, source, flags));
2710 : }
2711 :
2712 : DCHECK(maybe_vector->IsFeedbackVector());
2713 513 : Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(maybe_vector);
2714 :
2715 513 : FeedbackNexus nexus(vector, slot);
2716 1026 : Handle<Map> source_map(source->map(), isolate);
2717 :
2718 513 : if (!CanFastCloneObject(source_map) || nexus.IsMegamorphic()) {
2719 : // Migrate to slow mode if needed.
2720 126 : nexus.ConfigureMegamorphic();
2721 252 : RETURN_RESULT_OR_FAILURE(isolate,
2722 : CloneObjectSlowPath(isolate, source, flags));
2723 : }
2724 :
2725 387 : Handle<Map> result_map = FastCloneObjectMap(isolate, source, flags);
2726 387 : nexus.ConfigureCloneObject(source_map, result_map);
2727 :
2728 513 : return *result_map;
2729 : }
2730 :
2731 495922 : RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2732 495922 : Handle<JSObject> receiver = args.at<JSObject>(0);
2733 495922 : Handle<JSObject> holder = args.at<JSObject>(1);
2734 495922 : Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2735 495922 : Handle<Name> name = args.at<Name>(3);
2736 495922 : Handle<Object> value = args.at(4);
2737 991844 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
2738 495922 : HandleScope scope(isolate);
2739 :
2740 495922 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
2741 0 : RETURN_RESULT_OR_FAILURE(
2742 : isolate,
2743 : Runtime::SetObjectProperty(isolate, receiver, name, value,
2744 : language_mode, StoreOrigin::kMaybeKeyed));
2745 : }
2746 :
2747 : DCHECK(info->IsCompatibleReceiver(*receiver));
2748 :
2749 : ShouldThrow should_throw =
2750 495922 : is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
2751 : PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
2752 1487766 : should_throw);
2753 495922 : arguments.CallAccessorSetter(info, name, value);
2754 495922 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2755 495922 : return *value;
2756 : }
2757 :
2758 6276 : RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) {
2759 1046 : Handle<JSObject> receiver = args.at<JSObject>(0);
2760 1046 : Handle<JSObject> holder = args.at<JSObject>(1);
2761 1046 : Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2762 1046 : Handle<Name> name = args.at<Name>(3);
2763 1046 : HandleScope scope(isolate);
2764 :
2765 : DCHECK(info->IsCompatibleReceiver(*receiver));
2766 :
2767 : PropertyCallbackArguments custom_args(isolate, info->data(), *receiver,
2768 3138 : *holder, kThrowOnError);
2769 1046 : Handle<Object> result = custom_args.CallAccessorGetter(info, name);
2770 1046 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2771 1046 : if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2772 1046 : return *result;
2773 : }
2774 :
2775 24030 : RUNTIME_FUNCTION(Runtime_LoadAccessorProperty) {
2776 4005 : HandleScope scope(isolate);
2777 : DCHECK_EQ(args.length(), 3);
2778 4005 : Handle<JSObject> receiver = args.at<JSObject>(0);
2779 4005 : int handler_kind = args.smi_at(1);
2780 4005 : Handle<CallHandlerInfo> call_handler_info = args.at<CallHandlerInfo>(2);
2781 :
2782 4005 : Object holder = *receiver;
2783 4005 : if (handler_kind == LoadHandler::kApiGetterHolderIsPrototype) {
2784 0 : holder = receiver->map()->prototype();
2785 : } else {
2786 : DCHECK_EQ(handler_kind, LoadHandler::kApiGetter);
2787 : }
2788 :
2789 : // Call the accessor without additional arguments.
2790 : FunctionCallbackArguments custom(isolate, call_handler_info->data(),
2791 16020 : *receiver, holder, HeapObject(), nullptr, 0);
2792 4005 : Handle<Object> result_handle = custom.Call(*call_handler_info);
2793 4005 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2794 4005 : if (result_handle.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2795 4005 : return *result_handle;
2796 : }
2797 :
2798 : /**
2799 : * Loads a property with an interceptor performing post interceptor
2800 : * lookup if interceptor failed.
2801 : */
2802 134144 : RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2803 134144 : HandleScope scope(isolate);
2804 : DCHECK_EQ(5, args.length());
2805 134144 : Handle<Name> name = args.at<Name>(0);
2806 134144 : Handle<Object> receiver = args.at(1);
2807 134144 : Handle<JSObject> holder = args.at<JSObject>(2);
2808 :
2809 268288 : if (!receiver->IsJSReceiver()) {
2810 10 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2811 : isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2812 : }
2813 :
2814 268288 : Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
2815 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2816 268288 : *holder, kDontThrow);
2817 134144 : Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
2818 :
2819 134144 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2820 :
2821 134132 : if (!result.is_null()) return *result;
2822 :
2823 55316 : LookupIterator it(receiver, name, holder);
2824 : // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2825 165948 : while (it.state() != LookupIterator::INTERCEPTOR ||
2826 110632 : !it.GetHolder<JSObject>().is_identical_to(holder)) {
2827 : DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2828 0 : it.Next();
2829 : }
2830 : // Skip past the interceptor.
2831 55316 : it.Next();
2832 110632 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2833 :
2834 55304 : if (it.IsFound()) return *result;
2835 :
2836 6437 : Handle<Smi> slot = args.at<Smi>(3);
2837 6437 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2838 6437 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2839 6437 : FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2840 : // It could actually be any kind of load IC slot here but the predicate
2841 : // handles all the cases properly.
2842 6437 : if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
2843 : return ReadOnlyRoots(isolate).undefined_value();
2844 : }
2845 :
2846 : // Throw a reference error.
2847 396 : THROW_NEW_ERROR_RETURN_FAILURE(
2848 134144 : isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
2849 : }
2850 :
2851 :
2852 546346 : RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
2853 546346 : HandleScope scope(isolate);
2854 : DCHECK_EQ(5, args.length());
2855 : // Runtime functions don't follow the IC's calling convention.
2856 546346 : Handle<Object> value = args.at(0);
2857 546346 : Handle<Smi> slot = args.at<Smi>(1);
2858 546346 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2859 546346 : Handle<JSObject> receiver = args.at<JSObject>(3);
2860 546346 : Handle<Name> name = args.at<Name>(4);
2861 546346 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2862 546346 : LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
2863 :
2864 : // TODO(ishell): Cache interceptor_holder in the store handler like we do
2865 : // for LoadHandler::kInterceptor case.
2866 : Handle<JSObject> interceptor_holder = receiver;
2867 1092692 : if (receiver->IsJSGlobalProxy()) {
2868 294 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2869 294 : if (IsStoreGlobalICKind(kind)) {
2870 294 : interceptor_holder = Handle<JSObject>::cast(isolate->global_object());
2871 : }
2872 : }
2873 : DCHECK(interceptor_holder->HasNamedInterceptor());
2874 : Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
2875 1092692 : isolate);
2876 :
2877 : DCHECK(!interceptor->non_masking());
2878 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2879 1639038 : *receiver, kDontThrow);
2880 :
2881 546346 : Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
2882 546346 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2883 546340 : if (!result.is_null()) return *value;
2884 :
2885 300294 : LookupIterator it(receiver, name, receiver);
2886 : // Skip past any access check on the receiver.
2887 300294 : if (it.state() == LookupIterator::ACCESS_CHECK) {
2888 : DCHECK(it.HasAccess());
2889 288 : it.Next();
2890 : }
2891 : // Skip past the interceptor on the receiver.
2892 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2893 300294 : it.Next();
2894 :
2895 300294 : MAYBE_RETURN(
2896 : Object::SetProperty(&it, value, language_mode, StoreOrigin::kNamed),
2897 : ReadOnlyRoots(isolate).exception());
2898 546346 : return *value;
2899 : }
2900 :
2901 :
2902 2238 : RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2903 : // TODO(verwaest): This should probably get the holder and receiver as input.
2904 2238 : HandleScope scope(isolate);
2905 2238 : Handle<JSObject> receiver = args.at<JSObject>(0);
2906 : DCHECK_GE(args.smi_at(1), 0);
2907 2238 : uint32_t index = args.smi_at(1);
2908 :
2909 : Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
2910 4476 : isolate);
2911 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2912 6714 : *receiver, kDontThrow);
2913 2238 : Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
2914 :
2915 2238 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2916 :
2917 2238 : if (result.is_null()) {
2918 0 : LookupIterator it(isolate, receiver, index, receiver);
2919 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2920 0 : it.Next();
2921 0 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2922 : Object::GetProperty(&it));
2923 : }
2924 :
2925 2238 : return *result;
2926 : }
2927 : } // namespace internal
2928 183867 : } // namespace v8
|