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 7114909 : void IC::TraceIC(const char* type, Handle<Object> name) {
89 7114909 : if (FLAG_ic_stats) {
90 7114909 : if (AddressIsDeoptimizedCode()) return;
91 0 : State new_state = nexus()->ic_state();
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 7383612 : 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 14767224 : 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 7383645 : 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 7383645 : reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
180 7383645 : 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 14767290 : Memory<intptr_t>(fp + TypedFrameConstants::kFrameTypeOffset);
194 7383645 : if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) {
195 6409884 : fp = Memory<Address>(fp + TypedFrameConstants::kCallerFPOffset);
196 : }
197 7383645 : fp_ = fp;
198 : if (FLAG_enable_embedded_constant_pool) {
199 : constant_pool_address_ = constant_pool;
200 : }
201 7383645 : pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
202 : DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind());
203 7383645 : state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.ic_state();
204 7383638 : old_state_ = state_;
205 7383638 : }
206 :
207 10768546 : 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 2765440 : StackFrameIterator it(isolate());
212 10768554 : 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 5530919 : return frame->function();
217 : }
218 :
219 7097776 : static void LookupForRead(Isolate* isolate, LookupIterator* it) {
220 7122126 : for (; it->IsFound(); it->Next()) {
221 3313258 : 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 3699 : 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 48826 : 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 601520 : bool IC::ShouldRecomputeHandler(Handle<String> name) {
250 378686 : if (!RecomputeHandlerForName(name)) return false;
251 :
252 : // This is a contextual access, always just update the handler and stay
253 : // monomorphic.
254 370753 : if (IsGlobalIC()) return true;
255 :
256 341904 : 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 341905 : if (maybe_handler_.is_null()) {
264 329391 : if (!receiver_map()->IsJSObjectMap()) return false;
265 321674 : Map first_map = FirstTargetMap();
266 321674 : if (first_map.is_null()) return false;
267 : Handle<Map> old_map(first_map, isolate());
268 222834 : if (old_map->is_deprecated()) return true;
269 : return IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
270 438176 : receiver_map()->elements_kind());
271 : }
272 :
273 : return true;
274 : }
275 :
276 378686 : bool IC::RecomputeHandlerForName(Handle<Object> name) {
277 378686 : if (is_keyed()) {
278 : // Determine whether the failure is due to a name failure.
279 27148 : if (!name->IsName()) return false;
280 9607 : Name stub_name = nexus()->GetName();
281 9607 : if (*name != stub_name) return false;
282 : }
283 :
284 : return true;
285 : }
286 :
287 :
288 14471982 : void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
289 7223263 : if (state() == NO_FEEDBACK) return;
290 7223269 : update_receiver_map(receiver);
291 14446559 : if (!name->IsString()) return;
292 6869916 : if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
293 757605 : 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 378686 : if (ShouldRecomputeHandler(Handle<String>::cast(name))) {
299 : MarkRecomputeHandler(name);
300 : }
301 : }
302 :
303 1367 : MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object,
304 2734 : Handle<Object> key) {
305 : HandleScope scope(isolate());
306 2734 : THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
307 : }
308 :
309 :
310 344656 : MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
311 : HandleScope scope(isolate());
312 344656 : THROW_NEW_ERROR(
313 : isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object);
314 : }
315 :
316 : // static
317 2765454 : void IC::OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus,
318 : JSFunction host_function, const char* reason) {
319 2765454 : FeedbackVector vector = nexus->vector();
320 2765451 : FeedbackSlot slot = nexus->slot();
321 2765451 : OnFeedbackChanged(isolate, vector, slot, host_function, reason);
322 2765450 : }
323 :
324 : // static
325 5585680 : void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector vector,
326 : FeedbackSlot slot, JSFunction host_function,
327 : const char* reason) {
328 2792840 : 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 2792840 : }
368 :
369 7407401 : static bool MigrateDeprecated(Handle<Object> object) {
370 14814810 : if (!object->IsJSObject()) return false;
371 7303968 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
372 7303966 : if (!receiver->map()->is_deprecated()) return false;
373 1457 : JSObject::MigrateInstance(Handle<JSObject>::cast(object));
374 1457 : return true;
375 : }
376 :
377 89812 : 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 89812 : nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
385 44906 : vector_set_ = true;
386 89812 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Megamorphic");
387 44906 : return changed;
388 : }
389 :
390 1290254 : void IC::ConfigureVectorState(Handle<Map> map) {
391 645123 : nexus()->ConfigurePremonomorphic(map);
392 645128 : vector_set_ = true;
393 1290259 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Premonomorphic");
394 645129 : }
395 :
396 0 : void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
397 : Handle<Object> handler) {
398 320449 : ConfigureVectorState(name, map, MaybeObjectHandle(handler));
399 0 : }
400 :
401 1847219 : void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
402 3694475 : const MaybeObjectHandle& handler) {
403 1847219 : if (IsGlobalIC()) {
404 44550 : nexus()->ConfigureHandlerMode(handler);
405 : } else {
406 : // Non-keyed ICs don't track the name explicitly.
407 1802669 : if (!is_keyed()) name = Handle<Name>::null();
408 1802669 : nexus()->ConfigureMonomorphic(name, map, handler);
409 : }
410 :
411 1847236 : vector_set_ = true;
412 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(),
413 3694475 : IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
414 1847235 : }
415 :
416 228180 : void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
417 228181 : MaybeObjectHandles* handlers) {
418 : DCHECK(!IsGlobalIC());
419 : // Non-keyed ICs don't track the name explicitly.
420 228180 : if (!is_keyed()) name = Handle<Name>::null();
421 228180 : nexus()->ConfigurePolymorphic(name, maps, handlers);
422 :
423 228181 : vector_set_ = true;
424 456362 : OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Polymorphic");
425 228181 : }
426 :
427 3537715 : MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
428 15468725 : 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 7075444 : if (object->IsNullOrUndefined(isolate())) {
433 2010 : if (use_ic && state() != PREMONOMORPHIC) {
434 : // Ensure the IC state progresses.
435 942 : TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
436 942 : update_receiver_map(object);
437 942 : PatchCache(name, slow_stub());
438 942 : TraceIC("LoadIC", name);
439 : }
440 :
441 1005 : if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
442 177 : return Runtime::ThrowIteratorError(isolate(), object);
443 : }
444 828 : return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
445 : }
446 :
447 3536717 : if (MigrateDeprecated(object)) use_ic = false;
448 :
449 3536706 : if (state() != UNINITIALIZED) {
450 1242460 : JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
451 1242462 : update_receiver_map(object);
452 : }
453 : // Named lookup in the object.
454 3536710 : LookupIterator it(isolate(), object, name);
455 3536714 : LookupForRead(isolate(), &it);
456 :
457 3536716 : if (name->IsPrivate()) {
458 15518 : if (name->IsPrivateName() && !it.IsFound()) {
459 : Handle<String> name_string(String::cast(Symbol::cast(*name)->name()),
460 : isolate());
461 : return TypeError(MessageTemplate::kInvalidPrivateFieldRead, object,
462 307 : name_string);
463 : }
464 :
465 : // IC handling of private symbols/fields lookup on JSProxy is not
466 : // supported.
467 30422 : if (object->IsJSProxy()) {
468 : use_ic = false;
469 : }
470 : }
471 :
472 3783906 : if (it.IsFound() || !ShouldThrowReferenceError()) {
473 : // Update inline cache and stub cache.
474 3364720 : if (use_ic) UpdateCaches(&it);
475 :
476 : // Get the property.
477 : Handle<Object> result;
478 :
479 6729451 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
480 : Object);
481 3363631 : if (it.IsFound()) {
482 3287592 : return result;
483 76039 : } else if (!ShouldThrowReferenceError()) {
484 75926 : LOG(isolate(), SuspectReadEvent(*name, *object));
485 75926 : return result;
486 : }
487 : }
488 171799 : return ReferenceError(name);
489 : }
490 :
491 2251208 : MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
492 6976599 : Handle<JSGlobalObject> global = isolate()->global_object();
493 :
494 4502418 : if (name->IsString()) {
495 : // Look up in script context table.
496 2251208 : Handle<String> str_name = Handle<String>::cast(name);
497 : Handle<ScriptContextTable> script_contexts(
498 4502410 : global->native_context()->script_context_table(), isolate());
499 :
500 : ScriptContextTable::LookupResult lookup_result;
501 2251206 : if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
502 : &lookup_result)) {
503 : Handle<Context> script_context = ScriptContextTable::GetContext(
504 111746 : isolate(), script_contexts, lookup_result.context_index);
505 :
506 : Handle<Object> result(script_context->get(lookup_result.slot_index),
507 167619 : isolate());
508 :
509 111745 : 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 55357 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
516 55357 : if (use_ic) {
517 55358 : if (nexus()->ConfigureLexicalVarMode(
518 : lookup_result.context_index, lookup_result.slot_index,
519 55358 : lookup_result.mode == VariableMode::kConst)) {
520 55357 : TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
521 : } else {
522 : // Given combination of indices can't be encoded, so use slow stub.
523 0 : TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
524 0 : PatchCache(name, slow_stub());
525 : }
526 55357 : TraceIC("LoadGlobalIC", name);
527 : }
528 55356 : return result;
529 : }
530 : }
531 2195335 : return LoadIC::Load(global, name);
532 : }
533 :
534 23216 : static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
535 : Handle<Map> new_receiver_map) {
536 : DCHECK(!new_receiver_map.is_null());
537 82906 : for (Handle<Map> map : *receiver_maps) {
538 80278 : if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
539 : return false;
540 : }
541 : }
542 19551 : receiver_maps->push_back(new_receiver_map);
543 19551 : return true;
544 : }
545 :
546 354491 : bool IC::UpdatePolymorphicIC(Handle<Name> name,
547 111947 : const MaybeObjectHandle& handler) {
548 : DCHECK(IsHandler(*handler));
549 367284 : if (is_keyed() && state() != RECOMPUTE_HANDLER) {
550 25294 : if (nexus()->GetName() != *name) return false;
551 : }
552 346230 : Handle<Map> map = receiver_map();
553 : MapHandles maps;
554 : MaybeObjectHandles handlers;
555 :
556 346230 : TargetMaps(&maps);
557 692466 : int number_of_maps = static_cast<int>(maps.size());
558 : int deprecated_maps = 0;
559 : int handler_to_overwrite = -1;
560 346233 : if (!nexus()->FindHandlers(&handlers, number_of_maps)) return false;
561 :
562 397457 : for (int i = 0; i < number_of_maps; i++) {
563 794985 : Handle<Map> current_map = maps.at(i);
564 397493 : if (current_map->is_deprecated()) {
565 : // Filter out deprecated maps to ensure their instances get migrated.
566 5252 : ++deprecated_maps;
567 392241 : } else if (map.is_identical_to(current_map)) {
568 : // If both map and handler stayed the same (and the name is also the
569 : // same as checked above, for keyed accesses), we're not progressing
570 : // in the lattice and need to go MEGAMORPHIC instead. There's one
571 : // exception to this rule, which is when we're in RECOMPUTE_HANDLER
572 : // state, there we allow to migrate to a new handler.
573 24189 : if (handler.is_identical_to(handlers[i]) &&
574 : state() != RECOMPUTE_HANDLER) {
575 : return false;
576 : }
577 : // If the receiver type is already in the polymorphic IC, this indicates
578 : // there was a prototoype chain failure. In that case, just overwrite the
579 : // handler.
580 : handler_to_overwrite = i;
581 759808 : } else if (handler_to_overwrite == -1 &&
582 379505 : IsTransitionOfMonomorphicTarget(*current_map, *map)) {
583 : handler_to_overwrite = i;
584 : }
585 : }
586 :
587 : int number_of_valid_maps =
588 345911 : number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
589 :
590 345911 : if (number_of_valid_maps >= FLAG_max_polymorphic_map_count) return false;
591 431611 : if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
592 : return false;
593 : }
594 :
595 : number_of_valid_maps++;
596 332768 : if (number_of_valid_maps == 1) {
597 121409 : ConfigureVectorState(name, receiver_map(), handler);
598 : } else {
599 218485 : if (is_keyed() && nexus()->GetName() != *name) return false;
600 211358 : if (handler_to_overwrite >= 0) {
601 3150 : handlers[handler_to_overwrite] = handler;
602 1575 : if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
603 1188 : maps[handler_to_overwrite] = map;
604 : }
605 : } else {
606 209783 : maps.push_back(map);
607 209784 : handlers.push_back(handler);
608 : }
609 :
610 211359 : ConfigureVectorState(name, maps, &handlers);
611 : }
612 :
613 : return true;
614 : }
615 :
616 0 : void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
617 : Handle<Name> name) {
618 : DCHECK(IsHandler(*handler));
619 1404831 : ConfigureVectorState(name, receiver_map(), handler);
620 0 : }
621 :
622 :
623 12709 : void IC::CopyICToMegamorphicCache(Handle<Name> name) {
624 : MapHandles maps;
625 : MaybeObjectHandles handlers;
626 12709 : TargetMaps(&maps);
627 38127 : if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return;
628 112178 : for (int i = 0; i < static_cast<int>(maps.size()); i++) {
629 99750 : UpdateMegamorphicCache(maps.at(i), name, handlers.at(i));
630 : }
631 : }
632 :
633 402888 : bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) {
634 386924 : if (source_map.is_null()) return true;
635 386924 : if (target_map.is_null()) return false;
636 386924 : if (source_map->is_abandoned_prototype_map()) return false;
637 : ElementsKind target_elements_kind = target_map->elements_kind();
638 : bool more_general_transition = IsMoreGeneralElementsKindTransition(
639 771126 : source_map->elements_kind(), target_elements_kind);
640 : Map transitioned_map;
641 385563 : if (more_general_transition) {
642 : MapHandles map_list;
643 47892 : map_list.push_back(handle(target_map, isolate_));
644 : transitioned_map =
645 15964 : source_map->FindElementsKindTransitionedMap(isolate(), map_list);
646 : }
647 385563 : return transitioned_map == target_map;
648 : }
649 :
650 0 : void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
651 1244665 : PatchCache(name, MaybeObjectHandle(handler));
652 0 : }
653 :
654 2398031 : void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
655 : DCHECK(IsHandler(*handler));
656 : // Currently only load and store ICs support non-code handlers.
657 : DCHECK(IsAnyLoad() || IsAnyStore());
658 2389015 : switch (state()) {
659 : case NO_FEEDBACK:
660 : break;
661 : case UNINITIALIZED:
662 : case PREMONOMORPHIC:
663 : UpdateMonomorphicIC(handler, name);
664 : break;
665 : case RECOMPUTE_HANDLER:
666 : case MONOMORPHIC:
667 232455 : if (IsGlobalIC()) {
668 : UpdateMonomorphicIC(handler, name);
669 : break;
670 : }
671 : V8_FALLTHROUGH;
672 : case POLYMORPHIC:
673 354491 : if (UpdatePolymorphicIC(name, handler)) break;
674 30741 : if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
675 12709 : CopyICToMegamorphicCache(name);
676 : }
677 21725 : ConfigureVectorState(MEGAMORPHIC, name);
678 : V8_FALLTHROUGH;
679 : case MEGAMORPHIC:
680 651425 : UpdateMegamorphicCache(receiver_map(), name, handler);
681 : // Indicate that we've handled this case.
682 651425 : vector_set_ = true;
683 651425 : break;
684 : case GENERIC:
685 0 : UNREACHABLE();
686 : break;
687 : }
688 2389032 : }
689 :
690 8650300 : void LoadIC::UpdateCaches(LookupIterator* lookup) {
691 8823391 : if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
692 : // This is the first time we execute this inline cache. Set the target to
693 : // the pre monomorphic stub to delay setting the monomorphic state.
694 99000 : TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
695 98992 : ConfigureVectorState(receiver_map());
696 98992 : TraceIC("LoadIC", lookup->name());
697 98992 : return;
698 : }
699 :
700 : Handle<Object> code;
701 3264291 : if (lookup->state() == LookupIterator::ACCESS_CHECK) {
702 35 : code = slow_stub();
703 3264256 : } else if (!lookup->IsFound()) {
704 73851 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
705 73851 : Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
706 : code = LoadHandler::LoadFullChain(
707 : isolate(), receiver_map(),
708 73851 : MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
709 : } else {
710 3190405 : if (IsLoadGlobalIC()) {
711 2022727 : if (lookup->TryLookupCachedProperty()) {
712 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
713 : }
714 4043763 : if (lookup->state() == LookupIterator::DATA &&
715 : lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
716 : DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
717 : // Now update the cell in the feedback vector.
718 2020604 : nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
719 2020608 : TraceIC("LoadGlobalIC", lookup->name());
720 2020606 : return;
721 : }
722 : }
723 1169800 : code = ComputeHandler(lookup);
724 : }
725 :
726 1243683 : PatchCache(lookup->name(), code);
727 1243698 : TraceIC("LoadIC", lookup->name());
728 : }
729 :
730 701300 : StubCache* IC::stub_cache() {
731 701300 : if (IsAnyLoad()) {
732 317274 : return isolate()->load_stub_cache();
733 : } else {
734 : DCHECK(IsAnyStore());
735 384026 : return isolate()->store_stub_cache();
736 : }
737 : }
738 :
739 701300 : void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
740 : const MaybeObjectHandle& handler) {
741 1402600 : stub_cache()->Set(*name, *map, *handler);
742 701300 : }
743 :
744 0 : void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
745 : DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
746 0 : if (V8_LIKELY(!FLAG_runtime_stats)) return;
747 0 : if (IsAnyLoad()) {
748 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
749 : } else {
750 : DCHECK(IsAnyStore());
751 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
752 : }
753 : }
754 :
755 3464935 : Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
756 : Handle<Object> receiver = lookup->GetReceiver();
757 3015610 : ReadOnlyRoots roots(isolate());
758 2376617 : if (receiver->IsString() && *lookup->name() == roots.length_string()) {
759 9721 : TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
760 9721 : return BUILTIN_CODE(isolate(), LoadIC_StringLength);
761 : }
762 :
763 2322250 : if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) {
764 81 : TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
765 81 : return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
766 : }
767 :
768 : // Use specialized code for getting prototype of functions.
769 3561894 : if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() &&
770 1173712 : !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
771 : Handle<Code> stub;
772 12460 : TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
773 12460 : return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
774 : }
775 :
776 1147559 : Handle<Map> map = receiver_map();
777 : Handle<JSObject> holder;
778 : bool receiver_is_holder;
779 1147559 : if (lookup->state() != LookupIterator::JSPROXY) {
780 : holder = lookup->GetHolder<JSObject>();
781 : receiver_is_holder = receiver.is_identical_to(holder);
782 : }
783 :
784 1147555 : switch (lookup->state()) {
785 : case LookupIterator::INTERCEPTOR: {
786 791 : Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
787 :
788 791 : if (holder->GetNamedInterceptor()->non_masking()) {
789 : MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
790 72 : if (!receiver_is_holder || IsLoadGlobalIC()) {
791 24 : holder_ref = MaybeObjectHandle::Weak(holder);
792 : }
793 48 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
794 : return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
795 48 : smi_handler);
796 : }
797 :
798 743 : if (receiver_is_holder) {
799 : DCHECK(map->has_named_interceptor());
800 636 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
801 636 : return smi_handler;
802 : }
803 :
804 107 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
805 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
806 107 : smi_handler);
807 : }
808 :
809 : case LookupIterator::ACCESSOR: {
810 : // Use simple field loads for some well-known callback properties.
811 : // The method will only return true for absolute truths based on the
812 : // receiver maps.
813 : FieldIndex index;
814 153181 : if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
815 : &index)) {
816 58689 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
817 58689 : return LoadHandler::LoadField(isolate(), index);
818 : }
819 188983 : if (holder->IsJSModuleNamespace()) {
820 : Handle<ObjectHashTable> exports(
821 59547 : Handle<JSModuleNamespace>::cast(holder)->module()->exports(),
822 39698 : isolate());
823 39698 : int entry = exports->FindEntry(roots, lookup->name(),
824 59547 : Smi::ToInt(lookup->name()->GetHash()));
825 : // We found the accessor, so the entry must exist.
826 : DCHECK_NE(entry, ObjectHashTable::kNotFound);
827 : int index = ObjectHashTable::EntryToValueIndex(entry);
828 19849 : return LoadHandler::LoadModuleExport(isolate(), index);
829 : }
830 :
831 74642 : Handle<Object> accessors = lookup->GetAccessors();
832 149286 : if (accessors->IsAccessorPair()) {
833 68453 : if (lookup->TryLookupCachedProperty()) {
834 : DCHECK_EQ(LookupIterator::DATA, lookup->state());
835 20 : return ComputeHandler(lookup);
836 : }
837 :
838 : Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
839 : isolate());
840 137921 : if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
841 270 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
842 270 : return slow_stub();
843 : }
844 :
845 204746 : if (getter->IsFunctionTemplateInfo() &&
846 68421 : FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) {
847 : // Do not install an IC if the api function has a breakpoint.
848 10 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
849 10 : return slow_stub();
850 : }
851 :
852 : Handle<Smi> smi_handler;
853 :
854 68153 : CallOptimization call_optimization(isolate(), getter);
855 68153 : if (call_optimization.is_simple_api_call()) {
856 10811 : if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
857 10705 : !holder->HasFastProperties()) {
858 69 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
859 69 : return slow_stub();
860 : }
861 :
862 : CallOptimization::HolderLookup holder_lookup;
863 3535 : call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
864 :
865 : smi_handler = LoadHandler::LoadApiGetter(
866 7070 : isolate(), holder_lookup == CallOptimization::kHolderIsReceiver);
867 :
868 : Handle<Context> context(
869 3535 : call_optimization.GetAccessorContext(holder->map()), isolate());
870 :
871 3539 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
872 : return LoadHandler::LoadFromPrototype(
873 : isolate(), map, holder, smi_handler,
874 : MaybeObjectHandle::Weak(call_optimization.api_call_info()),
875 3535 : MaybeObjectHandle::Weak(context));
876 : }
877 :
878 64549 : if (holder->HasFastProperties()) {
879 : smi_handler =
880 118760 : LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
881 :
882 59380 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
883 59380 : if (receiver_is_holder) return smi_handler;
884 44452 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
885 10338 : } else if (holder->IsJSGlobalObject()) {
886 937 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
887 937 : smi_handler = LoadHandler::LoadGlobal(isolate());
888 : return LoadHandler::LoadFromPrototype(
889 : isolate(), map, holder, smi_handler,
890 1874 : MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
891 : } else {
892 4232 : smi_handler = LoadHandler::LoadNormal(isolate());
893 :
894 4232 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
895 4232 : if (receiver_is_holder) return smi_handler;
896 63 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
897 : }
898 :
899 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
900 44515 : smi_handler);
901 : }
902 :
903 6190 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
904 :
905 18570 : if (v8::ToCData<Address>(info->getter()) == kNullAddress ||
906 12368 : !AccessorInfo::IsCompatibleReceiverMap(info, map) ||
907 24160 : !holder->HasFastProperties() ||
908 6282 : (info->is_sloppy() && !receiver->IsJSReceiver())) {
909 588 : TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
910 588 : return slow_stub();
911 : }
912 :
913 : Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
914 11204 : isolate(), lookup->GetAccessorIndex());
915 5606 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
916 5602 : if (receiver_is_holder) return smi_handler;
917 303 : TRACE_HANDLER_STATS(isolate(),
918 : LoadIC_LoadNativeDataPropertyFromPrototypeDH);
919 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
920 303 : smi_handler);
921 : }
922 :
923 : case LookupIterator::DATA: {
924 : DCHECK_EQ(kData, lookup->property_details().kind());
925 : Handle<Smi> smi_handler;
926 988486 : if (lookup->is_dictionary_holder()) {
927 36012 : if (holder->IsJSGlobalObject()) {
928 : // TODO(verwaest): Also supporting the global object as receiver is a
929 : // workaround for code that leaks the global object.
930 11761 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
931 11761 : smi_handler = LoadHandler::LoadGlobal(isolate());
932 : return LoadHandler::LoadFromPrototype(
933 : isolate(), map, holder, smi_handler,
934 23522 : MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
935 : }
936 :
937 6245 : smi_handler = LoadHandler::LoadNormal(isolate());
938 6245 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
939 6245 : if (receiver_is_holder) return smi_handler;
940 3715 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
941 :
942 970482 : } else if (lookup->property_details().location() == kField) {
943 970482 : FieldIndex field = lookup->GetFieldIndex();
944 970485 : smi_handler = LoadHandler::LoadField(isolate(), field);
945 970484 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
946 970483 : if (receiver_is_holder) return smi_handler;
947 297993 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
948 : } else {
949 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
950 : smi_handler =
951 0 : LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
952 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
953 0 : if (receiver_is_holder) return smi_handler;
954 0 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
955 : }
956 : return LoadHandler::LoadFromPrototype(isolate(), map, holder,
957 301708 : smi_handler);
958 : }
959 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
960 45 : TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
961 45 : return LoadHandler::LoadNonExistent(isolate());
962 : case LookupIterator::JSPROXY: {
963 : Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
964 : bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy);
965 5052 : Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
966 5052 : if (receiver_is_holder_proxy) {
967 4277 : return smi_handler;
968 : }
969 : return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
970 775 : smi_handler);
971 : }
972 : case LookupIterator::ACCESS_CHECK:
973 : case LookupIterator::NOT_FOUND:
974 : case LookupIterator::TRANSITION:
975 0 : UNREACHABLE();
976 : }
977 :
978 0 : return Handle<Code>::null();
979 : }
980 :
981 373173 : static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
982 : // This helper implements a few common fast cases for converting
983 : // non-smi keys of keyed loads/stores to a smi or a string.
984 746346 : if (key->IsHeapNumber()) {
985 3896 : double value = Handle<HeapNumber>::cast(key)->value();
986 1948 : if (std::isnan(value)) {
987 : key = isolate->factory()->NaN_string();
988 : } else {
989 : // Check bounds first to avoid undefined behavior in the conversion
990 : // to int.
991 1690 : if (value <= Smi::kMaxValue && value >= Smi::kMinValue) {
992 : int int_value = FastD2I(value);
993 776 : if (value == int_value) {
994 : key = handle(Smi::FromInt(int_value), isolate);
995 : }
996 : }
997 : }
998 742450 : } else if (key->IsString()) {
999 43907 : key = isolate->factory()->InternalizeString(Handle<String>::cast(key));
1000 : }
1001 373173 : return key;
1002 : }
1003 :
1004 521 : bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) {
1005 521 : const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map);
1006 521 : if (handler.is_null()) return false;
1007 521 : return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD;
1008 : }
1009 :
1010 137347 : void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
1011 : KeyedAccessLoadMode load_mode) {
1012 155791 : Handle<Map> receiver_map(receiver->map(), isolate());
1013 : DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
1014 : MapHandles target_receiver_maps;
1015 137347 : TargetMaps(&target_receiver_maps);
1016 :
1017 137347 : if (target_receiver_maps.empty()) {
1018 118840 : Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1019 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1020 : }
1021 :
1022 79572 : for (Handle<Map> map : target_receiver_maps) {
1023 30564 : if (map.is_null()) continue;
1024 30564 : if (map->instance_type() == JS_VALUE_TYPE) {
1025 : set_slow_stub_reason("JSValue");
1026 : return;
1027 : }
1028 30555 : if (map->instance_type() == JS_PROXY_TYPE) {
1029 : set_slow_stub_reason("JSProxy");
1030 : return;
1031 : }
1032 : }
1033 :
1034 : // The first time a receiver is seen that is a transitioned version of the
1035 : // previous monomorphic receiver type, assume the new ElementsKind is the
1036 : // monomorphic type. This benefits global arrays that only transition
1037 : // once, and all call sites accessing them are faster if they remain
1038 : // monomorphic. If this optimistic assumption is not true, the IC will
1039 : // miss again and it will become polymorphic and support both the
1040 : // untransitioned and transitioned maps.
1041 53853 : if (state() == MONOMORPHIC && !receiver->IsString() &&
1042 60258 : !receiver->IsJSProxy() &&
1043 : IsMoreGeneralElementsKindTransition(
1044 : target_receiver_maps.at(0)->elements_kind(),
1045 53499 : Handle<JSObject>::cast(receiver)->GetElementsKind())) {
1046 2618 : Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
1047 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1048 : }
1049 :
1050 : DCHECK(state() != GENERIC);
1051 :
1052 : // Determine the list of receiver maps that this call site has seen,
1053 : // adding the map that was just encountered.
1054 15826 : if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1055 : // If the {receiver_map} previously had a handler that didn't handle
1056 : // out-of-bounds access, but can generally handle it, we can just go
1057 : // on and update the handler appropriately below.
1058 2459 : if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS ||
1059 521 : !CanChangeToAllowOutOfBounds(receiver_map)) {
1060 : // If the miss wasn't due to an unseen map, a polymorphic stub
1061 : // won't help, use the generic stub.
1062 : set_slow_stub_reason("same map added twice");
1063 : return;
1064 : }
1065 : }
1066 :
1067 : // If the maximum number of receiver maps has been exceeded, use the generic
1068 : // version of the IC.
1069 28792 : if (target_receiver_maps.size() > kMaxKeyedPolymorphism) {
1070 : set_slow_stub_reason("max polymorph exceeded");
1071 : return;
1072 : }
1073 :
1074 : MaybeObjectHandles handlers;
1075 12625 : handlers.reserve(target_receiver_maps.size());
1076 12625 : LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1077 : DCHECK_LE(1, target_receiver_maps.size());
1078 25250 : if (target_receiver_maps.size() == 1) {
1079 1020 : ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1080 : } else {
1081 12115 : ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1082 : }
1083 : }
1084 :
1085 : namespace {
1086 :
1087 26378 : bool AllowConvertHoleElementToUndefined(Isolate* isolate,
1088 : Handle<Map> receiver_map) {
1089 26378 : if (receiver_map->IsJSTypedArrayMap()) {
1090 : // For JSTypedArray we never lookup elements in the prototype chain.
1091 : return true;
1092 : }
1093 :
1094 : // For other {receiver}s we need to check the "no elements" protector.
1095 25439 : if (isolate->IsNoElementsProtectorIntact()) {
1096 21632 : if (receiver_map->IsStringMap()) {
1097 : return true;
1098 : }
1099 21495 : if (receiver_map->IsJSObjectMap()) {
1100 : // For other JSObjects (including JSArrays) we can only continue if
1101 : // the {receiver}s prototype is either the initial Object.prototype
1102 : // or the initial Array.prototype, which are both guarded by the
1103 : // "no elements" protector checked above.
1104 : Handle<Object> receiver_prototype(receiver_map->prototype(), isolate);
1105 :
1106 21495 : if (isolate->IsInAnyContext(*receiver_prototype,
1107 28854 : Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1108 : isolate->IsInAnyContext(*receiver_prototype,
1109 7359 : Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
1110 : return true;
1111 : }
1112 : }
1113 : }
1114 :
1115 : return false;
1116 : }
1117 : } // namespace
1118 :
1119 152549 : Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
1120 : KeyedAccessLoadMode load_mode) {
1121 152657 : if (receiver_map->has_indexed_interceptor() &&
1122 152657 : !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
1123 479622 : isolate()) &&
1124 152633 : !receiver_map->GetIndexedInterceptor()->non_masking()) {
1125 : // TODO(jgruber): Update counter name.
1126 84 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1127 84 : return BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
1128 : }
1129 : InstanceType instance_type = receiver_map->instance_type();
1130 152465 : if (instance_type < FIRST_NONSTRING_TYPE) {
1131 1292 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1132 1292 : return LoadHandler::LoadIndexedString(isolate(), load_mode);
1133 : }
1134 151173 : if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1135 0 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1136 0 : return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
1137 : }
1138 151173 : if (instance_type == JS_PROXY_TYPE) {
1139 144 : return LoadHandler::LoadProxy(isolate());
1140 : }
1141 :
1142 : ElementsKind elements_kind = receiver_map->elements_kind();
1143 151029 : if (IsSloppyArgumentsElementsKind(elements_kind)) {
1144 : // TODO(jgruber): Update counter name.
1145 1728 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1146 1728 : return BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
1147 : }
1148 149301 : bool is_js_array = instance_type == JS_ARRAY_TYPE;
1149 149301 : if (elements_kind == DICTIONARY_ELEMENTS) {
1150 4253 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1151 : return LoadHandler::LoadElement(isolate(), elements_kind, false,
1152 8506 : is_js_array, load_mode);
1153 : }
1154 : DCHECK(IsFastElementsKind(elements_kind) ||
1155 : IsFixedTypedArrayElementsKind(elements_kind));
1156 : bool convert_hole_to_undefined =
1157 290096 : (elements_kind == HOLEY_SMI_ELEMENTS ||
1158 311879 : elements_kind == HOLEY_ELEMENTS) &&
1159 21783 : AllowConvertHoleElementToUndefined(isolate(), receiver_map);
1160 145048 : TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1161 : return LoadHandler::LoadElement(isolate(), elements_kind,
1162 : convert_hole_to_undefined, is_js_array,
1163 290096 : load_mode);
1164 : }
1165 :
1166 12625 : void KeyedLoadIC::LoadElementPolymorphicHandlers(
1167 : MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1168 : KeyedAccessLoadMode load_mode) {
1169 : // Filter out deprecated maps to ensure their instances get migrated.
1170 : receiver_maps->erase(
1171 : std::remove_if(
1172 : receiver_maps->begin(), receiver_maps->end(),
1173 62234 : [](const Handle<Map>& map) { return map->is_deprecated(); }),
1174 12625 : receiver_maps->end());
1175 :
1176 56341 : for (Handle<Map> receiver_map : *receiver_maps) {
1177 : // Mark all stable receiver maps that have elements kind transition map
1178 : // among receiver_maps as unstable because the optimizing compilers may
1179 : // generate an elements kind transition for this kind of receivers.
1180 31091 : if (receiver_map->is_stable()) {
1181 : Map tmap = receiver_map->FindElementsKindTransitionedMap(isolate(),
1182 37436 : *receiver_maps);
1183 18709 : if (!tmap.is_null()) {
1184 18 : receiver_map->NotifyLeafMapLayoutChange(isolate());
1185 : }
1186 : }
1187 : handlers->push_back(
1188 62182 : MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode)));
1189 : }
1190 12625 : }
1191 :
1192 : namespace {
1193 :
1194 145979 : bool ConvertKeyToIndex(Handle<Object> receiver, Handle<Object> key,
1195 : uint32_t* index, InlineCacheState state) {
1196 145979 : if (!FLAG_use_ic || state == NO_FEEDBACK) return false;
1197 583694 : if (receiver->IsAccessCheckNeeded() || receiver->IsJSValue()) return false;
1198 :
1199 : // For regular JSReceiver or String receivers, the {key} must be a positive
1200 : // array index.
1201 296662 : if (receiver->IsJSReceiver() || receiver->IsString()) {
1202 287686 : if (key->ToArrayIndex(index)) return true;
1203 : }
1204 : // For JSTypedArray receivers, we can also support negative keys, which we
1205 : // just map into the [2**31, 2**32 - 1] range via a bit_cast. This is valid
1206 : // because JSTypedArray::length is always a Smi, so such keys will always
1207 : // be detected as OOB.
1208 16466 : if (receiver->IsJSTypedArray()) {
1209 : int32_t signed_index;
1210 377 : if (key->ToInt32(&signed_index)) {
1211 206 : *index = bit_cast<uint32_t>(signed_index);
1212 206 : return true;
1213 : }
1214 : }
1215 : return false;
1216 : }
1217 :
1218 439548 : bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) {
1219 439548 : uint32_t length = 0;
1220 879097 : if (receiver->IsJSArray()) {
1221 762017 : JSArray::cast(*receiver)->length()->ToArrayLength(&length);
1222 117080 : } else if (receiver->IsString()) {
1223 1228 : length = String::cast(*receiver)->length();
1224 114624 : } else if (receiver->IsJSObject()) {
1225 114246 : length = JSObject::cast(*receiver)->elements()->length();
1226 : } else {
1227 : return false;
1228 : }
1229 439359 : return index >= length;
1230 : }
1231 :
1232 137347 : KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
1233 : uint32_t index) {
1234 137347 : if (IsOutOfBoundsAccess(receiver, index)) {
1235 : DCHECK(receiver->IsHeapObject());
1236 9190 : Handle<Map> receiver_map(Handle<HeapObject>::cast(receiver)->map(),
1237 : isolate);
1238 4595 : if (AllowConvertHoleElementToUndefined(isolate, receiver_map)) {
1239 3165 : return LOAD_IGNORE_OUT_OF_BOUNDS;
1240 : }
1241 : }
1242 : return STANDARD_LOAD;
1243 : }
1244 :
1245 : } // namespace
1246 :
1247 214052 : MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
1248 : Handle<Object> key) {
1249 214052 : if (MigrateDeprecated(object)) {
1250 : Handle<Object> result;
1251 780827 : ASSIGN_RETURN_ON_EXCEPTION(
1252 : isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
1253 : Object);
1254 121 : return result;
1255 : }
1256 :
1257 : Handle<Object> load_handle;
1258 :
1259 : // Check for non-string values that can be converted into an
1260 : // internalized string directly or is representable as a smi.
1261 213931 : key = TryConvertKey(key, isolate());
1262 :
1263 : uint32_t index;
1264 463556 : if ((key->IsInternalizedString() &&
1265 646284 : !String::cast(*key)->AsArrayIndex(&index)) ||
1266 396659 : key->IsSymbol()) {
1267 135904 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1268 : LoadIC::Load(object, Handle<Name>::cast(key)),
1269 : Object);
1270 145979 : } else if (ConvertKeyToIndex(object, key, &index, state())) {
1271 274694 : KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index);
1272 137347 : UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode);
1273 137348 : if (is_vector_set()) {
1274 134084 : TraceIC("LoadIC", key);
1275 : }
1276 : }
1277 :
1278 213305 : if (vector_needs_update()) {
1279 11923 : ConfigureVectorState(MEGAMORPHIC, key);
1280 11923 : TraceIC("LoadIC", key);
1281 : }
1282 :
1283 213305 : if (!load_handle.is_null()) return load_handle;
1284 :
1285 : Handle<Object> result;
1286 291959 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
1287 : Runtime::GetObjectProperty(isolate(), object, key),
1288 : Object);
1289 145676 : return result;
1290 : }
1291 :
1292 8365926 : bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
1293 : StoreOrigin store_origin) {
1294 : // Disable ICs for non-JSObjects for now.
1295 : Handle<Object> object = it->GetReceiver();
1296 5576290 : if (object->IsJSProxy()) return true;
1297 5575959 : if (!object->IsJSObject()) return false;
1298 2787645 : Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1299 : DCHECK(!receiver->map()->is_deprecated());
1300 :
1301 2787645 : if (it->state() != LookupIterator::TRANSITION) {
1302 2792633 : for (; it->IsFound(); it->Next()) {
1303 2325872 : switch (it->state()) {
1304 : case LookupIterator::NOT_FOUND:
1305 : case LookupIterator::TRANSITION:
1306 0 : UNREACHABLE();
1307 : case LookupIterator::JSPROXY:
1308 : return true;
1309 : case LookupIterator::INTERCEPTOR: {
1310 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1311 295 : InterceptorInfo info = holder->GetNamedInterceptor();
1312 295 : if (it->HolderIsReceiverOrHiddenPrototype()) {
1313 741 : return !info->non_masking() && receiver.is_identical_to(holder) &&
1314 1364 : !info->setter()->IsUndefined(isolate());
1315 144 : } else if (!info->getter()->IsUndefined(isolate()) ||
1316 48 : !info->query()->IsUndefined(isolate())) {
1317 : return false;
1318 : }
1319 0 : break;
1320 : }
1321 : case LookupIterator::ACCESS_CHECK:
1322 5020 : if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1323 : break;
1324 : case LookupIterator::ACCESSOR:
1325 228793 : return !it->IsReadOnly();
1326 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1327 90 : return false;
1328 : case LookupIterator::DATA: {
1329 2093978 : if (it->IsReadOnly()) return false;
1330 : Handle<JSObject> holder = it->GetHolder<JSObject>();
1331 2080833 : if (receiver.is_identical_to(holder)) {
1332 2074939 : it->PrepareForDataProperty(value);
1333 : // The previous receiver map might just have been deprecated,
1334 : // so reload it.
1335 2074941 : update_receiver_map(receiver);
1336 2074942 : return true;
1337 : }
1338 :
1339 : // Receiver != holder.
1340 11788 : if (receiver->IsJSGlobalProxy()) {
1341 623 : PrototypeIterator iter(isolate(), receiver);
1342 : return it->GetHolder<Object>().is_identical_to(
1343 : PrototypeIterator::GetCurrent(iter));
1344 : }
1345 :
1346 5271 : if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1347 :
1348 5271 : if (it->ExtendingNonExtensible(receiver)) return false;
1349 : it->PrepareTransitionToDataProperty(receiver, value, NONE,
1350 5271 : store_origin);
1351 5271 : return it->IsCacheableTransition();
1352 : }
1353 : }
1354 : }
1355 : }
1356 :
1357 464266 : receiver = it->GetStoreTarget<JSObject>();
1358 464266 : if (it->ExtendingNonExtensible(receiver)) return false;
1359 464194 : it->PrepareTransitionToDataProperty(receiver, value, NONE, store_origin);
1360 464197 : return it->IsCacheableTransition();
1361 : }
1362 :
1363 1685911 : MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
1364 : Handle<Object> value) {
1365 : DCHECK(name->IsString());
1366 :
1367 : // Look up in script context table.
1368 1685911 : Handle<String> str_name = Handle<String>::cast(name);
1369 3372027 : Handle<JSGlobalObject> global = isolate()->global_object();
1370 : Handle<ScriptContextTable> script_contexts(
1371 3371822 : global->native_context()->script_context_table(), isolate());
1372 :
1373 : ScriptContextTable::LookupResult lookup_result;
1374 1685911 : if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
1375 : &lookup_result)) {
1376 : Handle<Context> script_context = ScriptContextTable::GetContext(
1377 140 : isolate(), script_contexts, lookup_result.context_index);
1378 70 : if (lookup_result.mode == VariableMode::kConst) {
1379 20 : return TypeError(MessageTemplate::kConstAssign, global, name);
1380 : }
1381 :
1382 : Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
1383 150 : isolate());
1384 :
1385 100 : if (previous_value->IsTheHole(isolate())) {
1386 : // Do not install stubs and stay pre-monomorphic for
1387 : // uninitialized accesses.
1388 15 : return ReferenceError(name);
1389 : }
1390 :
1391 35 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1392 35 : if (use_ic) {
1393 35 : if (nexus()->ConfigureLexicalVarMode(
1394 : lookup_result.context_index, lookup_result.slot_index,
1395 35 : lookup_result.mode == VariableMode::kConst)) {
1396 35 : TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1397 : } else {
1398 : // Given combination of indices can't be encoded, so use slow stub.
1399 0 : TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1400 0 : PatchCache(name, slow_stub());
1401 : }
1402 35 : TraceIC("StoreGlobalIC", name);
1403 : }
1404 :
1405 105 : script_context->set(lookup_result.slot_index, *value);
1406 35 : return value;
1407 : }
1408 :
1409 1685841 : return StoreIC::Store(global, name, value);
1410 : }
1411 :
1412 3334934 : MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
1413 : Handle<Object> value,
1414 : StoreOrigin store_origin) {
1415 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
1416 : // might deprecate the current map again, if value does not fit.
1417 3334934 : if (MigrateDeprecated(object)) {
1418 : Handle<Object> result;
1419 14470556 : ASSIGN_RETURN_ON_EXCEPTION(
1420 : isolate(), result, Object::SetProperty(isolate(), object, name, value),
1421 : Object);
1422 74 : return result;
1423 : }
1424 :
1425 3334860 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
1426 : // If the object is undefined or null it's illegal to try to set any
1427 : // properties on it; throw a TypeError in that case.
1428 6669720 : if (object->IsNullOrUndefined(isolate())) {
1429 80 : if (use_ic && state() != PREMONOMORPHIC) {
1430 : // Ensure the IC state progresses.
1431 40 : TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1432 40 : update_receiver_map(object);
1433 40 : PatchCache(name, slow_stub());
1434 40 : TraceIC("StoreIC", name);
1435 : }
1436 40 : return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
1437 : }
1438 :
1439 3334820 : if (state() != UNINITIALIZED) {
1440 1130834 : JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
1441 : }
1442 3334822 : LookupIterator it(isolate(), object, name);
1443 :
1444 3334822 : if (name->IsPrivate()) {
1445 1961 : if (name->IsPrivateName() && !it.IsFound()) {
1446 : Handle<String> name_string(String::cast(Symbol::cast(*name)->name()),
1447 : isolate());
1448 : return TypeError(MessageTemplate::kInvalidPrivateFieldWrite, object,
1449 172 : name_string);
1450 : }
1451 :
1452 : // IC handling of private fields/symbols stores on JSProxy is not
1453 : // supported.
1454 3578 : if (object->IsJSProxy()) {
1455 : use_ic = false;
1456 : }
1457 : }
1458 3334649 : if (use_ic) UpdateCaches(&it, value, store_origin);
1459 :
1460 3334656 : MAYBE_RETURN_NULL(Object::SetProperty(&it, value, store_origin));
1461 3320841 : return value;
1462 : }
1463 :
1464 5019672 : void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
1465 : StoreOrigin store_origin) {
1466 8326131 : if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
1467 : // This is the first time we execute this inline cache. Transition
1468 : // to premonomorphic state to delay setting the monomorphic state.
1469 546104 : TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
1470 546104 : ConfigureVectorState(receiver_map());
1471 546110 : TraceIC("StoreIC", lookup->name());
1472 2736002 : return;
1473 : }
1474 :
1475 : MaybeObjectHandle handler;
1476 2788144 : if (LookupForWrite(lookup, value, store_origin)) {
1477 2769299 : if (IsStoreGlobalIC()) {
1478 3328937 : if (lookup->state() == LookupIterator::DATA &&
1479 : lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1480 : DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
1481 : // Now update the cell in the feedback vector.
1482 1643766 : nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1483 1643766 : TraceIC("StoreGlobalIC", lookup->name());
1484 1643766 : return;
1485 : }
1486 : }
1487 1125533 : handler = ComputeHandler(lookup);
1488 : } else {
1489 19351 : if (state() == UNINITIALIZED && IsStoreGlobalIC() &&
1490 : lookup->state() == LookupIterator::INTERCEPTOR) {
1491 : InterceptorInfo info =
1492 89 : lookup->GetHolder<JSObject>()->GetNamedInterceptor();
1493 267 : if (!lookup->HolderIsReceiverOrHiddenPrototype() &&
1494 125 : !info->getter()->IsUndefined(isolate())) {
1495 : // Utilize premonomorphic state for global store ics that run into
1496 : // an interceptor because the property doesn't exist yet.
1497 : // After we actually set the property, we'll have more information.
1498 : // Premonomorphism gives us a chance to find more information the
1499 : // second time.
1500 18 : TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_Premonomorphic);
1501 18 : ConfigureVectorState(receiver_map());
1502 18 : TraceIC("StoreGlobalIC", lookup->name());
1503 18 : return;
1504 : }
1505 : }
1506 :
1507 : set_slow_stub_reason("LookupForWrite said 'false'");
1508 : // TODO(marja): change slow_stub to return MaybeObjectHandle.
1509 18827 : handler = MaybeObjectHandle(slow_stub());
1510 : }
1511 :
1512 1144357 : PatchCache(lookup->name(), handler);
1513 1144363 : TraceIC("StoreIC", lookup->name());
1514 : }
1515 :
1516 1125531 : MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
1517 1125531 : switch (lookup->state()) {
1518 : case LookupIterator::TRANSITION: {
1519 464531 : Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1520 929064 : if (store_target->IsJSGlobalObject()) {
1521 1592378 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1522 :
1523 83962 : if (receiver_map()->IsJSGlobalObject()) {
1524 : DCHECK(IsStoreGlobalIC());
1525 : #ifdef DEBUG
1526 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1527 : DCHECK_EQ(*lookup->GetReceiver(), *holder);
1528 : DCHECK_EQ(*store_target, *holder);
1529 : #endif
1530 0 : return StoreHandler::StoreGlobal(lookup->transition_cell());
1531 : }
1532 :
1533 41981 : Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
1534 : Handle<Object> handler = StoreHandler::StoreThroughPrototype(
1535 : isolate(), receiver_map(), store_target, smi_handler,
1536 41981 : MaybeObjectHandle::Weak(lookup->transition_cell()));
1537 41981 : return MaybeObjectHandle(handler);
1538 : }
1539 : // Dictionary-to-fast transitions are not expected and not supported.
1540 : DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
1541 : !receiver_map()->is_dictionary_map());
1542 :
1543 : DCHECK(lookup->IsCacheableTransition());
1544 :
1545 422550 : return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
1546 : }
1547 :
1548 : case LookupIterator::INTERCEPTOR: {
1549 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1550 : USE(holder);
1551 :
1552 : DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
1553 : // TODO(jgruber): Update counter name.
1554 170 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
1555 170 : return MaybeObjectHandle(BUILTIN_CODE(isolate(), StoreInterceptorIC));
1556 : }
1557 :
1558 : case LookupIterator::ACCESSOR: {
1559 : // This is currently guaranteed by checks in StoreIC::Store.
1560 228703 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1561 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1562 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1563 :
1564 228703 : if (!holder->HasFastProperties()) {
1565 : set_slow_stub_reason("accessor on slow map");
1566 506 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1567 506 : return MaybeObjectHandle(slow_stub());
1568 : }
1569 228197 : Handle<Object> accessors = lookup->GetAccessors();
1570 456394 : if (accessors->IsAccessorInfo()) {
1571 91219 : Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
1572 91219 : if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
1573 : set_slow_stub_reason("setter == kNullAddress");
1574 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1575 0 : return MaybeObjectHandle(slow_stub());
1576 : }
1577 182344 : if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
1578 91125 : !lookup->HolderIsReceiverOrHiddenPrototype()) {
1579 : set_slow_stub_reason("special data property in prototype chain");
1580 27 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1581 27 : return MaybeObjectHandle(slow_stub());
1582 : }
1583 91192 : if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) {
1584 : set_slow_stub_reason("incompatible receiver type");
1585 12 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1586 12 : return MaybeObjectHandle(slow_stub());
1587 : }
1588 :
1589 : Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
1590 182360 : isolate(), lookup->GetAccessorIndex());
1591 91180 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
1592 91180 : if (receiver.is_identical_to(holder)) {
1593 91142 : return MaybeObjectHandle(smi_handler);
1594 : }
1595 38 : TRACE_HANDLER_STATS(isolate(),
1596 : StoreIC_StoreNativeDataPropertyOnPrototypeDH);
1597 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1598 38 : isolate(), receiver_map(), holder, smi_handler));
1599 :
1600 273956 : } else if (accessors->IsAccessorPair()) {
1601 273956 : Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1602 : isolate());
1603 292244 : if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
1604 : set_slow_stub_reason("setter not a function");
1605 8898 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1606 8898 : return MaybeObjectHandle(slow_stub());
1607 : }
1608 :
1609 384486 : if (setter->IsFunctionTemplateInfo() &&
1610 128326 : FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) {
1611 : // Do not install an IC if the api function has a breakpoint.
1612 10 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1613 10 : return MaybeObjectHandle(slow_stub());
1614 : }
1615 :
1616 128070 : CallOptimization call_optimization(isolate(), setter);
1617 128070 : if (call_optimization.is_simple_api_call()) {
1618 399 : if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
1619 : CallOptimization::HolderLookup holder_lookup;
1620 : call_optimization.LookupHolderOfExpectedType(receiver_map(),
1621 351 : &holder_lookup);
1622 :
1623 : Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
1624 : isolate(),
1625 702 : holder_lookup == CallOptimization::kHolderIsReceiver);
1626 :
1627 : Handle<Context> context(
1628 351 : call_optimization.GetAccessorContext(holder->map()), isolate());
1629 351 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
1630 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1631 : isolate(), receiver_map(), holder, smi_handler,
1632 : MaybeObjectHandle::Weak(call_optimization.api_call_info()),
1633 351 : MaybeObjectHandle::Weak(context)));
1634 : }
1635 : set_slow_stub_reason("incompatible receiver");
1636 48 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1637 48 : return MaybeObjectHandle(slow_stub());
1638 255342 : } else if (setter->IsFunctionTemplateInfo()) {
1639 : set_slow_stub_reason("setter non-simple template");
1640 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1641 0 : return MaybeObjectHandle(slow_stub());
1642 : }
1643 :
1644 : Handle<Smi> smi_handler =
1645 255342 : StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex());
1646 :
1647 127671 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
1648 127671 : if (receiver.is_identical_to(holder)) {
1649 491 : return MaybeObjectHandle(smi_handler);
1650 : }
1651 127180 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
1652 :
1653 : return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
1654 127180 : isolate(), receiver_map(), holder, smi_handler));
1655 : }
1656 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1657 0 : return MaybeObjectHandle(slow_stub());
1658 : }
1659 :
1660 : case LookupIterator::DATA: {
1661 : // This is currently guaranteed by checks in StoreIC::Store.
1662 431756 : Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
1663 : USE(receiver);
1664 : Handle<JSObject> holder = lookup->GetHolder<JSObject>();
1665 : DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
1666 :
1667 : DCHECK_EQ(kData, lookup->property_details().kind());
1668 431756 : if (lookup->is_dictionary_holder()) {
1669 10136 : if (holder->IsJSGlobalObject()) {
1670 582 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
1671 : return MaybeObjectHandle(
1672 582 : StoreHandler::StoreGlobal(lookup->GetPropertyCell()));
1673 : }
1674 4486 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
1675 : DCHECK(holder.is_identical_to(receiver));
1676 4486 : return MaybeObjectHandle(StoreHandler::StoreNormal(isolate()));
1677 : }
1678 :
1679 : // -------------- Fields --------------
1680 426688 : if (lookup->property_details().location() == kField) {
1681 426688 : TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
1682 426688 : int descriptor = lookup->GetFieldDescriptorIndex();
1683 426688 : FieldIndex index = lookup->GetFieldIndex();
1684 : PropertyConstness constness = lookup->constness();
1685 821909 : if (constness == PropertyConstness::kConst &&
1686 395221 : IsStoreOwnICKind(nexus()->kind())) {
1687 : // StoreOwnICs are used for initializing object literals therefore
1688 : // we must store the value unconditionally even to
1689 : // VariableMode::kConst fields.
1690 : constness = PropertyConstness::kMutable;
1691 : }
1692 : return MaybeObjectHandle(StoreHandler::StoreField(
1693 426689 : isolate(), descriptor, index, constness, lookup->representation()));
1694 : }
1695 :
1696 : // -------------- Constant properties --------------
1697 : DCHECK_EQ(kDescriptor, lookup->property_details().location());
1698 : set_slow_stub_reason("constant property");
1699 0 : TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1700 0 : return MaybeObjectHandle(slow_stub());
1701 : }
1702 : case LookupIterator::JSPROXY: {
1703 : Handle<JSReceiver> receiver =
1704 371 : Handle<JSReceiver>::cast(lookup->GetReceiver());
1705 371 : Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
1706 : return MaybeObjectHandle(StoreHandler::StoreProxy(
1707 371 : isolate(), receiver_map(), holder, receiver));
1708 : }
1709 :
1710 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
1711 : case LookupIterator::ACCESS_CHECK:
1712 : case LookupIterator::NOT_FOUND:
1713 0 : UNREACHABLE();
1714 : }
1715 0 : return MaybeObjectHandle();
1716 : }
1717 :
1718 205146 : void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
1719 : KeyedAccessStoreMode store_mode,
1720 : bool receiver_was_cow) {
1721 : MapHandles target_receiver_maps;
1722 216715 : TargetMaps(&target_receiver_maps);
1723 205149 : if (target_receiver_maps.empty()) {
1724 : Handle<Map> monomorphic_map =
1725 193570 : ComputeTransitionedMap(receiver_map, store_mode);
1726 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1727 193566 : Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode);
1728 : return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
1729 : }
1730 :
1731 44325 : for (Handle<Map> map : target_receiver_maps) {
1732 32756 : if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
1733 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1734 : set_slow_stub_reason("JSValue");
1735 : return;
1736 : }
1737 : }
1738 :
1739 : // There are several special cases where an IC that is MONOMORPHIC can still
1740 : // transition to a different GetNonTransitioningStoreMode IC that handles a
1741 : // superset of the original IC. Handle those here if the receiver map hasn't
1742 : // changed or it has transitioned to a more general kind.
1743 : KeyedAccessStoreMode old_store_mode;
1744 : old_store_mode = GetKeyedAccessStoreMode();
1745 11569 : Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
1746 11569 : if (state() == MONOMORPHIC) {
1747 : Handle<Map> transitioned_receiver_map = receiver_map;
1748 8949 : if (IsTransitionStoreMode(store_mode)) {
1749 : transitioned_receiver_map =
1750 2687 : ComputeTransitionedMap(receiver_map, store_mode);
1751 : }
1752 11417 : if ((receiver_map.is_identical_to(previous_receiver_map) &&
1753 16368 : IsTransitionStoreMode(store_mode)) ||
1754 : IsTransitionOfMonomorphicTarget(*previous_receiver_map,
1755 7419 : *transitioned_receiver_map)) {
1756 : // If the "old" and "new" maps are in the same elements map family, or
1757 : // if they at least come from the same origin for a transitioning store,
1758 : // stay MONOMORPHIC and use the map for the most generic ElementsKind.
1759 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1760 : Handle<Object> handler =
1761 4959 : StoreElementHandler(transitioned_receiver_map, store_mode);
1762 : ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler);
1763 : return;
1764 : }
1765 4928 : if (receiver_map.is_identical_to(previous_receiver_map) &&
1766 4805 : old_store_mode == STANDARD_STORE &&
1767 1630 : (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1768 1173 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1769 : store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1770 : // A "normal" IC that handles stores can switch to a version that can
1771 : // grow at the end of the array, handle OOB accesses or copy COW arrays
1772 : // and still stay MONOMORPHIC.
1773 466 : Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
1774 : return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
1775 : }
1776 : }
1777 :
1778 : DCHECK(state() != GENERIC);
1779 :
1780 : bool map_added =
1781 6144 : AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
1782 :
1783 6144 : if (IsTransitionStoreMode(store_mode)) {
1784 : Handle<Map> transitioned_receiver_map =
1785 1246 : ComputeTransitionedMap(receiver_map, store_mode);
1786 : map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1787 1246 : transitioned_receiver_map);
1788 : }
1789 :
1790 6144 : if (!map_added) {
1791 : // If the miss wasn't due to an unseen map, a polymorphic stub
1792 : // won't help, use the megamorphic stub which can handle everything.
1793 : set_slow_stub_reason("same map added twice");
1794 : return;
1795 : }
1796 :
1797 : // If the maximum number of receiver maps has been exceeded, use the
1798 : // megamorphic version of the IC.
1799 11040 : if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return;
1800 :
1801 : // Make sure all polymorphic handlers have the same store mode, otherwise the
1802 : // megamorphic stub must be used.
1803 : store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow);
1804 4787 : if (old_store_mode != STANDARD_STORE) {
1805 735 : if (store_mode == STANDARD_STORE) {
1806 : store_mode = old_store_mode;
1807 471 : } else if (store_mode != old_store_mode) {
1808 : set_slow_stub_reason("store mode mismatch");
1809 : return;
1810 : }
1811 : }
1812 :
1813 : // If the store mode isn't the standard mode, make sure that all polymorphic
1814 : // receivers are either external arrays, or all "normal" arrays. Otherwise,
1815 : // use the megamorphic stub.
1816 4760 : if (store_mode != STANDARD_STORE) {
1817 : size_t external_arrays = 0;
1818 4940 : for (Handle<Map> map : target_receiver_maps) {
1819 2034 : if (map->has_fixed_typed_array_elements()) {
1820 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1821 306 : external_arrays++;
1822 : }
1823 : }
1824 998 : if (external_arrays != 0 &&
1825 126 : external_arrays != target_receiver_maps.size()) {
1826 : DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1827 : set_slow_stub_reason(
1828 : "unsupported combination of external and normal arrays");
1829 : return;
1830 : }
1831 : }
1832 :
1833 : MaybeObjectHandles handlers;
1834 9466 : handlers.reserve(target_receiver_maps.size());
1835 4733 : StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
1836 9466 : if (target_receiver_maps.size() == 0) {
1837 : // Transition to PREMONOMORPHIC state here and remember a weak-reference
1838 : // to the {receiver_map} in case TurboFan sees this function before the
1839 : // IC can transition further.
1840 9 : ConfigureVectorState(receiver_map);
1841 4724 : } else if (target_receiver_maps.size() == 1) {
1842 36 : ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
1843 : } else {
1844 4706 : ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
1845 : }
1846 : }
1847 :
1848 :
1849 197499 : Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1850 : Handle<Map> map, KeyedAccessStoreMode store_mode) {
1851 197499 : switch (store_mode) {
1852 : case STORE_TRANSITION_TO_OBJECT:
1853 : case STORE_AND_GROW_TRANSITION_TO_OBJECT: {
1854 : ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1855 : ? HOLEY_ELEMENTS
1856 18399 : : PACKED_ELEMENTS;
1857 22029 : return Map::TransitionElementsTo(isolate(), map, kind);
1858 : }
1859 : case STORE_TRANSITION_TO_DOUBLE:
1860 : case STORE_AND_GROW_TRANSITION_TO_DOUBLE: {
1861 : ElementsKind kind = IsHoleyElementsKind(map->elements_kind())
1862 : ? HOLEY_DOUBLE_ELEMENTS
1863 3630 : : PACKED_DOUBLE_ELEMENTS;
1864 7260 : return Map::TransitionElementsTo(isolate(), map, kind);
1865 : }
1866 : case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1867 : DCHECK(map->has_fixed_typed_array_elements());
1868 : V8_FALLTHROUGH;
1869 : case STORE_NO_TRANSITION_HANDLE_COW:
1870 : case STANDARD_STORE:
1871 : case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
1872 175470 : return map;
1873 : }
1874 0 : UNREACHABLE();
1875 : }
1876 :
1877 209278 : Handle<Object> KeyedStoreIC::StoreElementHandler(
1878 : Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1879 : DCHECK(store_mode == STANDARD_STORE ||
1880 : store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1881 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1882 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1883 : DCHECK_IMPLIES(
1884 : receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()),
1885 : IsStoreInArrayLiteralICKind(kind()));
1886 :
1887 209279 : if (receiver_map->IsJSProxyMap()) {
1888 451987 : return StoreHandler::StoreProxy(isolate());
1889 : }
1890 :
1891 : // TODO(ishell): move to StoreHandler::StoreElement().
1892 : Handle<Code> code;
1893 209202 : if (receiver_map->has_sloppy_arguments_elements()) {
1894 : // TODO(jgruber): Update counter name.
1895 0 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
1896 : code =
1897 0 : CodeFactory::KeyedStoreIC_SloppyArguments(isolate(), store_mode).code();
1898 231438 : } else if (receiver_map->has_fast_elements() ||
1899 : receiver_map->has_fixed_typed_array_elements()) {
1900 207783 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
1901 415566 : code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code();
1902 207783 : if (receiver_map->has_fixed_typed_array_elements()) return code;
1903 1418 : } else if (IsStoreInArrayLiteralICKind(kind())) {
1904 : // TODO(jgruber): Update counter name.
1905 36 : TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
1906 : code =
1907 72 : CodeFactory::StoreInArrayLiteralIC_Slow(isolate(), store_mode).code();
1908 : } else {
1909 : // TODO(jgruber): Update counter name.
1910 1382 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
1911 : DCHECK_EQ(DICTIONARY_ELEMENTS, receiver_map->elements_kind());
1912 2764 : code = CodeFactory::KeyedStoreIC_Slow(isolate(), store_mode).code();
1913 : }
1914 :
1915 188382 : if (IsStoreInArrayLiteralICKind(kind())) return code;
1916 :
1917 : Handle<Object> validity_cell =
1918 26480 : Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
1919 52960 : if (validity_cell->IsSmi()) {
1920 : // There's no prototype validity cell to check, so we can just use the stub.
1921 51 : return code;
1922 : }
1923 26429 : Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0);
1924 26429 : handler->set_validity_cell(*validity_cell);
1925 52858 : handler->set_smi_handler(*code);
1926 26429 : return handler;
1927 : }
1928 :
1929 4733 : void KeyedStoreIC::StoreElementPolymorphicHandlers(
1930 : MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1931 : KeyedAccessStoreMode store_mode) {
1932 : DCHECK(store_mode == STANDARD_STORE ||
1933 : store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW ||
1934 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1935 : store_mode == STORE_NO_TRANSITION_HANDLE_COW);
1936 :
1937 : // Filter out deprecated maps to ensure their instances get migrated.
1938 : receiver_maps->erase(
1939 : std::remove_if(
1940 : receiver_maps->begin(), receiver_maps->end(),
1941 24154 : [](const Handle<Map>& map) { return map->is_deprecated(); }),
1942 4733 : receiver_maps->end());
1943 :
1944 21472 : for (Handle<Map> receiver_map : *receiver_maps) {
1945 : Handle<Object> handler;
1946 : Handle<Map> transition;
1947 :
1948 36018 : if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
1949 51363 : receiver_map->DictionaryElementsInPrototypeChainOnly(isolate())) {
1950 : // TODO(mvstanton): Consider embedding store_mode in the state of the slow
1951 : // keyed store ic for uniformity.
1952 45 : TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
1953 45 : handler = slow_stub();
1954 :
1955 : } else {
1956 : {
1957 : Map tmap = receiver_map->FindElementsKindTransitionedMap(
1958 11961 : isolate(), *receiver_maps);
1959 11961 : if (!tmap.is_null()) {
1960 1674 : if (receiver_map->is_stable()) {
1961 36 : receiver_map->NotifyLeafMapLayoutChange(isolate());
1962 : }
1963 : transition = handle(tmap, isolate());
1964 : }
1965 : }
1966 :
1967 : // TODO(mvstanton): The code below is doing pessimistic elements
1968 : // transitions. I would like to stop doing that and rely on Allocation
1969 : // Site Tracking to do a better job of ensuring the data types are what
1970 : // they need to be. Not all the elements are in place yet, pessimistic
1971 : // elements transitions are still important for performance.
1972 11961 : if (!transition.is_null()) {
1973 1674 : TRACE_HANDLER_STATS(isolate(),
1974 : KeyedStoreIC_ElementsTransitionAndStoreStub);
1975 : handler = StoreHandler::StoreElementTransition(isolate(), receiver_map,
1976 1674 : transition, store_mode);
1977 : } else {
1978 10287 : handler = StoreElementHandler(receiver_map, store_mode);
1979 : }
1980 : }
1981 : DCHECK(!handler.is_null());
1982 12006 : handlers->push_back(MaybeObjectHandle(handler));
1983 : }
1984 4733 : }
1985 :
1986 :
1987 302200 : static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
1988 : uint32_t index, Handle<Object> value) {
1989 302200 : bool oob_access = IsOutOfBoundsAccess(receiver, index);
1990 : // Don't consider this a growing store if the store would send the receiver to
1991 : // dictionary mode.
1992 1008561 : bool allow_growth = receiver->IsJSArray() && oob_access &&
1993 404158 : !receiver->WouldConvertToSlowElements(index);
1994 302202 : if (allow_growth) {
1995 : // Handle growing array in stub if necessary.
1996 202216 : if (receiver->HasSmiElements()) {
1997 15230 : if (value->IsHeapNumber()) {
1998 : return STORE_AND_GROW_TRANSITION_TO_DOUBLE;
1999 : }
2000 14350 : if (value->IsHeapObject()) {
2001 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2002 : }
2003 186986 : } else if (receiver->HasDoubleElements()) {
2004 1878 : if (!value->IsSmi() && !value->IsHeapNumber()) {
2005 : return STORE_AND_GROW_TRANSITION_TO_OBJECT;
2006 : }
2007 : }
2008 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
2009 : } else {
2010 : // Handle only in-bounds elements accesses.
2011 402186 : if (receiver->HasSmiElements()) {
2012 317288 : if (value->IsHeapNumber()) {
2013 : return STORE_TRANSITION_TO_DOUBLE;
2014 311673 : } else if (value->IsHeapObject()) {
2015 : return STORE_TRANSITION_TO_OBJECT;
2016 : }
2017 84900 : } else if (receiver->HasDoubleElements()) {
2018 15736 : if (!value->IsSmi() && !value->IsHeapNumber()) {
2019 : return STORE_TRANSITION_TO_OBJECT;
2020 : }
2021 : }
2022 537983 : if (!FLAG_trace_external_array_abuse &&
2023 196631 : receiver->map()->has_fixed_typed_array_elements() && oob_access) {
2024 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
2025 : }
2026 357135 : return receiver->elements()->IsCowArray() ? STORE_NO_TRANSITION_HANDLE_COW
2027 178568 : : STANDARD_STORE;
2028 : }
2029 : }
2030 :
2031 :
2032 159269 : MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
2033 : Handle<Object> key,
2034 : Handle<Object> value) {
2035 : // TODO(verwaest): Let SetProperty do the migration, since storing a property
2036 : // might deprecate the current map again, if value does not fit.
2037 159269 : if (MigrateDeprecated(object)) {
2038 : Handle<Object> result;
2039 939415 : ASSIGN_RETURN_ON_EXCEPTION(
2040 : isolate(), result,
2041 : Runtime::SetObjectProperty(isolate(), object, key, value,
2042 : StoreOrigin::kMaybeKeyed),
2043 : Object);
2044 27 : return result;
2045 : }
2046 :
2047 : // Check for non-string values that can be converted into an
2048 : // internalized string directly or is representable as a smi.
2049 159242 : key = TryConvertKey(key, isolate());
2050 :
2051 : Handle<Object> store_handle;
2052 :
2053 : uint32_t index;
2054 326955 : if ((key->IsInternalizedString() &&
2055 478648 : !String::cast(*key)->AsArrayIndex(&index)) ||
2056 310935 : key->IsSymbol()) {
2057 24364 : ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle,
2058 : StoreIC::Store(object, Handle<Name>::cast(key),
2059 : value, StoreOrigin::kMaybeKeyed),
2060 : Object);
2061 11613 : if (vector_needs_update()) {
2062 18 : if (ConfigureVectorState(MEGAMORPHIC, key)) {
2063 : set_slow_stub_reason("unhandled internalized string key");
2064 18 : TraceIC("StoreIC", key);
2065 : }
2066 : }
2067 11613 : return store_handle;
2068 : }
2069 :
2070 147060 : JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
2071 :
2072 294120 : bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic &&
2073 1028650 : !object->IsStringWrapper() && !object->IsAccessCheckNeeded() &&
2074 293840 : !object->IsJSGlobalProxy();
2075 440368 : if (use_ic && !object->IsSmi()) {
2076 : // Don't use ICs for maps of the objects in Array's prototype chain. We
2077 : // expect to be able to trap element sets to objects with those maps in
2078 : // the runtime to enable optimization of element hole access.
2079 146239 : Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2080 146239 : if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) {
2081 : set_slow_stub_reason("map in array prototype");
2082 : use_ic = false;
2083 : }
2084 : }
2085 :
2086 : Handle<Map> old_receiver_map;
2087 : bool is_arguments = false;
2088 : bool key_is_valid_index = false;
2089 : KeyedAccessStoreMode store_mode = STANDARD_STORE;
2090 438706 : if (use_ic && object->IsJSReceiver()) {
2091 145169 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
2092 : old_receiver_map = handle(receiver->map(), isolate());
2093 290338 : is_arguments = receiver->IsJSArgumentsObject();
2094 290338 : bool is_proxy = receiver->IsJSProxy();
2095 : // For JSTypedArray {object}s we can handle negative indices as OOB
2096 : // accesses, since integer indexed properties are never looked up
2097 : // on the prototype chain. For this we simply map the negative {key}s
2098 : // to the [2**31,2**32-1] range, which is safe since JSTypedArray::length
2099 : // is always an unsigned Smi.
2100 : key_is_valid_index =
2101 433421 : key->IsSmi() && (Smi::ToInt(*key) >= 0 || object->IsJSTypedArray());
2102 145169 : if (!is_arguments && !is_proxy) {
2103 143506 : if (key_is_valid_index) {
2104 140316 : uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key));
2105 140316 : Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
2106 140316 : store_mode = GetStoreMode(receiver_object, index, value);
2107 : }
2108 : }
2109 : }
2110 :
2111 : DCHECK(store_handle.is_null());
2112 : bool receiver_was_cow =
2113 557510 : object->IsJSArray() &&
2114 379720 : Handle<JSArray>::cast(object)->elements()->IsCowArray();
2115 294120 : ASSIGN_RETURN_ON_EXCEPTION(
2116 : isolate(), store_handle,
2117 : Runtime::SetObjectProperty(isolate(), object, key, value,
2118 : StoreOrigin::kMaybeKeyed),
2119 : Object);
2120 :
2121 53080 : if (use_ic) {
2122 51863 : if (!old_receiver_map.is_null()) {
2123 51326 : if (is_arguments) {
2124 : set_slow_stub_reason("arguments receiver");
2125 50190 : } else if (key_is_valid_index) {
2126 47549 : if (old_receiver_map->is_abandoned_prototype_map()) {
2127 : set_slow_stub_reason("receiver with prototype map");
2128 47531 : } else if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly(
2129 47531 : isolate())) {
2130 : // We should go generic if receiver isn't a dictionary, but our
2131 : // prototype chain does have dictionary elements. This ensures that
2132 : // other non-dictionary receivers in the polymorphic case benefit
2133 : // from fast path keyed stores.
2134 43261 : UpdateStoreElement(old_receiver_map, store_mode, receiver_was_cow);
2135 : } else {
2136 : set_slow_stub_reason("dictionary or proxy prototype");
2137 : }
2138 : } else {
2139 : set_slow_stub_reason("non-smi-like key");
2140 : }
2141 : } else {
2142 : set_slow_stub_reason("non-JSObject receiver");
2143 : }
2144 : }
2145 :
2146 53080 : if (vector_needs_update()) {
2147 11240 : ConfigureVectorState(MEGAMORPHIC, key);
2148 : }
2149 53080 : TraceIC("StoreIC", key);
2150 :
2151 53080 : return store_handle;
2152 : }
2153 :
2154 : namespace {
2155 162004 : void StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
2156 : Handle<Object> index, Handle<Object> value) {
2157 : DCHECK(index->IsNumber());
2158 162004 : bool success = false;
2159 : LookupIterator it = LookupIterator::PropertyOrElement(
2160 162004 : isolate, array, index, &success, LookupIterator::OWN);
2161 : DCHECK(success);
2162 :
2163 324012 : CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(
2164 : &it, value, NONE, Just(ShouldThrow::kThrowOnError))
2165 : .FromJust());
2166 162007 : }
2167 : } // namespace
2168 :
2169 161886 : void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
2170 : Handle<Object> value) {
2171 : DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate()));
2172 : DCHECK(index->IsNumber());
2173 :
2174 647547 : if (!FLAG_use_ic || state() == NO_FEEDBACK || MigrateDeprecated(array)) {
2175 0 : StoreOwnElement(isolate(), array, index, value);
2176 0 : TraceIC("StoreInArrayLiteralIC", index);
2177 161887 : return;
2178 : }
2179 :
2180 : // TODO(neis): Convert HeapNumber to Smi if possible?
2181 :
2182 : KeyedAccessStoreMode store_mode = STANDARD_STORE;
2183 323772 : if (index->IsSmi()) {
2184 : DCHECK_GE(Smi::ToInt(*index), 0);
2185 161887 : uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2186 161887 : store_mode = GetStoreMode(array, index32, value);
2187 : }
2188 :
2189 : Handle<Map> old_array_map(array->map(), isolate());
2190 161886 : bool array_was_cow = array->elements()->IsCowArray();
2191 161888 : StoreOwnElement(isolate(), array, index, value);
2192 :
2193 323773 : if (index->IsSmi()) {
2194 : DCHECK(!old_array_map->is_abandoned_prototype_map());
2195 161887 : UpdateStoreElement(old_array_map, store_mode, array_was_cow);
2196 : } else {
2197 : set_slow_stub_reason("index out of Smi range");
2198 : }
2199 :
2200 161887 : if (vector_needs_update()) {
2201 0 : ConfigureVectorState(MEGAMORPHIC, index);
2202 : }
2203 161887 : TraceIC("StoreInArrayLiteralIC", index);
2204 : }
2205 :
2206 : // ----------------------------------------------------------------------------
2207 : // Static IC stub generators.
2208 : //
2209 : //
2210 1274477 : RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2211 1274427 : HandleScope scope(isolate);
2212 : DCHECK_EQ(4, args.length());
2213 : // Runtime functions don't follow the IC's calling convention.
2214 1274429 : Handle<Object> receiver = args.at(0);
2215 1274430 : Handle<Name> key = args.at<Name>(1);
2216 1274429 : Handle<Smi> slot = args.at<Smi>(2);
2217 1274428 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2218 1274423 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2219 :
2220 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2221 2548836 : if (!maybe_vector->IsUndefined()) {
2222 : DCHECK(maybe_vector->IsFeedbackVector());
2223 1274417 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2224 : }
2225 : // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2226 : // LoadIC miss handler if the handler misses. Since the vector Nexus is
2227 : // set up outside the IC, handle that here.
2228 : // The only case where we call without a vector is from the LoadNamedProperty
2229 : // bytecode handler. Also, when there is no feedback vector, there is no
2230 : // difference between LoadProperty or LoadKeyed kind.
2231 : FeedbackSlotKind kind = FeedbackSlotKind::kLoadProperty;
2232 1274416 : if (!vector.is_null()) {
2233 1274418 : kind = vector->GetKind(vector_slot);
2234 : }
2235 1274415 : if (IsLoadICKind(kind)) {
2236 1274415 : LoadIC ic(isolate, vector, vector_slot, kind);
2237 1274422 : ic.UpdateState(receiver, key);
2238 3823307 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2239 :
2240 0 : } else if (IsLoadGlobalICKind(kind)) {
2241 : DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2242 0 : receiver = isolate->global_object();
2243 0 : LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2244 0 : ic.UpdateState(receiver, key);
2245 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2246 :
2247 : } else {
2248 : DCHECK(IsKeyedLoadICKind(kind));
2249 0 : KeyedLoadIC ic(isolate, vector, vector_slot, kind);
2250 0 : ic.UpdateState(receiver, key);
2251 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2252 1274436 : }
2253 : }
2254 :
2255 2251250 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2256 2251200 : HandleScope scope(isolate);
2257 : DCHECK_EQ(4, args.length());
2258 : // Runtime functions don't follow the IC's calling convention.
2259 2251200 : Handle<JSGlobalObject> global = isolate->global_object();
2260 2251200 : Handle<String> name = args.at<String>(0);
2261 2251196 : Handle<Smi> slot = args.at<Smi>(1);
2262 2251199 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2263 4502395 : CONVERT_INT32_ARG_CHECKED(typeof_value, 3);
2264 2251200 : TypeofMode typeof_mode = static_cast<TypeofMode>(typeof_value);
2265 2251200 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2266 :
2267 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2268 4502397 : if (!maybe_vector->IsUndefined()) {
2269 : DCHECK(maybe_vector->IsFeedbackVector());
2270 2251198 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2271 : }
2272 :
2273 : FeedbackSlotKind kind = (typeof_mode == TypeofMode::INSIDE_TYPEOF)
2274 : ? FeedbackSlotKind::kLoadGlobalInsideTypeof
2275 2251199 : : FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
2276 4502407 : LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2277 2251202 : ic.UpdateState(global, name);
2278 :
2279 : Handle<Object> result;
2280 4502418 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2281 2251205 : return *result;
2282 : }
2283 :
2284 784 : RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2285 784 : HandleScope scope(isolate);
2286 : DCHECK_EQ(3, args.length());
2287 1568 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2288 :
2289 784 : Handle<Context> native_context = isolate->native_context();
2290 : Handle<ScriptContextTable> script_contexts(
2291 1568 : native_context->script_context_table(), isolate);
2292 :
2293 : ScriptContextTable::LookupResult lookup_result;
2294 784 : if (ScriptContextTable::Lookup(isolate, *script_contexts, *name,
2295 : &lookup_result)) {
2296 : Handle<Context> script_context = ScriptContextTable::GetContext(
2297 0 : isolate, script_contexts, lookup_result.context_index);
2298 : Handle<Object> result(script_context->get(lookup_result.slot_index),
2299 0 : isolate);
2300 0 : if (*result == ReadOnlyRoots(isolate).the_hole_value()) {
2301 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2302 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2303 : }
2304 : return *result;
2305 : }
2306 :
2307 1568 : Handle<JSGlobalObject> global(native_context->global_object(), isolate);
2308 : Handle<Object> result;
2309 784 : bool is_found = false;
2310 1568 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2311 : isolate, result,
2312 : Runtime::GetObjectProperty(isolate, global, name, &is_found));
2313 784 : if (!is_found) {
2314 0 : Handle<Smi> slot = args.at<Smi>(1);
2315 0 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2316 0 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2317 0 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2318 : // It is actually a LoadGlobalICs here but the predicate handles this case
2319 : // properly.
2320 0 : if (LoadIC::ShouldThrowReferenceError(kind)) {
2321 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2322 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2323 : }
2324 : }
2325 784 : return *result;
2326 : }
2327 :
2328 214052 : RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2329 214052 : HandleScope scope(isolate);
2330 : DCHECK_EQ(4, args.length());
2331 : // Runtime functions don't follow the IC's calling convention.
2332 214052 : Handle<Object> receiver = args.at(0);
2333 214052 : Handle<Object> key = args.at(1);
2334 214052 : Handle<Smi> slot = args.at<Smi>(2);
2335 214052 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2336 :
2337 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2338 428104 : if (!maybe_vector->IsUndefined()) {
2339 : DCHECK(maybe_vector->IsFeedbackVector());
2340 214052 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2341 : }
2342 214052 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2343 428104 : KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadKeyed);
2344 214052 : ic.UpdateState(receiver, key);
2345 642156 : RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2346 : }
2347 :
2348 1636914 : RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2349 1636914 : HandleScope scope(isolate);
2350 : DCHECK_EQ(5, args.length());
2351 : // Runtime functions don't follow the IC's calling convention.
2352 1636915 : Handle<Object> value = args.at(0);
2353 1636915 : Handle<Smi> slot = args.at<Smi>(1);
2354 1636914 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2355 1636914 : Handle<Object> receiver = args.at(3);
2356 1636913 : Handle<Name> key = args.at<Name>(4);
2357 :
2358 1636910 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2359 :
2360 : // When there is no feedback vector it is OK to use the StoreNamedStrict as
2361 : // the feedback slot kind. We only need if it is StoreOwnICKind when
2362 : // installing the handler for storing const properties. This will happen only
2363 : // when feedback vector is available.
2364 : FeedbackSlotKind kind = FeedbackSlotKind::kStoreNamedStrict;
2365 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2366 3273822 : if (!maybe_vector->IsUndefined()) {
2367 : DCHECK(maybe_vector->IsFeedbackVector());
2368 1636911 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2369 1636910 : kind = vector->GetKind(vector_slot);
2370 : }
2371 :
2372 : DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind));
2373 3273826 : StoreIC ic(isolate, vector, vector_slot, kind);
2374 1636912 : ic.UpdateState(receiver, key);
2375 4910739 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2376 : }
2377 :
2378 1685911 : RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2379 1685911 : HandleScope scope(isolate);
2380 : DCHECK_EQ(4, args.length());
2381 : // Runtime functions don't follow the IC's calling convention.
2382 1685911 : Handle<Object> value = args.at(0);
2383 1685911 : Handle<Smi> slot = args.at<Smi>(1);
2384 1685911 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2385 1685911 : Handle<Name> key = args.at<Name>(3);
2386 :
2387 1685911 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2388 1685911 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2389 3371822 : StoreGlobalIC ic(isolate, vector, vector_slot, kind);
2390 1685911 : Handle<JSGlobalObject> global = isolate->global_object();
2391 1685911 : ic.UpdateState(global, key);
2392 5057733 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2393 : }
2394 :
2395 0 : RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
2396 0 : HandleScope scope(isolate);
2397 : DCHECK_EQ(2, args.length());
2398 : // Runtime functions don't follow the IC's calling convention.
2399 0 : Handle<Object> value = args.at(0);
2400 0 : Handle<Name> key = args.at<Name>(1);
2401 :
2402 : // TODO(mythria): Replace StoreGlobalStrict/Sloppy with StoreNamed.
2403 : StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(),
2404 0 : FeedbackSlotKind::kStoreGlobalStrict);
2405 0 : RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2406 : }
2407 :
2408 : // TODO(mythria): Remove Feedback vector and slot. Since they are not used apart
2409 : // from the DCHECK.
2410 7417 : RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
2411 7417 : HandleScope scope(isolate);
2412 : DCHECK_EQ(5, args.length());
2413 : // Runtime functions don't follow the IC's calling convention.
2414 7417 : Handle<Object> value = args.at(0);
2415 14834 : CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
2416 :
2417 : #ifdef DEBUG
2418 : {
2419 : Handle<Smi> slot = args.at<Smi>(1);
2420 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2421 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2422 : FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2423 : DCHECK(IsStoreGlobalICKind(slot_kind));
2424 : Handle<Object> receiver = args.at(3);
2425 : DCHECK(receiver->IsJSGlobalProxy());
2426 : }
2427 : #endif
2428 :
2429 7417 : Handle<JSGlobalObject> global = isolate->global_object();
2430 7417 : Handle<Context> native_context = isolate->native_context();
2431 : Handle<ScriptContextTable> script_contexts(
2432 14834 : native_context->script_context_table(), isolate);
2433 :
2434 : ScriptContextTable::LookupResult lookup_result;
2435 7417 : if (ScriptContextTable::Lookup(isolate, *script_contexts, *name,
2436 : &lookup_result)) {
2437 : Handle<Context> script_context = ScriptContextTable::GetContext(
2438 18 : isolate, script_contexts, lookup_result.context_index);
2439 18 : if (lookup_result.mode == VariableMode::kConst) {
2440 18 : THROW_NEW_ERROR_RETURN_FAILURE(
2441 : isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
2442 : }
2443 :
2444 : Handle<Object> previous_value(script_context->get(lookup_result.slot_index),
2445 27 : isolate);
2446 :
2447 18 : if (previous_value->IsTheHole(isolate)) {
2448 0 : THROW_NEW_ERROR_RETURN_FAILURE(
2449 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
2450 : }
2451 :
2452 27 : script_context->set(lookup_result.slot_index, *value);
2453 : return *value;
2454 : }
2455 :
2456 22197 : RETURN_RESULT_OR_FAILURE(
2457 : isolate, Runtime::SetObjectProperty(isolate, global, name, value,
2458 7417 : StoreOrigin::kMaybeKeyed));
2459 : }
2460 :
2461 160783 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
2462 160783 : HandleScope scope(isolate);
2463 : DCHECK_EQ(5, args.length());
2464 : // Runtime functions don't follow the IC's calling convention.
2465 160783 : Handle<Object> value = args.at(0);
2466 160783 : Handle<Smi> slot = args.at<Smi>(1);
2467 160783 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2468 160783 : Handle<Object> receiver = args.at(3);
2469 160783 : Handle<Object> key = args.at(4);
2470 160783 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2471 :
2472 : // When the feedback vector is not valid the slot can only be of type
2473 : // StoreKeyed. Storing in array literals falls back to
2474 : // StoreInArrayLiterIC_Miss. This function is also used from store handlers
2475 : // installed in feedback vectors. In such cases, we need to get the kind from
2476 : // feedback vector slot since the handlers are used for both for StoreKeyed
2477 : // and StoreInArrayLiteral kinds.
2478 : FeedbackSlotKind kind = FeedbackSlotKind::kStoreKeyedStrict;
2479 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2480 321566 : if (!maybe_vector->IsUndefined()) {
2481 : DCHECK(maybe_vector->IsFeedbackVector());
2482 160783 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2483 160783 : kind = vector->GetKind(vector_slot);
2484 : }
2485 :
2486 : // The elements store stubs miss into this function, but they are shared by
2487 : // different ICs.
2488 160783 : if (IsKeyedStoreICKind(kind)) {
2489 159269 : KeyedStoreIC ic(isolate, vector, vector_slot, kind);
2490 159269 : ic.UpdateState(receiver, key);
2491 477807 : 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 1514 : StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2497 1514 : ic.UpdateState(receiver, key);
2498 1514 : ic.Store(Handle<JSArray>::cast(receiver), key, value);
2499 1514 : return *value;
2500 160783 : }
2501 : }
2502 :
2503 160371 : RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
2504 160371 : HandleScope scope(isolate);
2505 : DCHECK_EQ(5, args.length());
2506 : // Runtime functions don't follow the IC's calling convention.
2507 160372 : Handle<Object> value = args.at(0);
2508 160372 : Handle<Smi> slot = args.at<Smi>(1);
2509 160373 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2510 160372 : Handle<Object> receiver = args.at(3);
2511 160372 : Handle<Object> key = args.at(4);
2512 : Handle<FeedbackVector> vector = Handle<FeedbackVector>();
2513 320745 : if (!maybe_vector->IsUndefined()) {
2514 : DCHECK(maybe_vector->IsFeedbackVector());
2515 160372 : vector = Handle<FeedbackVector>::cast(maybe_vector);
2516 : }
2517 : DCHECK(receiver->IsJSArray());
2518 : DCHECK(key->IsNumber());
2519 160374 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2520 320747 : StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
2521 160373 : ic.Store(Handle<JSArray>::cast(receiver), key, value);
2522 160374 : return *value;
2523 : }
2524 :
2525 316432 : RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
2526 316432 : HandleScope scope(isolate);
2527 : DCHECK_EQ(3, args.length());
2528 : // Runtime functions don't follow the IC's calling convention.
2529 316432 : Handle<Object> value = args.at(0);
2530 316432 : Handle<Object> object = args.at(1);
2531 316432 : Handle<Object> key = args.at(2);
2532 632864 : RETURN_RESULT_OR_FAILURE(
2533 : isolate, Runtime::SetObjectProperty(isolate, object, key, value,
2534 316432 : StoreOrigin::kMaybeKeyed));
2535 : }
2536 :
2537 47 : RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
2538 47 : HandleScope scope(isolate);
2539 : DCHECK_EQ(3, args.length());
2540 : // Runtime functions don't follow the IC's calling convention.
2541 47 : Handle<Object> value = args.at(0);
2542 47 : Handle<Object> array = args.at(1);
2543 47 : Handle<Object> index = args.at(2);
2544 47 : StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value);
2545 47 : return *value;
2546 : }
2547 :
2548 202 : RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
2549 202 : HandleScope scope(isolate);
2550 : DCHECK_EQ(6, args.length());
2551 : // Runtime functions don't follow the IC's calling convention.
2552 202 : Handle<Object> object = args.at(0);
2553 202 : Handle<Object> key = args.at(1);
2554 202 : Handle<Object> value = args.at(2);
2555 202 : Handle<Map> map = args.at<Map>(3);
2556 202 : Handle<Smi> slot = args.at<Smi>(4);
2557 202 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(5);
2558 202 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2559 202 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2560 :
2561 404 : if (object->IsJSObject()) {
2562 : JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2563 202 : map->elements_kind());
2564 : }
2565 :
2566 202 : if (IsStoreInArrayLiteralICKind(kind)) {
2567 73 : StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value);
2568 : return *value;
2569 : } else {
2570 : DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
2571 258 : RETURN_RESULT_OR_FAILURE(
2572 : isolate, Runtime::SetObjectProperty(isolate, object, key, value,
2573 : StoreOrigin::kMaybeKeyed));
2574 202 : }
2575 : }
2576 :
2577 558 : static bool CanFastCloneObject(Handle<Map> map) {
2578 : DisallowHeapAllocation no_gc;
2579 558 : if (map->IsNullOrUndefinedMap()) return true;
2580 999 : if (!map->IsJSObjectMap() ||
2581 981 : !IsSmiOrObjectElementsKind(map->elements_kind()) ||
2582 981 : !map->OnlyHasSimpleProperties()) {
2583 : return false;
2584 : }
2585 :
2586 432 : DescriptorArray descriptors = map->instance_descriptors();
2587 1944 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
2588 567 : PropertyDetails details = descriptors->GetDetails(i);
2589 567 : Name key = descriptors->GetKey(i);
2590 1656 : if (details.kind() != kData || !details.IsEnumerable() ||
2591 540 : key->IsPrivateName()) {
2592 27 : return false;
2593 : }
2594 : }
2595 :
2596 : return true;
2597 : }
2598 :
2599 432 : static Handle<Map> FastCloneObjectMap(Isolate* isolate,
2600 : Handle<HeapObject> source, int flags) {
2601 : Handle<Map> source_map(source->map(), isolate);
2602 : SLOW_DCHECK(source->IsNullOrUndefined() || CanFastCloneObject(source_map));
2603 1296 : Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2604 432 : isolate);
2605 : DCHECK(constructor->has_initial_map());
2606 864 : Handle<Map> initial_map(constructor->initial_map(), isolate);
2607 : Handle<Map> map = initial_map;
2608 :
2609 1674 : if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() !=
2610 837 : initial_map->GetInObjectProperties()) {
2611 351 : int inobject_properties = source_map->GetInObjectProperties();
2612 : int instance_size =
2613 351 : JSObject::kHeaderSize + kTaggedSize * inobject_properties;
2614 351 : int unused = source_map->UnusedInObjectProperties();
2615 : DCHECK(instance_size <= JSObject::kMaxInstanceSize);
2616 : map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties,
2617 351 : unused);
2618 : }
2619 :
2620 432 : if (flags & ObjectLiteral::kHasNullPrototype) {
2621 0 : if (map.is_identical_to(initial_map)) {
2622 0 : map = Map::Copy(isolate, map, "ObjectWithNullProto");
2623 : }
2624 0 : Map::SetPrototype(isolate, map, isolate->factory()->null_value());
2625 : }
2626 :
2627 1269 : if (source->IsNullOrUndefined() || !source_map->NumberOfOwnDescriptors()) {
2628 126 : return map;
2629 : }
2630 :
2631 306 : if (map.is_identical_to(initial_map)) {
2632 18 : map = Map::Copy(isolate, map, "InitializeClonedDescriptors");
2633 : }
2634 :
2635 : Handle<DescriptorArray> source_descriptors(source_map->instance_descriptors(),
2636 612 : isolate);
2637 : int size = source_map->NumberOfOwnDescriptors();
2638 : int slack = 0;
2639 : Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone(
2640 306 : isolate, source_descriptors, size, slack);
2641 : Handle<LayoutDescriptor> layout =
2642 306 : LayoutDescriptor::New(isolate, map, descriptors, size);
2643 306 : map->InitializeDescriptors(isolate, *descriptors, *layout);
2644 306 : map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map);
2645 :
2646 : // Update bitfields
2647 : map->set_may_have_interesting_symbols(
2648 612 : source_map->may_have_interesting_symbols());
2649 :
2650 306 : return map;
2651 : }
2652 :
2653 126 : static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate,
2654 : Handle<HeapObject> source,
2655 : int flags) {
2656 : Handle<JSObject> new_object;
2657 126 : if (flags & ObjectLiteral::kHasNullPrototype) {
2658 0 : new_object = isolate->factory()->NewJSObjectWithNullProto();
2659 : } else {
2660 378 : Handle<JSFunction> constructor(isolate->native_context()->object_function(),
2661 126 : isolate);
2662 126 : new_object = isolate->factory()->NewJSObject(constructor);
2663 : }
2664 :
2665 252 : if (source->IsNullOrUndefined()) {
2666 0 : return new_object;
2667 : }
2668 :
2669 126 : MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source,
2670 : nullptr, false),
2671 : MaybeHandle<JSObject>());
2672 90 : return new_object;
2673 : }
2674 :
2675 558 : RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
2676 558 : HandleScope scope(isolate);
2677 : DCHECK_EQ(4, args.length());
2678 558 : Handle<HeapObject> source = args.at<HeapObject>(0);
2679 558 : int flags = args.smi_at(1);
2680 :
2681 558 : MigrateDeprecated(source);
2682 :
2683 558 : FeedbackSlot slot = FeedbackVector::ToSlot(args.smi_at(2));
2684 558 : Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2685 1116 : if (maybe_vector->IsUndefined()) {
2686 0 : RETURN_RESULT_OR_FAILURE(isolate,
2687 : CloneObjectSlowPath(isolate, source, flags));
2688 : }
2689 :
2690 : DCHECK(maybe_vector->IsFeedbackVector());
2691 558 : Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(maybe_vector);
2692 :
2693 558 : FeedbackNexus nexus(vector, slot);
2694 1116 : Handle<Map> source_map(source->map(), isolate);
2695 :
2696 558 : if (!CanFastCloneObject(source_map) || nexus.IsMegamorphic()) {
2697 : // Migrate to slow mode if needed.
2698 126 : nexus.ConfigureMegamorphic();
2699 252 : RETURN_RESULT_OR_FAILURE(isolate,
2700 : CloneObjectSlowPath(isolate, source, flags));
2701 : }
2702 :
2703 432 : Handle<Map> result_map = FastCloneObjectMap(isolate, source, flags);
2704 432 : nexus.ConfigureCloneObject(source_map, result_map);
2705 :
2706 558 : return *result_map;
2707 : }
2708 :
2709 490340 : RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
2710 490340 : Handle<JSObject> receiver = args.at<JSObject>(0);
2711 490340 : Handle<JSObject> holder = args.at<JSObject>(1);
2712 490340 : Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2713 490340 : Handle<Name> name = args.at<Name>(3);
2714 490340 : Handle<Object> value = args.at(4);
2715 490340 : HandleScope scope(isolate);
2716 :
2717 490340 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
2718 0 : RETURN_RESULT_OR_FAILURE(
2719 : isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
2720 : StoreOrigin::kMaybeKeyed));
2721 : }
2722 :
2723 : DCHECK(info->IsCompatibleReceiver(*receiver));
2724 :
2725 : PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
2726 1961360 : Nothing<ShouldThrow>());
2727 490340 : arguments.CallAccessorSetter(info, name, value);
2728 490340 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2729 490340 : return *value;
2730 : }
2731 :
2732 6276 : RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) {
2733 1046 : Handle<JSObject> receiver = args.at<JSObject>(0);
2734 1046 : Handle<JSObject> holder = args.at<JSObject>(1);
2735 1046 : Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
2736 1046 : Handle<Name> name = args.at<Name>(3);
2737 1046 : HandleScope scope(isolate);
2738 :
2739 : DCHECK(info->IsCompatibleReceiver(*receiver));
2740 :
2741 : PropertyCallbackArguments custom_args(isolate, info->data(), *receiver,
2742 4184 : *holder, Just(kThrowOnError));
2743 1046 : Handle<Object> result = custom_args.CallAccessorGetter(info, name);
2744 1046 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2745 1046 : if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2746 1046 : return *result;
2747 : }
2748 :
2749 24030 : RUNTIME_FUNCTION(Runtime_LoadAccessorProperty) {
2750 4005 : HandleScope scope(isolate);
2751 : DCHECK_EQ(args.length(), 3);
2752 4005 : Handle<JSObject> receiver = args.at<JSObject>(0);
2753 4005 : int handler_kind = args.smi_at(1);
2754 4005 : Handle<CallHandlerInfo> call_handler_info = args.at<CallHandlerInfo>(2);
2755 :
2756 4005 : Object holder = *receiver;
2757 4005 : if (handler_kind == LoadHandler::kApiGetterHolderIsPrototype) {
2758 0 : holder = receiver->map()->prototype();
2759 : } else {
2760 : DCHECK_EQ(handler_kind, LoadHandler::kApiGetter);
2761 : }
2762 :
2763 : // Call the accessor without additional arguments.
2764 : FunctionCallbackArguments custom(isolate, call_handler_info->data(),
2765 16020 : *receiver, holder, HeapObject(), nullptr, 0);
2766 4005 : Handle<Object> result_handle = custom.Call(*call_handler_info);
2767 4005 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2768 4005 : if (result_handle.is_null()) return ReadOnlyRoots(isolate).undefined_value();
2769 4005 : return *result_handle;
2770 : }
2771 :
2772 : /**
2773 : * Loads a property with an interceptor performing post interceptor
2774 : * lookup if interceptor failed.
2775 : */
2776 130371 : RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
2777 130371 : HandleScope scope(isolate);
2778 : DCHECK_EQ(5, args.length());
2779 130371 : Handle<Name> name = args.at<Name>(0);
2780 130371 : Handle<Object> receiver = args.at(1);
2781 130371 : Handle<JSObject> holder = args.at<JSObject>(2);
2782 :
2783 260742 : if (!receiver->IsJSReceiver()) {
2784 10 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2785 : isolate, receiver, Object::ConvertReceiver(isolate, receiver));
2786 : }
2787 :
2788 260742 : Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
2789 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2790 391113 : *holder, Just(kDontThrow));
2791 130371 : Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
2792 :
2793 130371 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2794 :
2795 130359 : if (!result.is_null()) return *result;
2796 :
2797 51543 : LookupIterator it(receiver, name, holder);
2798 : // Skip any lookup work until we hit the (possibly non-masking) interceptor.
2799 154629 : while (it.state() != LookupIterator::INTERCEPTOR ||
2800 103086 : !it.GetHolder<JSObject>().is_identical_to(holder)) {
2801 : DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
2802 0 : it.Next();
2803 : }
2804 : // Skip past the interceptor.
2805 51543 : it.Next();
2806 103086 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
2807 :
2808 51531 : if (it.IsFound()) return *result;
2809 :
2810 6437 : Handle<Smi> slot = args.at<Smi>(3);
2811 6437 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(4);
2812 6437 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2813 6437 : FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
2814 : // It could actually be any kind of load IC slot here but the predicate
2815 : // handles all the cases properly.
2816 6437 : if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
2817 : return ReadOnlyRoots(isolate).undefined_value();
2818 : }
2819 :
2820 : // Throw a reference error.
2821 396 : THROW_NEW_ERROR_RETURN_FAILURE(
2822 130371 : isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
2823 : }
2824 :
2825 :
2826 546346 : RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
2827 546346 : HandleScope scope(isolate);
2828 : DCHECK_EQ(5, args.length());
2829 : // Runtime functions don't follow the IC's calling convention.
2830 546346 : Handle<Object> value = args.at(0);
2831 546346 : Handle<Smi> slot = args.at<Smi>(1);
2832 546346 : Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
2833 546346 : Handle<JSObject> receiver = args.at<JSObject>(3);
2834 546346 : Handle<Name> name = args.at<Name>(4);
2835 546346 : FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
2836 :
2837 : // TODO(ishell): Cache interceptor_holder in the store handler like we do
2838 : // for LoadHandler::kInterceptor case.
2839 : Handle<JSObject> interceptor_holder = receiver;
2840 1092692 : if (receiver->IsJSGlobalProxy()) {
2841 294 : FeedbackSlotKind kind = vector->GetKind(vector_slot);
2842 294 : if (IsStoreGlobalICKind(kind)) {
2843 294 : interceptor_holder = Handle<JSObject>::cast(isolate->global_object());
2844 : }
2845 : }
2846 : DCHECK(interceptor_holder->HasNamedInterceptor());
2847 : Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(),
2848 1092692 : isolate);
2849 :
2850 : DCHECK(!interceptor->non_masking());
2851 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2852 2185384 : *receiver, Just(kDontThrow));
2853 :
2854 546346 : Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
2855 546346 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2856 546340 : if (!result.is_null()) return *value;
2857 :
2858 300294 : LookupIterator it(receiver, name, receiver);
2859 : // Skip past any access check on the receiver.
2860 300294 : if (it.state() == LookupIterator::ACCESS_CHECK) {
2861 : DCHECK(it.HasAccess());
2862 288 : it.Next();
2863 : }
2864 : // Skip past the interceptor on the receiver.
2865 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2866 300294 : it.Next();
2867 :
2868 300294 : MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed),
2869 : ReadOnlyRoots(isolate).exception());
2870 546346 : return *value;
2871 : }
2872 :
2873 :
2874 2238 : RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
2875 : // TODO(verwaest): This should probably get the holder and receiver as input.
2876 2238 : HandleScope scope(isolate);
2877 2238 : Handle<JSObject> receiver = args.at<JSObject>(0);
2878 : DCHECK_GE(args.smi_at(1), 0);
2879 2238 : uint32_t index = args.smi_at(1);
2880 :
2881 : Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
2882 4476 : isolate);
2883 : PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
2884 8952 : *receiver, Just(kDontThrow));
2885 2238 : Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
2886 :
2887 2238 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
2888 :
2889 2238 : if (result.is_null()) {
2890 0 : LookupIterator it(isolate, receiver, index, receiver);
2891 : DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
2892 0 : it.Next();
2893 0 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
2894 : Object::GetProperty(&it));
2895 : }
2896 :
2897 2238 : return *result;
2898 : }
2899 : } // namespace internal
2900 178779 : } // namespace v8
|