v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
ic.cc
Go to the documentation of this file.
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 <optional>
8#include <tuple>
9
11#include "src/ast/ast.h"
12#include "src/base/logging.h"
15#include "src/common/globals.h"
29#include "src/ic/ic-inl.h"
30#include "src/ic/ic-stats.h"
31#include "src/ic/stub-cache.h"
41#include "src/runtime/runtime.h"
44#include "src/utils/ostreams.h"
45
46#if V8_ENABLE_WEBASSEMBLY
48#endif // V8_ENABLE_WEBASSEMBLY
49
50namespace v8 {
51namespace internal {
52
53using enum InlineCacheState;
54
56 switch (state) {
57 case NO_FEEDBACK:
58 return 'X';
59 case UNINITIALIZED:
60 return '0';
61 case MONOMORPHIC:
62 return '1';
64 return '^';
65 case POLYMORPHIC:
66 return 'P';
67 case MEGAMORPHIC:
68 return 'N';
69 case MEGADOM:
70 return 'D';
71 case GENERIC:
72 return 'G';
73 }
75}
76
77namespace {
78
79const char* GetModifier(KeyedAccessLoadMode mode) {
80 switch (mode) {
82 return ".OOB";
84 return ".HOLES";
86 return ".OOB+HOLES";
88 return "";
89 }
90}
91
92const char* GetModifier(KeyedAccessStoreMode mode) {
93 switch (mode) {
95 return ".COW";
97 return ".STORE+COW";
99 return ".IGNORE_OOB";
101 return "";
102 }
103 UNREACHABLE();
104}
105
106} // namespace
107
108void IC::TraceIC(const char* type, DirectHandle<Object> name) {
110 State new_state =
111 (state() == NO_FEEDBACK) ? NO_FEEDBACK : nexus()->ic_state();
112 TraceIC(type, name, state(), new_state);
113}
114
115void IC::TraceIC(const char* type, DirectHandle<Object> name, State old_state,
116 State new_state) {
118
119 DirectHandle<Map> map = lookup_start_object_map(); // Might be empty.
120
121 const char* modifier = "";
122 if (state() == NO_FEEDBACK) {
123 modifier = "";
124 } else if (IsKeyedLoadIC()) {
125 KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
126 modifier = GetModifier(mode);
127 } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralIC() ||
129 KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
130 modifier = GetModifier(mode);
131 }
132
133 bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralIC();
134
135 if (!(TracingFlags::ic_stats.load(std::memory_order_relaxed) &
137 LOG(isolate(), ICEvent(type, keyed_prefix, map, name,
138 TransitionMarkFromState(old_state),
139 TransitionMarkFromState(new_state), modifier,
141 return;
142 }
143
145 JavaScriptFrame* frame = it.frame();
146
148 Tagged<JSFunction> function = frame->function();
149
151 ICInfo& ic_info = ICStats::instance()->Current();
152 ic_info.type = keyed_prefix ? "Keyed" : "";
153 ic_info.type += type;
154
155 int code_offset = 0;
157 std::tie(code, code_offset) = frame->GetActiveCodeAndOffset();
159 code_offset);
160
161 // Reserve enough space for IC transition state, the longest length is 17.
162 ic_info.state.reserve(17);
163 ic_info.state = "(";
164 ic_info.state += TransitionMarkFromState(old_state);
165 ic_info.state += "->";
166 ic_info.state += TransitionMarkFromState(new_state);
167 ic_info.state += modifier;
168 ic_info.state += ")";
169 if (!map.is_null()) {
170 ic_info.map = reinterpret_cast<void*>(map->ptr());
171 ic_info.is_dictionary_map = map->is_dictionary_map();
172 ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors();
173 ic_info.instance_type = std::to_string(map->instance_type());
174 } else {
175 ic_info.map = nullptr;
176 }
177 // TODO(lpy) Add name as key field in ICStats.
179}
180
183 : isolate_(isolate),
184 vector_set_(false),
185 kind_(kind),
186 target_maps_(isolate),
187 target_maps_set_(false),
188 slow_stub_reason_(nullptr),
189 nexus_(isolate, vector, slot) {
190 DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind());
191 state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.ic_state();
193}
194
195static void LookupForRead(LookupIterator* it, bool is_has_property) {
196 for (;; it->Next()) {
197 switch (it->state()) {
199 UNREACHABLE();
201 return;
203 continue; // Continue to the prototype, if present.
205 // If there is a getter, return; otherwise loop to perform the lookup.
206 DirectHandle<JSObject> holder = it->GetHolder<JSObject>();
207 {
208 Tagged<InterceptorInfo> interceptor = holder->GetNamedInterceptor();
209 if (interceptor->has_getter()) {
210 return;
211 }
212 if (is_has_property && interceptor->has_query()) {
213 return;
214 }
215 }
216 continue;
217 }
219 // ICs know how to perform access checks on global proxies.
220 if (it->GetHolder<JSObject>().is_identical_to(
221 it->isolate()->global_proxy()) &&
222 !it->isolate()->global_object()->IsDetached()) {
223 continue;
224 }
225 return;
230 return;
231 }
232 UNREACHABLE();
233 }
234}
235
237 if (!RecomputeHandlerForName(name)) return false;
238
239 // This is a contextual access, always just update the handler and stay
240 // monomorphic.
241 if (IsGlobalIC()) return true;
242
243 MaybeObjectDirectHandle maybe_handler =
244 nexus()->FindHandlerForMap(lookup_start_object_map());
245
246 // The current map wasn't handled yet. There's no reason to stay monomorphic,
247 // *unless* we're moving from a deprecated map to its replacement, or
248 // to a more general elements kind.
249 // TODO(verwaest): Check if the current map is actually what the old map
250 // would transition to.
251 if (maybe_handler.is_null()) {
252 if (!IsJSObjectMap(*lookup_start_object_map())) return false;
253 Tagged<Map> first_map = FirstTargetMap();
254 if (first_map.is_null()) return false;
255 DirectHandle<Map> old_map(first_map, isolate());
256 if (old_map->is_deprecated()) return true;
258 old_map->elements_kind(), lookup_start_object_map()->elements_kind());
259 }
260
261 return true;
262}
263
265 if (is_keyed()) {
266 // Determine whether the failure is due to a name failure.
267 if (!IsName(*name)) return false;
268 Tagged<Name> stub_name = nexus()->GetName();
269 if (*name != stub_name) return false;
270 }
271
272 return true;
273}
274
275void IC::UpdateState(DirectHandle<Object> lookup_start_object,
277 if (state() == NO_FEEDBACK) return;
278 update_lookup_start_object_map(lookup_start_object);
279 if (!IsString(*name)) return;
280 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
281 if (IsNullOrUndefined(*lookup_start_object, isolate())) return;
282
283 // Remove the target from the code cache if it became invalid
284 // because of changes in the prototype chain to avoid hitting it
285 // again.
288 }
289}
290
292 Handle<Object> object,
294 HandleScope scope(isolate());
295 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object));
296}
297
299 HandleScope scope(isolate());
301 NewReferenceError(MessageTemplate::kNotDefined, name));
302}
303
304void IC::OnFeedbackChanged(const char* reason) {
305 vector_set_ = true;
306 Tagged<FeedbackVector> vector = nexus()->vector();
307 FeedbackSlot slot = nexus()->slot();
308 OnFeedbackChanged(isolate(), vector, slot, reason);
309}
310
311// static
313 FeedbackSlot slot, const char* reason) {
314#ifdef V8_TRACE_FEEDBACK_UPDATES
315 if (v8_flags.trace_feedback_updates) {
316 FeedbackVector::TraceFeedbackChange(isolate, vector, slot, reason);
317 }
318#endif
319
320 isolate->tiering_manager()->NotifyICChanged(vector);
321}
322
323namespace {
324
325bool MigrateDeprecated(Isolate* isolate, DirectHandle<Object> object) {
326 if (!IsJSObject(*object)) return false;
328 if (!receiver->map()->is_deprecated()) return false;
330 return true;
331}
332
333} // namespace
334
336 DCHECK_EQ(MEGAMORPHIC, new_state);
337 DCHECK_IMPLIES(!is_keyed(), IsName(*key));
338 bool changed = nexus()->ConfigureMegamorphic(
340 if (changed) {
341 OnFeedbackChanged("Megamorphic");
342 }
343 return changed;
344}
345
350
352 const MaybeObjectDirectHandle& handler) {
353 if (IsGlobalIC()) {
354 nexus()->ConfigureHandlerMode(handler);
355 } else {
356 // Non-keyed ICs don't track the name explicitly.
357 if (!is_keyed()) name = Handle<Name>::null();
358 nexus()->ConfigureMonomorphic(name, map, handler);
359 }
360
361 OnFeedbackChanged(IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic");
362}
363
365 MaybeObjectHandles* handlers) {
366 DCHECK(!IsGlobalIC());
367 MapsAndHandlers maps_and_handlers(isolate());
368 maps_and_handlers.reserve(maps.size());
369 DCHECK_EQ(maps.size(), handlers->size());
370 for (size_t i = 0; i < maps.size(); i++) {
371 maps_and_handlers.emplace_back(maps[i], handlers->at(i));
372 }
373 ConfigureVectorState(name, maps_and_handlers);
374}
375
377 MapsAndHandlers const& maps_and_handlers) {
378 DCHECK(!IsGlobalIC());
379 // Non-keyed ICs don't track the name explicitly.
380 if (!is_keyed()) name = Handle<Name>::null();
381 nexus()->ConfigurePolymorphic(name, maps_and_handlers);
382
383 OnFeedbackChanged("Polymorphic");
384}
385
387 bool update_feedback,
389 bool use_ic = (state() != NO_FEEDBACK) && v8_flags.use_ic && update_feedback;
390
391 if (receiver.is_null()) {
392 receiver = object;
393 }
394
395 // If the object is undefined or null it's illegal to try to get any
396 // of its properties; throw a TypeError in that case.
397 if (IsAnyHas() ? !IsJSReceiver(*object)
398 : IsNullOrUndefined(*object, isolate())) {
399 if (use_ic) {
400 // Ensure the IC state progresses.
401 TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
404 TraceIC("LoadIC", name);
405 }
406
407 if (IsAnyHas()) {
408 return TypeError(MessageTemplate::kInvalidInOperatorUse, object, name);
409 } else {
410 DCHECK(IsNullOrUndefined(*object, isolate()));
413 }
414 }
415
416 // If we encounter an object with a deprecated map, we want to update the
417 // feedback vector with the migrated map.
418 // Mark ourselves as RECOMPUTE_HANDLER so that we don't turn megamorphic due
419 // to seeing the same map and handler.
420 if (MigrateDeprecated(isolate(), object)) {
421 UpdateState(object, name);
422 }
423
426
427 PropertyKey key(isolate(), name);
429
430 // Named lookup in the object.
431 LookupForRead(&it, IsAnyHas());
432
433 if (it.IsFound() || !ShouldThrowReferenceError()) {
434 // Update inline cache and stub cache.
435 if (use_ic) {
436 UpdateCaches(&it);
437 } else if (state() == NO_FEEDBACK) {
438 // Tracing IC stats
439 IsLoadGlobalIC() ? TraceIC("LoadGlobalIC", name)
440 : TraceIC("LoadIC", name);
441 }
442
443 if (IsAnyHas()) {
444 // Named lookup in the object.
446 if (maybe.IsNothing()) return MaybeDirectHandle<Object>();
447 return isolate()->factory()->ToBoolean(maybe.FromJust());
448 }
449
450 // Get the property.
452
455 if (it.IsFound()) {
456 return result;
457 } else if (!ShouldThrowReferenceError()) {
458 return result;
459 }
460 }
461 return ReferenceError(name);
462}
463
465 bool update_feedback) {
467
468 if (IsString(*name)) {
469 // Look up in script context table.
470 DirectHandle<String> str_name = Cast<String>(name);
471 DirectHandle<ScriptContextTable> script_contexts(
472 global->native_context()->script_context_table(), isolate());
473
474 VariableLookupResult lookup_result;
475 if (script_contexts->Lookup(str_name, &lookup_result)) {
476 DirectHandle<Context> script_context(
477 script_contexts->get(lookup_result.context_index), isolate());
478 DirectHandle<Object> result(script_context->get(lookup_result.slot_index),
479 isolate());
480
481 if (IsTheHole(*result, isolate())) {
482 // Do not install stubs and stay pre-monomorphic for
483 // uninitialized accesses.
485 isolate(),
486 NewReferenceError(MessageTemplate::kAccessedUninitializedVariable,
487 name));
488 }
489
490 bool use_ic =
491 (state() != NO_FEEDBACK) && v8_flags.use_ic && update_feedback;
492 if (use_ic) {
493 // 'const' Variables are mutable if REPL mode is enabled. This disables
494 // compiler inlining for all 'const' variables declared in REPL mode.
495 if (nexus()->ConfigureLexicalVarMode(
496 lookup_result.context_index, lookup_result.slot_index,
497 (IsImmutableLexicalVariableMode(lookup_result.mode) &&
498 !lookup_result.is_repl_mode))) {
499 TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
500 } else {
501 // Given combination of indices can't be encoded, so use slow stub.
502 TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
504 }
505 TraceIC("LoadGlobalIC", name);
506 } else if (state() == NO_FEEDBACK) {
507 TraceIC("LoadGlobalIC", name);
508 }
509 if (v8_flags.script_context_mutable_heap_number) {
510 return direct_handle(
512 script_context, lookup_result.slot_index, result, isolate()),
513 isolate());
514 }
515 return result;
516 }
517 }
518 return LoadIC::Load(global, name, update_feedback);
519}
520
521namespace {
522
523bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
524 Handle<Map> new_receiver_map) {
525 DCHECK(!new_receiver_map.is_null());
526 for (DirectHandle<Map> map : *receiver_maps) {
527 if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
528 return false;
529 }
530 }
531 receiver_maps->push_back(new_receiver_map);
532 return true;
533}
534
535bool AddOneReceiverMapIfMissing(MapsAndHandlers* receiver_maps_and_handlers,
536 Handle<Map> new_receiver_map) {
537 DCHECK(!new_receiver_map.is_null());
538 if (new_receiver_map->is_deprecated()) return false;
539 for (DirectHandle<Map> map : receiver_maps_and_handlers->maps()) {
540 if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
541 return false;
542 }
543 }
544 receiver_maps_and_handlers->emplace_back(new_receiver_map, {});
545 return true;
546}
547
548DirectHandle<NativeContext> GetAccessorContext(
549 const CallOptimization& call_optimization, Tagged<Map> holder_map,
550 Isolate* isolate) {
551 std::optional<Tagged<NativeContext>> maybe_context =
552 call_optimization.GetAccessorContext(holder_map);
553
554 // Holders which are remote objects are not expected in the IC system.
555 CHECK(maybe_context.has_value());
556 return direct_handle(maybe_context.value(), isolate);
557}
558
559} // namespace
560
562 DirectHandle<Name> name) {
563 if (!v8_flags.mega_dom_ic) return false;
564
565 // TODO(gsathya): Enable fuzzing once this feature is more stable.
566 if (v8_flags.fuzzing) return false;
567
568 // TODO(gsathya): Support KeyedLoadIC, StoreIC and KeyedStoreIC.
569 if (!IsLoadIC()) return false;
570
571 // Check if DOM protector cell is valid.
572 if (!Protectors::IsMegaDOMIntact(isolate())) return false;
573
574 // Check if current lookup object is an API object
576 if (!InstanceTypeChecker::IsJSApiObject(map->instance_type())) return false;
577
578 Handle<Object> accessor_obj;
579 // TODO(gsathya): Check if there are overloads possible for this accessor and
580 // transition only if it isn't possible.
581 if (!accessor().ToHandle(&accessor_obj)) return false;
582
583 // TODO(gsathya): This is also created in IC::ComputeHandler, find a way to
584 // reuse it here.
585 CallOptimization call_optimization(isolate(), accessor_obj);
586
587 // Check if accessor is an API function
588 if (!call_optimization.is_simple_api_call()) return false;
589
590 // Check if accessor requires access checks
591 if (call_optimization.accept_any_receiver()) return false;
592
593 // Check if accessor requires signature checks
594 if (!call_optimization.requires_signature_check()) return false;
595
596 // Check if the receiver is the holder
597 CallOptimization::HolderLookup holder_lookup;
598 call_optimization.LookupHolderOfExpectedType(isolate(), map, &holder_lookup);
599 if (holder_lookup != CallOptimization::kHolderIsReceiver) return false;
600
601 DirectHandle<NativeContext> accessor_context =
602 GetAccessorContext(call_optimization, *map, isolate());
603
605 if (IsJSFunction(*accessor_obj)) {
606 fti = direct_handle(
607 Cast<JSFunction>(*accessor_obj)->shared()->api_func_data(), isolate());
608 } else {
609 fti = Cast<FunctionTemplateInfo>(accessor_obj);
610 }
611
612 DirectHandle<MegaDomHandler> new_handler =
615 MaybeObjectDirectHandle::Weak(accessor_context));
616 nexus()->ConfigureMegaDOM(MaybeObjectDirectHandle(new_handler));
617 return true;
618}
619
621 const MaybeObjectDirectHandle& handler) {
622 DCHECK(IsHandler(*handler));
623 if (is_keyed() && state() != RECOMPUTE_HANDLER) {
624 if (nexus()->GetName() != *name) return false;
625 }
627
628 MapsAndHandlers maps_and_handlers(isolate());
629 maps_and_handlers.reserve(v8_flags.max_valid_polymorphic_map_count);
630 int deprecated_maps = 0;
631 int handler_to_overwrite = -1;
632
633 {
635 int i = 0;
636 for (FeedbackIterator it(nexus()); !it.done(); it.Advance()) {
637 if (it.handler().IsCleared()) continue;
638 MaybeObjectDirectHandle existing_handler(it.handler(), isolate());
639 DirectHandle<Map> existing_map(it.map(), isolate());
640
641 maps_and_handlers.emplace_back(existing_map, existing_handler);
642
643 if (existing_map->is_deprecated()) {
644 // Filter out deprecated maps to ensure their instances get migrated.
645 deprecated_maps++;
646 } else if (map.is_identical_to(existing_map)) {
647 // If both map and handler stayed the same (and the name is also the
648 // same as checked above, for keyed accesses), we're not progressing
649 // in the lattice and need to go MEGAMORPHIC instead. There's one
650 // exception to this rule, which is when we're in RECOMPUTE_HANDLER
651 // state, there we allow to migrate to a new handler.
652 if (handler.is_identical_to(existing_handler) &&
653 state() != RECOMPUTE_HANDLER) {
654 return false;
655 }
656
657 // If the receiver type is already in the polymorphic IC, this indicates
658 // there was a prototoype chain failure. In that case, just overwrite
659 // the handler.
660 handler_to_overwrite = i;
661 } else if (handler_to_overwrite == -1 &&
662 IsTransitionOfMonomorphicTarget(*existing_map, *map)) {
663 handler_to_overwrite = i;
664 }
665
666 i++;
667 }
668 DCHECK_LE(i, maps_and_handlers.size());
669 }
670
671 int number_of_maps = static_cast<int>(maps_and_handlers.size());
672 int number_of_valid_maps =
673 number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
674
675 if (number_of_valid_maps >= v8_flags.max_valid_polymorphic_map_count) {
676 return false;
677 }
678 if (deprecated_maps >= v8_flags.max_valid_polymorphic_map_count) {
679 return false;
680 }
681 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
682 return false;
683 }
684
685 number_of_valid_maps++;
686 if (number_of_valid_maps == 1) {
688 } else {
689 if (is_keyed() && nexus()->GetName() != *name) return false;
690 if (handler_to_overwrite >= 0) {
691 maps_and_handlers.set_handler(handler_to_overwrite, handler);
692 if (!map.is_identical_to(
693 maps_and_handlers.maps()[handler_to_overwrite])) {
694 maps_and_handlers.set_map(handler_to_overwrite, map);
695 }
696 } else {
697 maps_and_handlers.emplace_back(map, handler);
698 }
699
700 ConfigureVectorState(name, maps_and_handlers);
701 }
702
703 return true;
704}
705
707 DirectHandle<Name> name) {
708 DCHECK(IsHandler(*handler));
710}
711
713 MapsAndHandlers maps_and_handlers(isolate());
714 nexus()->ExtractMapsAndHandlers(&maps_and_handlers);
715 for (auto [map, handler] : maps_and_handlers) {
716 UpdateMegamorphicCache(map, name, handler);
717 }
718}
719
721 Tagged<Map> target_map) {
722 if (source_map.is_null()) return true;
723 if (target_map.is_null()) return false;
724 if (source_map->is_abandoned_prototype_map()) return false;
725 ElementsKind target_elements_kind = target_map->elements_kind();
726 bool more_general_transition = IsMoreGeneralElementsKindTransition(
727 source_map->elements_kind(), target_elements_kind);
728 Tagged<Map> transitioned_map;
729 if (more_general_transition) {
730 DirectHandle<Map> single_map[1] = {direct_handle(target_map, isolate_)};
731 transitioned_map = source_map->FindElementsKindTransitionedMap(
733 }
734 return transitioned_map == target_map;
735}
736
738 SetCache(name, MaybeObjectHandle(handler));
739}
740
742 DCHECK(IsHandler(*handler));
743 // Currently only load and store ICs support non-code handlers.
744 DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas());
745 switch (state()) {
746 case NO_FEEDBACK:
747 UNREACHABLE();
748 case UNINITIALIZED:
749 UpdateMonomorphicIC(handler, name);
750 break;
752 case MONOMORPHIC:
753 if (IsGlobalIC()) {
754 UpdateMonomorphicIC(handler, name);
755 break;
756 }
757 [[fallthrough]];
758 case POLYMORPHIC:
759 if (UpdatePolymorphicIC(name, handler)) break;
760 if (UpdateMegaDOMIC(handler, name)) break;
761 if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
763 }
764 [[fallthrough]];
765 case MEGADOM:
767 [[fallthrough]];
768 case MEGAMORPHIC:
770 // Indicate that we've handled this case.
771 vector_set_ = true;
772 break;
773 case GENERIC:
774 UNREACHABLE();
775 }
776}
777
780 if (lookup->state() == LookupIterator::ACCESS_CHECK) {
782 } else if (!lookup->IsFound()) {
783 if (lookup->IsPrivateName()) {
785 } else {
786 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
790 MaybeObjectDirectHandle(isolate()->factory()->null_value()),
791 smi_handler));
792 }
793 } else if (IsLoadGlobalIC() && lookup->state() == LookupIterator::JSPROXY) {
794 // If there is proxy just install the slow stub since we need to call the
795 // HasProperty trap for global loads. The ProxyGetProperty builtin doesn't
796 // handle this case.
798 } else {
799 if (IsLoadGlobalIC()) {
800 if (lookup->TryLookupCachedProperty()) {
802 }
803 if (lookup->state() == LookupIterator::DATA &&
804 lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
805 DCHECK(IsJSGlobalObject(*lookup->GetReceiver()));
806 // Now update the cell in the feedback vector.
807 nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
808 TraceIC("LoadGlobalIC", lookup->name());
809 return;
810 }
811 }
812 handler = ComputeHandler(lookup);
813 auto holder = lookup->GetHolder<Object>();
814 CHECK(*holder == *(lookup->lookup_start_object()) ||
816 IsJSPrimitiveWrapper(*holder));
817 }
818 // Can't use {lookup->name()} because the LookupIterator might be in
819 // "elements" mode for keys that are strings representing integers above
820 // JSArray::kMaxIndex.
821 SetCache(lookup->GetName(), handler);
822 TraceIC("LoadIC", lookup->GetName());
823}
824
826 // HasICs and each of the store own ICs require its own stub cache.
827 // Until we create them, don't allow accessing the load/store stub caches.
828 DCHECK(!IsAnyHas());
829 if (IsAnyLoad()) {
830 return isolate()->load_stub_cache();
831 } else if (IsAnyDefineOwn()) {
832 return isolate()->define_own_stub_cache();
833 } else {
835 return isolate()->store_stub_cache();
836 }
837}
838
840 const MaybeObjectDirectHandle& handler) {
841 if (!IsAnyHas()) {
842 stub_cache()->Set(*name, *map, *handler);
843 }
844}
845
848 ReadOnlyRoots roots(isolate());
849
850 DirectHandle<Object> lookup_start_object = lookup->lookup_start_object();
851 // `in` cannot be called on strings, and will always return true for string
852 // wrapper length and function prototypes. The latter two cases are given
853 // LoadHandler::LoadNativeDataProperty below.
854 if (!IsAnyHas() && !lookup->IsElement()) {
855 if (IsString(*lookup_start_object) &&
856 *lookup->name() == roots.length_string()) {
857 TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
858 return MaybeObjectHandle(BUILTIN_CODE(isolate(), LoadIC_StringLength));
859 }
860
861 if (IsStringWrapper(*lookup_start_object) &&
862 *lookup->name() == roots.length_string()) {
863 TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
864 return MaybeObjectHandle(
865 BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength));
866 }
867
868 // Use specialized code for getting prototype of functions.
869 if (IsJSFunction(*lookup_start_object) &&
870 *lookup->name() == roots.prototype_string() &&
871 !Cast<JSFunction>(*lookup_start_object)
872 ->PrototypeRequiresRuntimeLookup()) {
873 TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
874 return MaybeObjectHandle(
875 BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype));
876 }
877 }
878
880 bool holder_is_lookup_start_object =
881 lookup_start_object.is_identical_to(lookup->GetHolder<JSReceiver>());
882
883 switch (lookup->state()) {
885 DirectHandle<JSObject> holder = lookup->GetHolder<JSObject>();
887
888 if (holder->GetNamedInterceptor()->non_masking()) {
889 MaybeObjectDirectHandle holder_ref(isolate()->factory()->null_value());
890 if (!holder_is_lookup_start_object || IsLoadGlobalIC()) {
891 holder_ref = MaybeObjectDirectHandle::Weak(holder);
892 }
893 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
895 isolate(), map, holder_ref, smi_handler));
896 }
897
898 if (holder_is_lookup_start_object) {
899 DCHECK(map->has_named_interceptor());
900 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
901 return MaybeObjectHandle(smi_handler);
902 }
903
904 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
905 return MaybeObjectHandle(
906 LoadHandler::LoadFromPrototype(isolate(), map, holder, *smi_handler));
907 }
908
910 Handle<JSObject> holder =
911 indirect_handle(lookup->GetHolder<JSObject>(), isolate());
912 // Use simple field loads for some well-known callback properties.
913 // The method will only return true for absolute truths based on the
914 // lookup start object maps.
915 FieldIndex field_index;
916 if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
917 &field_index)) {
918 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
919 return MaybeObjectHandle(
920 LoadHandler::LoadField(isolate(), field_index));
921 }
922 if (IsJSModuleNamespace(*holder)) {
924 Cast<JSModuleNamespace>(holder)->module()->exports(), isolate());
925 InternalIndex entry =
926 exports->FindEntry(isolate(), roots, lookup->name(),
927 Smi::ToInt(Object::GetHash(*lookup->name())));
928 // We found the accessor, so the entry must exist.
929 DCHECK(entry.is_found());
930 int value_index = ObjectHashTable::EntryToValueIndex(entry);
931 Handle<Smi> smi_handler =
933 if (holder_is_lookup_start_object) {
934 return MaybeObjectHandle(smi_handler);
935 }
937 isolate(), map, holder, *smi_handler));
938 }
939
940 DirectHandle<Object> accessors = lookup->GetAccessors();
941 if (IsAccessorPair(*accessors)) {
942 DirectHandle<AccessorPair> accessor_pair =
943 Cast<AccessorPair>(accessors);
944 if (lookup->TryLookupCachedProperty(accessor_pair)) {
946 return MaybeObjectHandle(ComputeHandler(lookup));
947 }
948
949 Handle<Object> getter(accessor_pair->getter(), isolate());
950 if (!IsCallableJSFunction(*getter) &&
951 !IsFunctionTemplateInfo(*getter)) {
952 // TODO(jgruber): Update counter name.
953 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
955 }
957
958 if ((IsFunctionTemplateInfo(*getter) &&
959 Cast<FunctionTemplateInfo>(*getter)->BreakAtEntry(isolate())) ||
960 (IsJSFunction(*getter) &&
961 Cast<JSFunction>(*getter)->shared()->BreakAtEntry(isolate()))) {
962 // Do not install an IC if the api function has a breakpoint.
963 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
965 }
966
967 Handle<Smi> smi_handler;
968
969 CallOptimization call_optimization(isolate(), getter);
970 if (call_optimization.is_simple_api_call()) {
971 CallOptimization::HolderLookup holder_lookup;
972 DirectHandle<JSObject> api_holder =
973 call_optimization.LookupHolderOfExpectedType(isolate(), map,
974 &holder_lookup);
975
976 if (!call_optimization.IsCompatibleReceiverMap(api_holder, holder,
977 holder_lookup) ||
978 !holder->HasFastProperties()) {
979 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
981 }
982
983 smi_handler = LoadHandler::LoadApiGetter(isolate());
984
985 DirectHandle<NativeContext> accessor_context =
986 GetAccessorContext(call_optimization, holder->map(), isolate());
987
988 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
990 isolate(), map, holder, *smi_handler,
991 MaybeObjectDirectHandle::Weak(call_optimization.api_call_info()),
992 MaybeObjectDirectHandle::Weak(accessor_context)));
993 }
994
995 if (holder->HasFastProperties()) {
996 DCHECK(IsCallableJSFunction(*getter));
997 if (holder_is_lookup_start_object) {
998 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
1000 indirect_handle(accessor_pair, isolate()));
1001 }
1002 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
1004 isolate(), map, holder,
1007 }
1008
1009 if (IsJSGlobalObject(*holder)) {
1010 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
1011 smi_handler = LoadHandler::LoadGlobal(isolate());
1013 isolate(), map, holder, *smi_handler,
1015 } else {
1016 smi_handler = LoadHandler::LoadNormal(isolate());
1017 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1018 if (holder_is_lookup_start_object)
1019 return MaybeObjectHandle(smi_handler);
1020 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1021 }
1022
1024 isolate(), map, holder, *smi_handler));
1025 }
1026
1028
1029 if (info->replace_on_access()) {
1031 "getter needs to be reconfigured to data property");
1032 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1034 }
1035
1036 if (!info->has_getter(isolate()) || !holder->HasFastProperties() ||
1037 (info->is_sloppy() && !IsJSReceiver(*receiver))) {
1038 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1040 }
1041
1043 isolate(), lookup->GetAccessorIndex());
1044 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
1045 if (holder_is_lookup_start_object) return MaybeObjectHandle(smi_handler);
1047 LoadIC_LoadNativeDataPropertyFromPrototypeDH);
1048 return MaybeObjectHandle(
1049 LoadHandler::LoadFromPrototype(isolate(), map, holder, *smi_handler));
1050 }
1051
1052 case LookupIterator::DATA: {
1053 DirectHandle<JSReceiver> holder = lookup->GetHolder<JSReceiver>();
1055 Handle<Smi> smi_handler;
1056 if (lookup->is_dictionary_holder()) {
1057 if (IsJSGlobalObject(*holder, isolate())) {
1058 // TODO(verwaest): Also supporting the global object as receiver is a
1059 // workaround for code that leaks the global object.
1060 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
1061 smi_handler = LoadHandler::LoadGlobal(isolate());
1063 isolate(), map, holder, *smi_handler,
1065 }
1066 smi_handler = LoadHandler::LoadNormal(isolate());
1067 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
1068 if (holder_is_lookup_start_object)
1069 return MaybeObjectHandle(smi_handler);
1070 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
1071 } else if (lookup->IsElement(*holder)) {
1072 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
1074 } else {
1076 lookup->property_details().location());
1077 DCHECK(IsJSObject(*holder, isolate()));
1078 FieldIndex field = lookup->GetFieldIndex();
1079 smi_handler = LoadHandler::LoadField(isolate(), field);
1080 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
1081 if (holder_is_lookup_start_object)
1082 return MaybeObjectHandle(smi_handler);
1083 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
1084 }
1085 if (lookup->constness() == PropertyConstness::kConst &&
1086 !holder_is_lookup_start_object) {
1088 !lookup->is_dictionary_holder());
1089
1090 DirectHandle<Object> value = lookup->GetDataValue();
1091
1092 if (IsThinString(*value)) {
1093 value = direct_handle(Cast<ThinString>(*value)->actual(), isolate());
1094 }
1095
1096 // Non internalized strings could turn into thin/cons strings
1097 // when internalized. Weak references to thin/cons strings are
1098 // not supported in the GC. If concurrent marking is running
1099 // and the thin/cons string is marked but the actual string is
1100 // not, then the weak reference could be missed.
1101 if (!IsString(*value) ||
1102 (IsString(*value) && IsInternalizedString(*value))) {
1103 MaybeObjectDirectHandle weak_value =
1104 IsSmi(*value) ? MaybeObjectHandle(*value, isolate())
1105 : MaybeObjectHandle::Weak(*value, isolate());
1106
1108 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
1110 isolate(), map, holder, *smi_handler, weak_value));
1111 }
1112 }
1113 return MaybeObjectHandle(
1114 LoadHandler::LoadFromPrototype(isolate(), map, holder, *smi_handler));
1115 }
1117 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
1119
1121 // Private names on JSProxy is currently not supported.
1122 if (lookup->name()->IsPrivate()) {
1124 }
1126 if (holder_is_lookup_start_object) return MaybeObjectHandle(smi_handler);
1127
1128 DirectHandle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
1130 isolate(), map, holder_proxy, *smi_handler));
1131 }
1132
1137 UNREACHABLE();
1138 }
1139
1141}
1142
1144 DirectHandle<Map> receiver_map) const {
1145 const MaybeObjectDirectHandle& handler =
1146 nexus()->FindHandlerForMap(receiver_map);
1147 if (handler.is_null()) return KeyedAccessLoadMode::kInBounds;
1148 return LoadHandler::GetKeyedAccessLoadMode(*handler);
1149}
1150
1151// Returns whether the load mode transition is allowed.
1153 KeyedAccessLoadMode new_mode) {
1154 // Only allow transitions to allow OOB or allow converting a hole to
1155 // undefined.
1156 using T = std::underlying_type_t<KeyedAccessLoadMode>;
1157 return ((static_cast<T>(old_mode) ^
1158 static_cast<T>(GeneralizeKeyedAccessLoadMode(old_mode, new_mode))) &
1159 0b11) != 0;
1160}
1161
1163 const KeyedAccessLoadMode new_load_mode) {
1164 Handle<Map> receiver_map(receiver->map(), isolate());
1165 DCHECK(receiver_map->instance_type() !=
1166 JS_PRIMITIVE_WRAPPER_TYPE); // Checked by caller.
1167 MapHandles target_receiver_maps(isolate());
1168 TargetMaps(&target_receiver_maps);
1169
1170 if (target_receiver_maps.empty()) {
1171 DirectHandle<Object> handler =
1172 LoadElementHandler(receiver_map, new_load_mode);
1173 return ConfigureVectorState(DirectHandle<Name>(), receiver_map, handler);
1174 }
1175
1176 for (DirectHandle<Map> map : target_receiver_maps) {
1177 if (map.is_null()) continue;
1178 if (map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
1179 set_slow_stub_reason("JSPrimitiveWrapper");
1180 return;
1181 }
1182 if (map->instance_type() == JS_PROXY_TYPE) {
1183 set_slow_stub_reason("JSProxy");
1184 return;
1185 }
1186 }
1187
1188 // The first time a receiver is seen that is a transitioned version of the
1189 // previous monomorphic receiver type, assume the new ElementsKind is the
1190 // monomorphic type. This benefits global arrays that only transition
1191 // once, and all call sites accessing them are faster if they remain
1192 // monomorphic. If this optimistic assumption is not true, the IC will
1193 // miss again and it will become polymorphic and support both the
1194 // untransitioned and transitioned maps.
1195 if (state() == MONOMORPHIC) {
1196 if ((IsJSObject(*receiver) &&
1198 target_receiver_maps.at(0)->elements_kind(),
1199 Cast<JSObject>(receiver)->GetElementsKind())) ||
1201 DirectHandle<Object> handler =
1202 LoadElementHandler(receiver_map, new_load_mode);
1203 return ConfigureVectorState(DirectHandle<Name>(), receiver_map, handler);
1204 }
1205 }
1206
1207 DCHECK(state() != GENERIC);
1208
1209 // Determine the list of receiver maps that this call site has seen,
1210 // adding the map that was just encountered.
1212 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1213 old_load_mode = GetKeyedAccessLoadModeFor(receiver_map);
1214 if (!AllowedHandlerChange(old_load_mode, new_load_mode)) {
1215 set_slow_stub_reason("same map added twice");
1216 return;
1217 }
1218 }
1219
1220 // If the maximum number of receiver maps has been exceeded, use the generic
1221 // version of the IC.
1222 if (static_cast<int>(target_receiver_maps.size()) >
1223 v8_flags.max_valid_polymorphic_map_count) {
1224 set_slow_stub_reason("max polymorph exceeded");
1225 return;
1226 }
1227
1228 MaybeObjectHandles handlers;
1229 handlers.reserve(target_receiver_maps.size());
1230 KeyedAccessLoadMode load_mode =
1231 GeneralizeKeyedAccessLoadMode(old_load_mode, new_load_mode);
1232 LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode);
1233 if (target_receiver_maps.empty()) {
1234 DirectHandle<Object> handler =
1235 LoadElementHandler(receiver_map, new_load_mode);
1236 ConfigureVectorState(DirectHandle<Name>(), receiver_map, handler);
1237 } else if (target_receiver_maps.size() == 1) {
1238 ConfigureVectorState(DirectHandle<Name>(), target_receiver_maps[0],
1239 handlers[0]);
1240 } else {
1242 MapHandlesSpan(target_receiver_maps.begin(),
1243 target_receiver_maps.end()),
1244 &handlers);
1245 }
1246}
1247
1248namespace {
1249
1250bool AllowConvertHoleElementToUndefined(Isolate* isolate,
1251 DirectHandle<Map> receiver_map) {
1252 if (IsJSTypedArrayMap(*receiver_map)) {
1253 // For JSTypedArray we never lookup elements in the prototype chain.
1254 return true;
1255 }
1256
1257 // For other {receiver}s we need to check the "no elements" protector.
1258 if (Protectors::IsNoElementsIntact(isolate)) {
1259 if (IsStringMap(*receiver_map)) {
1260 return true;
1261 }
1262 if (IsJSObjectMap(*receiver_map)) {
1263 // For other JSObjects (including JSArrays) we can only continue if
1264 // the {receiver}s prototype is either the initial Object.prototype
1265 // or the initial Array.prototype, which are both guarded by the
1266 // "no elements" protector checked above.
1267 DirectHandle<HeapObject> receiver_prototype(receiver_map->prototype(),
1268 isolate);
1269 InstanceType prototype_type = receiver_prototype->map()->instance_type();
1270 if (prototype_type == JS_OBJECT_PROTOTYPE_TYPE ||
1271 (prototype_type == JS_ARRAY_TYPE &&
1272 isolate->IsInCreationContext(
1273 Cast<JSObject>(*receiver_prototype),
1274 Context::INITIAL_ARRAY_PROTOTYPE_INDEX))) {
1275 return true;
1276 }
1277 }
1278 }
1279
1280 return false;
1281}
1282
1283bool IsOutOfBoundsAccess(DirectHandle<Object> receiver, size_t index) {
1284 size_t length;
1285 if (IsJSArray(*receiver)) {
1286 length = Object::NumberValue(Cast<JSArray>(*receiver)->length());
1287 } else if (IsJSTypedArray(*receiver)) {
1288 length = Cast<JSTypedArray>(*receiver)->GetLength();
1289 } else if (IsJSObject(*receiver)) {
1290 length = Cast<JSObject>(*receiver)->elements()->length();
1291 } else if (IsString(*receiver)) {
1292 length = Cast<String>(*receiver)->length();
1293 } else {
1294 return false;
1295 }
1296 return index >= length;
1297}
1298
1299bool AllowReadingHoleElement(ElementsKind elements_kind) {
1300 return IsHoleyElementsKind(elements_kind);
1301}
1302
1303KeyedAccessLoadMode GetNewKeyedLoadMode(Isolate* isolate,
1304 DirectHandle<HeapObject> receiver,
1305 size_t index, bool is_found) {
1306 DirectHandle<Map> receiver_map(Cast<HeapObject>(receiver)->map(), isolate);
1307 if (!AllowConvertHoleElementToUndefined(isolate, receiver_map)) {
1309 }
1310
1311 // Always handle holes when the elements kind is HOLEY_ELEMENTS, since the
1312 // optimizer compilers can not benefit from this information to narrow the
1313 // type. That is, the load type will always just be a generic tagged value.
1314 // This avoid an IC miss if we see a hole.
1315 ElementsKind elements_kind = receiver_map->elements_kind();
1316 bool always_handle_holes = (elements_kind == HOLEY_ELEMENTS);
1317
1318 // In bound access and did not read a hole.
1319 if (is_found) {
1320 return always_handle_holes ? KeyedAccessLoadMode::kHandleHoles
1322 }
1323
1324 // OOB access.
1325 bool is_oob_access = IsOutOfBoundsAccess(receiver, index);
1326 if (is_oob_access) {
1327 return always_handle_holes ? KeyedAccessLoadMode::kHandleOOBAndHoles
1329 }
1330
1331 // Read a hole.
1332 DCHECK(!is_found && !is_oob_access);
1333 bool handle_hole = AllowReadingHoleElement(elements_kind);
1334 DCHECK_IMPLIES(always_handle_holes, handle_hole);
1335 return handle_hole ? KeyedAccessLoadMode::kHandleHoles
1337}
1338
1339KeyedAccessLoadMode GetUpdatedLoadModeForMap(Isolate* isolate,
1340 DirectHandle<Map> map,
1341 KeyedAccessLoadMode load_mode) {
1342 // If we are not allowed to convert a hole to undefined, then we should not
1343 // handle OOB nor reading holes.
1344 if (!AllowConvertHoleElementToUndefined(isolate, map)) {
1346 }
1347 // Check if the elements kind allow reading a hole.
1348 bool allow_reading_hole_element =
1349 AllowReadingHoleElement(map->elements_kind());
1350 switch (load_mode) {
1353 return load_mode;
1355 return allow_reading_hole_element ? KeyedAccessLoadMode::kHandleHoles
1358 return allow_reading_hole_element
1361 }
1362}
1363
1364} // namespace
1365
1367 DirectHandle<Map> receiver_map, KeyedAccessLoadMode new_load_mode) {
1368 // Has a getter interceptor, or is any has and has a query interceptor.
1369 if (receiver_map->has_indexed_interceptor() &&
1370 (receiver_map->GetIndexedInterceptor()->has_getter() ||
1371 (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) &&
1372 !receiver_map->GetIndexedInterceptor()->non_masking()) {
1373 // TODO(jgruber): Update counter name.
1374 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
1375 return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC)
1376 : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
1377 }
1378
1379 InstanceType instance_type = receiver_map->instance_type();
1380 if (instance_type < FIRST_NONSTRING_TYPE) {
1381 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
1382 if (IsAnyHas()) return LoadHandler::LoadSlow(isolate());
1383 return LoadHandler::LoadIndexedString(isolate(), new_load_mode);
1384 }
1385 if (instance_type < FIRST_JS_RECEIVER_TYPE) {
1386 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1388 }
1389 if (instance_type == JS_PROXY_TYPE) {
1391 }
1392#if V8_ENABLE_WEBASSEMBLY
1393 if (InstanceTypeChecker::IsWasmObject(instance_type)) {
1394 // TODO(jgruber): Update counter name.
1395 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
1397 }
1398#endif // V8_ENABLE_WEBASSEMBLY
1399
1400 ElementsKind elements_kind = receiver_map->elements_kind();
1401 if (IsSloppyArgumentsElementsKind(elements_kind)) {
1402 // TODO(jgruber): Update counter name.
1403 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
1404 return IsAnyHas() ? BUILTIN_CODE(isolate(), KeyedHasIC_SloppyArguments)
1405 : BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
1406 }
1407 bool is_js_array = instance_type == JS_ARRAY_TYPE;
1408 if (elements_kind == DICTIONARY_ELEMENTS) {
1409 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1410 return LoadHandler::LoadElement(isolate(), elements_kind, is_js_array,
1411 new_load_mode);
1412 }
1413 DCHECK(IsFastElementsKind(elements_kind) ||
1414 IsAnyNonextensibleElementsKind(elements_kind) ||
1417 LoadModeHandlesHoles(new_load_mode),
1418 AllowReadingHoleElement(elements_kind) &&
1419 AllowConvertHoleElementToUndefined(isolate(), receiver_map));
1420 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
1421 return LoadHandler::LoadElement(isolate(), elements_kind, is_js_array,
1422 new_load_mode);
1423}
1424
1426 MapHandles* receiver_maps, MaybeObjectHandles* handlers,
1427 KeyedAccessLoadMode new_load_mode) {
1428 // Filter out deprecated maps to ensure their instances get migrated.
1429 receiver_maps->erase(std::remove_if(
1430 receiver_maps->begin(), receiver_maps->end(),
1431 [](const DirectHandle<Map>& map) { return map->is_deprecated(); }));
1432
1433 for (DirectHandle<Map> receiver_map : *receiver_maps) {
1434 // Mark all stable receiver maps that have elements kind transition map
1435 // among receiver_maps as unstable because the optimizing compilers may
1436 // generate an elements kind transition for this kind of receivers.
1437 if (receiver_map->is_stable()) {
1438 Tagged<Map> tmap = receiver_map->FindElementsKindTransitionedMap(
1439 isolate(),
1440 MapHandlesSpan(receiver_maps->begin(), receiver_maps->end()),
1442 if (!tmap.is_null()) {
1443 receiver_map->NotifyLeafMapLayoutChange(isolate());
1444 }
1445 }
1446 handlers->push_back(MaybeObjectHandle(LoadElementHandler(
1447 receiver_map,
1448 GetUpdatedLoadModeForMap(isolate(), receiver_map, new_load_mode))));
1449 }
1450}
1451
1452namespace {
1453
1454enum KeyType { kIntPtr, kName, kBailout };
1455
1456// The cases where kIntPtr is returned must match what
1457// CodeStubAssembler::TryToIntptr can handle!
1458KeyType TryConvertKey(Handle<Object> key, Isolate* isolate, intptr_t* index_out,
1459 Handle<Name>* name_out) {
1460 if (IsSmi(*key)) {
1461 *index_out = Smi::ToInt(*key);
1462 return kIntPtr;
1463 }
1464 if (IsHeapNumber(*key)) {
1465 double num = Cast<HeapNumber>(*key)->value();
1466 if (!(num >= -kMaxSafeInteger)) return kBailout;
1467 if (num > kMaxSafeInteger) return kBailout;
1468 *index_out = static_cast<intptr_t>(num);
1469 if (*index_out != num) return kBailout;
1470 return kIntPtr;
1471 }
1472 if (IsString(*key)) {
1473 key = isolate->factory()->InternalizeString(Cast<String>(key));
1474 uint32_t maybe_array_index;
1475 if (Cast<String>(*key)->AsArrayIndex(&maybe_array_index)) {
1476 if (maybe_array_index <= INT_MAX) {
1477 *index_out = static_cast<intptr_t>(maybe_array_index);
1478 return kIntPtr;
1479 }
1480 // {key} is a string representation of an array index beyond the range
1481 // that the IC could handle. Don't try to take the named-property path.
1482 return kBailout;
1483 }
1484 *name_out = Cast<String>(key);
1485 return kName;
1486 }
1487 if (IsSymbol(*key)) {
1488 *name_out = Cast<Symbol>(key);
1489 return kName;
1490 }
1491 return kBailout;
1492}
1493
1494bool IntPtrKeyToSize(intptr_t index, DirectHandle<HeapObject> receiver,
1495 size_t* out) {
1496 if (index < 0) {
1497 if (IsJSTypedArray(*receiver)) {
1498 // For JSTypedArray receivers, we can support negative keys, which we
1499 // just map to a very large value. This is valid because all OOB accesses
1500 // (negative or positive) are handled the same way, and size_t::max is
1501 // guaranteed to be an OOB access.
1502 *out = std::numeric_limits<size_t>::max();
1503 return true;
1504 }
1505 return false;
1506 }
1507#if V8_HOST_ARCH_64_BIT
1508 if (index > JSObject::kMaxElementIndex && !IsJSTypedArray(*receiver)) {
1509 return false;
1510 }
1511#else
1512 // On 32-bit platforms, any intptr_t is less than kMaxElementIndex.
1513 static_assert(
1514 static_cast<double>(std::numeric_limits<decltype(index)>::max()) <=
1515 static_cast<double>(JSObject::kMaxElementIndex));
1516#endif
1517 *out = static_cast<size_t>(index);
1518 return true;
1519}
1520
1521bool CanCache(DirectHandle<Object> receiver, InlineCacheState state) {
1522 if (!v8_flags.use_ic || state == NO_FEEDBACK) return false;
1523 if (!IsJSReceiver(*receiver) && !IsString(*receiver)) return false;
1524 return !IsAccessCheckNeeded(*receiver) && !IsJSPrimitiveWrapper(*receiver);
1525}
1526
1527} // namespace
1528
1531 bool* is_found) {
1533
1534 if (IsKeyedLoadIC()) {
1536 isolate(), result,
1538 DirectHandle<JSAny>(), is_found));
1539 } else {
1542 Runtime::HasProperty(isolate(), object, key));
1543 }
1544 return result;
1545}
1546
1549 Handle<Name> name) {
1550 DirectHandle<Object> load_handle;
1551 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
1552 LoadIC::Load(object, name));
1553
1554 if (vector_needs_update()) {
1556 TraceIC("LoadIC", key);
1557 }
1558
1559 DCHECK(!load_handle.is_null());
1560 return load_handle;
1561}
1562
1565 if (MigrateDeprecated(isolate(), object)) {
1566 return RuntimeLoad(object, key);
1567 }
1568
1569 intptr_t maybe_index;
1570 Handle<Name> maybe_name;
1571 KeyType key_type = TryConvertKey(key, isolate(), &maybe_index, &maybe_name);
1572
1573 if (key_type == kName) return LoadName(object, key, maybe_name);
1574
1575 bool is_found = false;
1576 MaybeDirectHandle<Object> result = RuntimeLoad(object, key, &is_found);
1577
1578 size_t index;
1579 if (key_type == kIntPtr && CanCache(object, state()) &&
1580 IntPtrKeyToSize(maybe_index, Cast<HeapObject>(object), &index)) {
1582 KeyedAccessLoadMode load_mode =
1583 GetNewKeyedLoadMode(isolate(), receiver, index, is_found);
1584 UpdateLoadElement(receiver, load_mode);
1585 if (is_vector_set()) {
1586 TraceIC("LoadIC", key);
1587 }
1588 }
1589
1590 if (vector_needs_update()) {
1592 TraceIC("LoadIC", key);
1593 }
1594
1595 return result;
1596}
1597
1599 StoreOrigin store_origin) {
1600 // Disable ICs for non-JSObjects for now.
1601 DirectHandle<Object> object = it->GetReceiver();
1602 if (IsJSProxy(*object)) return true;
1603 if (!IsJSObject(*object)) return false;
1605 DCHECK(!receiver->map()->is_deprecated());
1606
1607 for (;; it->Next()) {
1608 switch (it->state()) {
1610 UNREACHABLE();
1612 return false;
1614 return true;
1616 DirectHandle<JSObject> holder = it->GetHolder<JSObject>();
1617 Tagged<InterceptorInfo> info = holder->GetNamedInterceptor();
1618 if (it->HolderIsReceiverOrHiddenPrototype() || info->has_getter() ||
1619 info->has_query()) {
1620 return true;
1621 }
1622 continue;
1623 }
1625 if (IsAccessCheckNeeded(*it->GetHolder<JSObject>())) return false;
1626 continue;
1628 return !it->IsReadOnly();
1630 return false;
1631 case LookupIterator::DATA: {
1632 if (it->IsReadOnly()) return false;
1633 if (IsAnyDefineOwn() && it->property_attributes() != NONE) {
1634 // IC doesn't support reconfiguration of property attributes,
1635 // so just bail out to the slow handler.
1636 return false;
1637 }
1638 DirectHandle<JSObject> holder = it->GetHolder<JSObject>();
1639 if (receiver.is_identical_to(holder)) {
1640 it->PrepareForDataProperty(value);
1641 // The previous receiver map might just have been deprecated,
1642 // so reload it.
1644 return true;
1645 }
1646
1647 // Receiver != holder.
1648 if (IsJSGlobalProxy(*receiver)) {
1650 return it->GetHolder<Object>().is_identical_to(
1652 }
1653
1654 if (it->HolderIsReceiverOrHiddenPrototype()) return false;
1655
1656 if (it->ExtendingNonExtensible(receiver)) return false;
1657 it->PrepareTransitionToDataProperty(receiver, value, NONE,
1658 store_origin);
1659 return it->IsCacheableTransition();
1660 }
1662 // If we are in StoreGlobal then check if we should throw on
1663 // non-existent properties.
1664 if (IsStoreGlobalIC() &&
1665 (GetShouldThrow(it->isolate(), Nothing<ShouldThrow>()) ==
1667 // ICs typically does the store in two steps: prepare receiver for the
1668 // transition followed by the actual store. For global objects we
1669 // create a property cell when preparing for transition and install
1670 // this cell in the handler. In strict mode, we throw and never
1671 // initialize this property cell. The IC handler assumes that the
1672 // property cell it is holding is for a property that is existing.
1673 // This case violates this assumption. If we happen to invalidate this
1674 // property cell later, it leads to incorrect behaviour. For now just
1675 // use a slow stub and don't install the property cell for these
1676 // cases. Hopefully these cases are not frequent enough to impact
1677 // performance.
1678 //
1679 // TODO(mythria): If we find this to be happening often, we could
1680 // install a new kind of handler for non-existent properties. These
1681 // handlers can then miss to runtime if the value is not hole (i.e.
1682 // cell got invalidated) and handle these stores correctly.
1683 return false;
1684 }
1685 receiver = it->GetStoreTarget<JSObject>();
1686 if (it->ExtendingNonExtensible(receiver)) return false;
1687 it->PrepareTransitionToDataProperty(receiver, value, NONE,
1688 store_origin);
1689 return it->IsCacheableTransition();
1690 }
1691 UNREACHABLE();
1692 }
1693}
1694
1696 DirectHandle<Object> value) {
1697 DCHECK(IsString(*name));
1698
1699 // Look up in script context table.
1700 DirectHandle<String> str_name = Cast<String>(name);
1702 DirectHandle<ScriptContextTable> script_contexts(
1703 global->native_context()->script_context_table(), isolate());
1704
1705 VariableLookupResult lookup_result;
1706 if (script_contexts->Lookup(str_name, &lookup_result)) {
1708 DisableGCMole no_gcmole;
1709 Tagged<Context> script_context =
1710 script_contexts->get(lookup_result.context_index);
1711 if (IsImmutableLexicalVariableMode(lookup_result.mode)) {
1713 return TypeError(MessageTemplate::kConstAssign, global, name);
1714 }
1715
1716 Tagged<Object> previous_value =
1717 script_context->get(lookup_result.slot_index);
1718
1719 if (IsTheHole(previous_value, isolate())) {
1720 // Do not install stubs and stay pre-monomorphic for uninitialized
1721 // accesses.
1724 isolate(),
1725 NewReferenceError(MessageTemplate::kAccessedUninitializedVariable,
1726 name));
1727 }
1728
1729 bool use_ic = (state() != NO_FEEDBACK) && v8_flags.use_ic;
1730 if (use_ic) {
1731 if (nexus()->ConfigureLexicalVarMode(
1732 lookup_result.context_index, lookup_result.slot_index,
1733 IsImmutableLexicalVariableMode(lookup_result.mode))) {
1734 TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
1735 } else {
1736 // Given combination of indices can't be encoded, so use slow stub.
1737 TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
1739 }
1740 TraceIC("StoreGlobalIC", name);
1741 } else if (state() == NO_FEEDBACK) {
1742 TraceIC("StoreGlobalIC", name);
1743 }
1744 if (v8_flags.script_context_mutable_heap_number ||
1745 v8_flags.const_tracking_let) {
1748 direct_handle(script_context, isolate()), lookup_result.slot_index,
1749 value, isolate());
1750 } else {
1751 script_context->set(lookup_result.slot_index, *value);
1752 }
1753 return value;
1754 }
1755
1756 return StoreIC::Store(global, name, value);
1757}
1758
1759namespace {
1760Maybe<bool> DefineOwnDataProperty(LookupIterator* it,
1761 LookupIterator::State original_state,
1762 DirectHandle<JSAny> value,
1763 Maybe<ShouldThrow> should_throw,
1764 StoreOrigin store_origin) {
1765 // It should not be possible to call DefineOwnDataProperty in a
1766 // contextual store (indicated by IsJSGlobalObject()).
1767 DCHECK(!IsJSGlobalObject(*it->GetReceiver(), it->isolate()));
1768
1769 // Handle special cases that can't be handled by
1770 // DefineOwnPropertyIgnoreAttributes first.
1771 switch (it->state()) {
1773 PropertyDescriptor new_desc;
1774 new_desc.set_value(value);
1775 new_desc.set_writable(true);
1776 new_desc.set_enumerable(true);
1777 new_desc.set_configurable(true);
1778 DCHECK_EQ(original_state, LookupIterator::JSPROXY);
1779 // TODO(joyee): this will start the lookup again. Ideally we should
1780 // implement something that reuses the existing LookupIterator.
1781 return JSProxy::DefineOwnProperty(it->isolate(), it->GetHolder<JSProxy>(),
1782 it->GetName(), &new_desc, should_throw);
1783 }
1785 RETURN_FAILURE(it->isolate(), kThrowOnError,
1786 NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
1787 // When lazy feedback is disabled, the original state could be different
1788 // while the object is already prepared for TRANSITION.
1790 switch (original_state) {
1798 UNREACHABLE();
1800 DCHECK(!IsAccessCheckNeeded(*it->GetHolder<JSObject>()));
1801 [[fallthrough]];
1802 }
1804 return Object::AddDataProperty(it, value, NONE,
1805 Nothing<ShouldThrow>(), store_origin,
1807 }
1808 }
1815 break;
1816 }
1817
1818 // We need to restart to handle interceptors properly.
1819 it->Restart();
1820
1822 it, value, NONE, should_throw, JSObject::DONT_FORCE_FIELD,
1823 EnforceDefineSemantics::kDefine, store_origin);
1824}
1825} // namespace
1826
1828 Handle<Name> name,
1830 StoreOrigin store_origin) {
1831 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1832 // might deprecate the current map again, if value does not fit.
1833 if (MigrateDeprecated(isolate(), object)) {
1834 // KeyedStoreIC should handle DefineKeyedOwnIC with deprecated maps directly
1835 // instead of reusing this method.
1837 DCHECK(!name->IsPrivateName());
1838
1839 PropertyKey key(isolate(), name);
1840 if (IsDefineNamedOwnIC()) {
1842 isolate(), object, key, value, Nothing<ShouldThrow>()));
1843 } else {
1846 }
1847 return value;
1848 }
1849
1850 bool use_ic = (state() != NO_FEEDBACK) && v8_flags.use_ic;
1851 // If the object is undefined or null it's illegal to try to set any
1852 // properties on it; throw a TypeError in that case.
1853 if (IsNullOrUndefined(*object, isolate())) {
1854 if (use_ic) {
1855 // Ensure the IC state progresses.
1856 TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
1859 TraceIC("StoreIC", name);
1860 }
1861 return TypeError(MessageTemplate::kNonObjectPropertyStoreWithProperty, name,
1862 object);
1863 }
1864
1866 PropertyKey key(isolate(), name);
1867 LookupIterator it(
1868 isolate(), object, key,
1870
1871 if (name->IsPrivate()) {
1872 if (name->IsPrivateName()) {
1874 Maybe<bool> can_store =
1876 MAYBE_RETURN_NULL(can_store);
1877 if (!can_store.FromJust()) {
1878 return isolate()->factory()->undefined_value();
1879 }
1880 }
1881
1882 // IC handling of private fields/symbols stores on JSProxy is not
1883 // supported.
1884 if (IsJSProxy(*object)) {
1885 use_ic = false;
1886 }
1887 }
1888
1889 // For IsAnyDefineOwn(), we can't simply do CreateDataProperty below
1890 // because we need to check the attributes before UpdateCaches updates
1891 // the state of the LookupIterator.
1892 LookupIterator::State original_state = it.state();
1893 // We'll defer the check for JSProxy and objects with named interceptors,
1894 // because the defineProperty traps need to be called first if they are
1895 // present. We can also skip this for private names since they are not
1896 // bound by configurability or extensibility checks, and errors would've
1897 // been thrown if the private field already exists in the object.
1898 if (IsAnyDefineOwn() && !name->IsPrivateName() && IsJSObject(*object) &&
1899 !Cast<JSObject>(object)->HasNamedInterceptor()) {
1901 isolate(), &it, value, Nothing<ShouldThrow>());
1902 MAYBE_RETURN_NULL(can_define);
1903 if (!can_define.FromJust()) {
1904 return isolate()->factory()->undefined_value();
1905 }
1906 // Restart the lookup iterator updated by CheckIfCanDefineAsConfigurable()
1907 // for UpdateCaches() to handle access checks.
1908 if (use_ic && IsAccessCheckNeeded(*object)) {
1909 it.Restart();
1910 }
1911 }
1912
1913 if (use_ic) {
1914 UpdateCaches(&it, value, store_origin);
1915 } else if (state() == NO_FEEDBACK) {
1916 // Tracing IC Stats for No Feedback State.
1917 IsStoreGlobalIC() ? TraceIC("StoreGlobalIC", name)
1918 : TraceIC("StoreIC", name);
1919 }
1920
1921 // TODO(v8:12548): refactor DefinedNamedOwnIC and SetNamedIC as subclasses
1922 // of StoreIC so their logic doesn't get mixed here.
1923 // ES #sec-definefield
1924 // ES #sec-runtime-semantics-propertydefinitionevaluation
1925 // IsAnyDefineOwn() can be true when this method is reused by KeyedStoreIC.
1926 if (IsAnyDefineOwn()) {
1927 if (name->IsPrivateName()) {
1928 // We should define private fields without triggering traps or checking
1929 // extensibility.
1932 } else {
1934 DefineOwnDataProperty(&it, original_state, Cast<JSAny>(value),
1935 Nothing<ShouldThrow>(), store_origin));
1936 }
1937 } else {
1938 MAYBE_RETURN_NULL(Object::SetProperty(&it, value, store_origin));
1939 }
1940 return value;
1941}
1942
1944 StoreOrigin store_origin) {
1946 if (LookupForWrite(lookup, value, store_origin)) {
1947 if (IsStoreGlobalIC()) {
1948 if (lookup->state() == LookupIterator::DATA &&
1949 lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
1950 DCHECK(IsJSGlobalObject(*lookup->GetReceiver()));
1951 // Now update the cell in the feedback vector.
1952 nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell());
1953 TraceIC("StoreGlobalIC", lookup->GetName());
1954 return;
1955 }
1956 }
1957 handler = ComputeHandler(lookup);
1958 } else {
1959 set_slow_stub_reason("LookupForWrite said 'false'");
1961 }
1962 // Can't use {lookup->name()} because the LookupIterator might be in
1963 // "elements" mode for keys that are strings representing integers above
1964 // JSArray::kMaxIndex.
1965 SetCache(lookup->GetName(), handler);
1966 TraceIC("StoreIC", lookup->GetName());
1967}
1968
1970 switch (lookup->state()) {
1972 DirectHandle<JSObject> store_target = lookup->GetStoreTarget<JSObject>();
1973 if (IsJSGlobalObject(*store_target)) {
1974 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
1975
1976 if (IsJSGlobalObject(*lookup_start_object_map())) {
1978#ifdef DEBUG
1979 DirectHandle<JSObject> holder = lookup->GetHolder<JSObject>();
1980 DCHECK_EQ(*lookup->GetReceiver(), *holder);
1981 DCHECK_EQ(*store_target, *holder);
1982#endif
1984 indirect_handle(lookup->transition_cell(), isolate()));
1985 }
1986 if (IsDefineKeyedOwnIC()) {
1987 // Private field can't be deleted from this global object and can't
1988 // be overwritten, so install slow handler in order to make store IC
1989 // throw if a private name already exists.
1990 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
1992 }
1993
1994 DirectHandle<Smi> smi_handler =
1997 isolate(), lookup_start_object_map(), store_target, *smi_handler,
1999 return MaybeObjectHandle(handler);
2000 }
2001 // Dictionary-to-fast transitions are not expected and not supported.
2002 DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
2003 !lookup_start_object_map()->is_dictionary_map());
2004
2005 DCHECK(lookup->IsCacheableTransition());
2006 if (IsAnyDefineOwn()) {
2008 isolate(), indirect_handle(lookup->transition_map(), isolate()));
2009 }
2011 isolate(), indirect_handle(lookup->transition_map(), isolate()));
2012 }
2013
2015 DirectHandle<JSObject> holder = lookup->GetHolder<JSObject>();
2016 Tagged<InterceptorInfo> info = holder->GetNamedInterceptor();
2017
2018 // If the interceptor is on the receiver...
2019 if (lookup->HolderIsReceiverOrHiddenPrototype() && !info->non_masking()) {
2020 // ...return a store interceptor Smi handler if there is a setter
2021 // interceptor and it's not DefineNamedOwnIC or DefineKeyedOwnIC
2022 // (which should call the definer)...
2023 if (info->has_setter() && !IsAnyDefineOwn()) {
2025 }
2026 // ...otherwise return a slow-case Smi handler, which invokes the
2027 // definer for DefineNamedOwnIC.
2029 }
2030
2031 // If the interceptor is a getter/query interceptor on the prototype
2032 // chain, return an invalidatable slow handler so it can turn fast if the
2033 // interceptor is masked by a regular property later.
2034 DCHECK(info->has_getter() || info->has_query());
2036 isolate(), lookup_start_object_map(), holder,
2038 return MaybeObjectHandle(handler);
2039 }
2040
2042 // This is currently guaranteed by checks in StoreIC::Store.
2044 Handle<JSObject> holder =
2045 indirect_handle(lookup->GetHolder<JSObject>(), isolate());
2046 DCHECK(!IsAccessCheckNeeded(*receiver) || lookup->name()->IsPrivate());
2047
2048 if (IsAnyDefineOwn()) {
2049 set_slow_stub_reason("define own with existing accessor");
2050 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2052 }
2053 if (!holder->HasFastProperties()) {
2054 set_slow_stub_reason("accessor on slow map");
2055 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2056 MaybeObjectHandle handler =
2058 return handler;
2059 }
2060 DirectHandle<Object> accessors = lookup->GetAccessors();
2061 if (IsAccessorInfo(*accessors)) {
2063 if (!info->has_setter(isolate())) {
2064 set_slow_stub_reason("setter == kNullAddress");
2065 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2067 }
2068 if (!lookup->HolderIsReceiverOrHiddenPrototype()) {
2069 set_slow_stub_reason("native data property in prototype chain");
2070 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2072 }
2073
2075 isolate(), lookup->GetAccessorIndex());
2076 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH);
2077 if (receiver.is_identical_to(holder)) {
2078 return MaybeObjectHandle(smi_handler);
2079 }
2081 StoreIC_StoreNativeDataPropertyOnPrototypeDH);
2083 isolate(), lookup_start_object_map(), holder, *smi_handler));
2084
2085 } else if (IsAccessorPair(*accessors)) {
2086 DirectHandle<AccessorPair> accessor_pair =
2087 Cast<AccessorPair>(accessors);
2088 Handle<Object> setter(accessor_pair->setter(), isolate());
2089 if (!IsCallableJSFunction(*setter) &&
2090 !IsFunctionTemplateInfo(*setter)) {
2091 set_slow_stub_reason("setter not a function");
2092 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2094 }
2095
2096 if ((IsFunctionTemplateInfo(*setter) &&
2097 Cast<FunctionTemplateInfo>(*setter)->BreakAtEntry(isolate())) ||
2098 (IsJSFunction(*setter) &&
2099 Cast<JSFunction>(*setter)->shared()->BreakAtEntry(isolate()))) {
2100 // Do not install an IC if the api function has a breakpoint.
2101 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2103 }
2104
2105 CallOptimization call_optimization(isolate(), setter);
2106 if (call_optimization.is_simple_api_call()) {
2107 CallOptimization::HolderLookup holder_lookup;
2108 DirectHandle<JSObject> api_holder =
2109 call_optimization.LookupHolderOfExpectedType(
2110 isolate(), lookup_start_object_map(), &holder_lookup);
2111 if (call_optimization.IsCompatibleReceiverMap(api_holder, holder,
2112 holder_lookup)) {
2113 DirectHandle<Smi> smi_handler =
2115
2116 DirectHandle<NativeContext> accessor_context =
2117 GetAccessorContext(call_optimization, holder->map(), isolate());
2118
2119 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
2121 isolate(), lookup_start_object_map(), holder, *smi_handler,
2123 call_optimization.api_call_info()),
2124 MaybeObjectDirectHandle::Weak(accessor_context)));
2125 }
2126 set_slow_stub_reason("incompatible receiver");
2127 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2129 } else if (IsFunctionTemplateInfo(*setter)) {
2130 set_slow_stub_reason("setter non-simple template");
2131 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2133 }
2134
2135 DCHECK(IsCallableJSFunction(*setter));
2136 if (receiver.is_identical_to(holder)) {
2137 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH);
2139 indirect_handle(accessor_pair, isolate()));
2140 }
2141 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
2142
2144 isolate(), lookup_start_object_map(), holder,
2147 }
2148 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2150 }
2151
2152 case LookupIterator::DATA: {
2153 // This is currently guaranteed by checks in StoreIC::Store.
2155 USE(receiver);
2156 DirectHandle<JSObject> holder = lookup->GetHolder<JSObject>();
2157 DCHECK(!IsAccessCheckNeeded(*receiver) || lookup->name()->IsPrivate());
2158
2160 if (lookup->is_dictionary_holder()) {
2161 if (IsJSGlobalObject(*holder)) {
2162 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
2164 indirect_handle(lookup->GetPropertyCell(), isolate())));
2165 }
2166 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
2170
2172 return MaybeObjectHandle(handler);
2173 }
2174
2175 // -------------- Elements (for TypedArrays) -------------
2176 if (lookup->IsElement(*holder)) {
2177 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2179 }
2180
2181 // -------------- Fields --------------
2183 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
2184 int descriptor = lookup->GetFieldDescriptorIndex();
2185 FieldIndex index = lookup->GetFieldIndex();
2186 if (V8_UNLIKELY(IsJSSharedStruct(*holder))) {
2188 isolate(), descriptor, index, lookup->representation()));
2189 }
2190 PropertyConstness constness = lookup->constness();
2191 if (constness == PropertyConstness::kConst &&
2193 // DefineNamedOwnICs are used for initializing object literals
2194 // therefore we must store the value unconditionally even to
2195 // VariableMode::kConst fields.
2196 constness = PropertyConstness::kMutable;
2197 }
2199 isolate(), descriptor, index, constness, lookup->representation()));
2200 }
2201
2202 // -------------- Constant properties --------------
2204 lookup->property_details().location());
2205 set_slow_stub_reason("constant property");
2206 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2208 }
2211 Cast<JSReceiver>(lookup->GetReceiver());
2212 Handle<JSProxy> holder =
2213 indirect_handle(lookup->GetHolder<JSProxy>(), isolate());
2214
2215 // IsDefineNamedOwnIC() is true when we are defining public fields on a
2216 // Proxy. IsDefineKeyedOwnIC() is true when we are defining computed
2217 // fields in a Proxy. In these cases use the slow stub to invoke the
2218 // define trap.
2220 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
2222 }
2223
2226 }
2227
2232 UNREACHABLE();
2233 }
2234 return MaybeObjectHandle();
2235}
2236
2238 KeyedAccessStoreMode store_mode,
2239 Handle<Map> new_receiver_map) {
2240 MapsAndHandlers target_maps_and_handlers(isolate());
2241 nexus()->ExtractMapsAndHandlers(
2242 &target_maps_and_handlers,
2243 [this](Handle<Map> map) { return Map::TryUpdate(isolate(), map); });
2244 if (target_maps_and_handlers.empty()) {
2245 DirectHandle<Map> monomorphic_map = receiver_map;
2246 // If we transitioned to a map that is a more general map than incoming
2247 // then use the new map.
2248 if (IsTransitionOfMonomorphicTarget(*receiver_map, *new_receiver_map)) {
2249 monomorphic_map = new_receiver_map;
2250 }
2251 DirectHandle<Object> handler =
2252 StoreElementHandler(monomorphic_map, store_mode);
2253 return ConfigureVectorState(DirectHandle<Name>(), monomorphic_map, handler);
2254 }
2255
2256 for (DirectHandle<Map> map : target_maps_and_handlers.maps()) {
2257 if (!map.is_null() && map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
2259 set_slow_stub_reason("JSPrimitiveWrapper");
2260 return;
2261 }
2262 }
2263
2264 // There are several special cases where an IC that is MONOMORPHIC can still
2265 // transition to a different IC that handles a superset of the original IC.
2266 // Handle those here if the receiver map hasn't changed or it has transitioned
2267 // to a more general kind.
2269 DirectHandle<Map> previous_receiver_map = target_maps_and_handlers.maps()[0];
2270 if (state() == MONOMORPHIC) {
2271 DirectHandle<Map> transitioned_receiver_map = new_receiver_map;
2272 if (IsTransitionOfMonomorphicTarget(*previous_receiver_map,
2273 *transitioned_receiver_map)) {
2274 // If the "old" and "new" maps are in the same elements map family, or
2275 // if they at least come from the same origin for a transitioning store,
2276 // stay MONOMORPHIC and use the map for the most generic ElementsKind.
2277 DirectHandle<Object> handler =
2278 StoreElementHandler(transitioned_receiver_map, store_mode);
2279 ConfigureVectorState(DirectHandle<Name>(), transitioned_receiver_map,
2280 handler);
2281 return;
2282 }
2283 // If there is no transition and if we have seen the same map earlier and
2284 // there is only a change in the store_mode we can still stay monomorphic.
2285 if (receiver_map.is_identical_to(previous_receiver_map) &&
2286 new_receiver_map.is_identical_to(receiver_map) &&
2287 StoreModeIsInBounds(old_store_mode) &&
2288 !StoreModeIsInBounds(store_mode)) {
2289 if (IsJSArrayMap(*receiver_map) &&
2290 JSArray::MayHaveReadOnlyLength(*receiver_map)) {
2292 "can't generalize store mode (potentially read-only length)");
2293 return;
2294 }
2295 // A "normal" IC that handles stores can switch to a version that can
2296 // grow at the end of the array, handle OOB accesses or copy COW arrays
2297 // and still stay MONOMORPHIC.
2298 DirectHandle<Object> handler =
2299 StoreElementHandler(receiver_map, store_mode);
2300 return ConfigureVectorState(DirectHandle<Name>(), receiver_map, handler);
2301 }
2302 }
2303
2304 DCHECK(state() != GENERIC);
2305
2306 bool map_added =
2307 AddOneReceiverMapIfMissing(&target_maps_and_handlers, receiver_map);
2308
2309 if (IsTransitionOfMonomorphicTarget(*receiver_map, *new_receiver_map)) {
2310 map_added |=
2311 AddOneReceiverMapIfMissing(&target_maps_and_handlers, new_receiver_map);
2312 }
2313
2314 if (!map_added) {
2315 // If the miss wasn't due to an unseen map, a polymorphic stub
2316 // won't help, use the megamorphic stub which can handle everything.
2317 set_slow_stub_reason("same map added twice");
2318 return;
2319 }
2320
2321 // If the maximum number of receiver maps has been exceeded, use the
2322 // megamorphic version of the IC.
2323 if (static_cast<int>(target_maps_and_handlers.size()) >
2324 v8_flags.max_valid_polymorphic_map_count) {
2325 return;
2326 }
2327
2328 // Make sure all polymorphic handlers have the same store mode, otherwise the
2329 // megamorphic stub must be used.
2330 if (!StoreModeIsInBounds(old_store_mode)) {
2331 if (StoreModeIsInBounds(store_mode)) {
2332 store_mode = old_store_mode;
2333 } else if (store_mode != old_store_mode) {
2334 set_slow_stub_reason("store mode mismatch");
2335 return;
2336 }
2337 }
2338
2339 // If the store mode isn't the standard mode, make sure that all polymorphic
2340 // receivers are either external arrays, or all "normal" arrays with writable
2341 // length. Otherwise, use the megamorphic stub.
2342 if (!StoreModeIsInBounds(store_mode)) {
2343 size_t external_arrays = 0;
2344 for (DirectHandle<Map> map : target_maps_and_handlers.maps()) {
2345 if (IsJSArrayMap(*map) && JSArray::MayHaveReadOnlyLength(*map)) {
2347 "unsupported combination of arrays (potentially read-only length)");
2348 return;
2349
2350 } else if (map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2352 external_arrays++;
2353 }
2354 }
2355 if (external_arrays != 0 &&
2356 external_arrays != target_maps_and_handlers.size()) {
2359 "unsupported combination of external and normal arrays");
2360 return;
2361 }
2362 }
2363
2364 StoreElementPolymorphicHandlers(&target_maps_and_handlers, store_mode);
2365 if (target_maps_and_handlers.empty()) {
2366 DirectHandle<Object> handler =
2367 StoreElementHandler(receiver_map, store_mode);
2368 ConfigureVectorState(DirectHandle<Name>(), receiver_map, handler);
2369 } else if (target_maps_and_handlers.size() == 1) {
2370 auto [map, handler] = target_maps_and_handlers[0];
2372 } else {
2373 ConfigureVectorState(DirectHandle<Name>(), target_maps_and_handlers);
2374 }
2375}
2376
2378 DirectHandle<Map> receiver_map, KeyedAccessStoreMode store_mode,
2379 MaybeDirectHandle<UnionOf<Smi, Cell>> prev_validity_cell) {
2380 // The only case when could keep using non-slow element store handler for
2381 // a fast array with potentially read-only elements is when it's an
2382 // initializing store to array literal.
2384 !receiver_map->has_dictionary_elements() &&
2385 receiver_map->ShouldCheckForReadOnlyElementsInPrototypeChain(
2386 isolate()),
2388
2389 if (!IsJSObjectMap(*receiver_map)) {
2390 // DefineKeyedOwnIC, which is used to define computed fields in instances,
2391 // should handled by the slow stub below instead of the proxy stub.
2392 if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) {
2394 }
2395
2396 // Wasm objects or other kind of special objects go through the slow stub.
2397 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
2398 return StoreHandler::StoreSlow(isolate(), store_mode);
2399 }
2400
2401 // TODO(ishell): move to StoreHandler::StoreElement().
2403 if (receiver_map->has_sloppy_arguments_elements()) {
2404 // TODO(jgruber): Update counter name.
2405 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
2407 } else if (receiver_map->has_fast_elements() ||
2408 receiver_map->has_sealed_elements() ||
2409 receiver_map->has_nonextensible_elements() ||
2410 receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2411 // TODO(jgruber): Update counter name.
2412 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
2413 if (IsJSArgumentsObjectMap(*receiver_map) &&
2414 receiver_map->has_fast_packed_elements()) {
2415 // Allow fast behaviour for in-bounds stores while making it miss and
2416 // properly handle the out of bounds store case.
2419 } else {
2420 code = StoreHandler::StoreFastElementBuiltin(isolate(), store_mode);
2421 if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
2422 return code;
2423 }
2424 }
2425 } else if (IsStoreInArrayLiteralIC()) {
2426 // TODO(jgruber): Update counter name.
2427 TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
2428 return StoreHandler::StoreSlow(isolate(), store_mode);
2429 } else {
2430 // TODO(jgruber): Update counter name.
2431 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
2432 DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() ||
2433 receiver_map->has_frozen_elements());
2434 return StoreHandler::StoreSlow(isolate(), store_mode);
2435 }
2436
2437 if (IsAnyDefineOwn() || IsStoreInArrayLiteralIC()) return code;
2438 DirectHandle<UnionOf<Smi, Cell>> validity_cell;
2439 if (!prev_validity_cell.ToHandle(&validity_cell)) {
2440 validity_cell =
2442 }
2443 if (IsSmi(*validity_cell)) {
2444 // There's no prototype validity cell to check, so we can just use the stub.
2445 return code;
2446 }
2448 handler->set_validity_cell(*validity_cell);
2449 handler->set_smi_handler(*code);
2450 return handler;
2451}
2452
2454 MapsAndHandlers* receiver_maps_and_handlers,
2455 KeyedAccessStoreMode store_mode) {
2456 DirectHandleVector<Map> receiver_maps(isolate());
2457 receiver_maps.reserve(receiver_maps_and_handlers->size());
2458 for (DirectHandle<Map> map : receiver_maps_and_handlers->maps()) {
2459 receiver_maps.push_back(map);
2460 }
2461 for (size_t i = 0; i < receiver_maps_and_handlers->size(); i++) {
2462 auto [receiver_map, old_handler] = (*receiver_maps_and_handlers)[i];
2463 DCHECK(!receiver_map->is_deprecated());
2465 DirectHandle<Map> transition;
2466
2467 if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
2468 receiver_map->ShouldCheckForReadOnlyElementsInPrototypeChain(
2469 isolate())) {
2470 // TODO(mvstanton): Consider embedding store_mode in the state of the slow
2471 // keyed store ic for uniformity.
2472 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
2473 handler = StoreHandler::StoreSlow(isolate());
2474
2475 } else {
2476 {
2477 Tagged<Map> tmap = receiver_map->FindElementsKindTransitionedMap(
2478 isolate(),
2479 MapHandlesSpan(receiver_maps.begin(), receiver_maps.end()),
2481 if (!tmap.is_null()) {
2482 if (receiver_map->is_stable()) {
2483 receiver_map->NotifyLeafMapLayoutChange(isolate());
2484 }
2485 transition = direct_handle(tmap, isolate());
2486 }
2487 }
2488
2490 Tagged<HeapObject> old_handler_obj;
2491 if (!old_handler.is_null() &&
2492 (*old_handler).GetHeapObject(&old_handler_obj) &&
2493 IsDataHandler(old_handler_obj)) {
2494 validity_cell = direct_handle(
2495 Cast<DataHandler>(old_handler_obj)->validity_cell(), isolate());
2496 }
2497 // TODO(mythria): Do not recompute the handler if we know there is no
2498 // change in the handler.
2499 // TODO(mvstanton): The code below is doing pessimistic elements
2500 // transitions. I would like to stop doing that and rely on Allocation
2501 // Site Tracking to do a better job of ensuring the data types are what
2502 // they need to be. Not all the elements are in place yet, pessimistic
2503 // elements transitions are still important for performance.
2504 if (!transition.is_null()) {
2506 KeyedStoreIC_ElementsTransitionAndStoreStub);
2508 isolate(), receiver_map, transition, store_mode, validity_cell);
2509 } else {
2510 handler = StoreElementHandler(receiver_map, store_mode, validity_cell);
2511 }
2512 }
2513 DCHECK(!handler.is_null());
2514 receiver_maps_and_handlers->set_map(i, receiver_map);
2515 receiver_maps_and_handlers->set_handler(i,
2516 MaybeObjectDirectHandle(handler));
2517 }
2518}
2519
2520namespace {
2521
2522bool MayHaveTypedArrayInPrototypeChain(Isolate* isolate,
2523 DirectHandle<JSObject> object) {
2524 for (PrototypeIterator iter(isolate, *object); !iter.IsAtEnd();
2525 iter.Advance()) {
2526 // Be conservative, don't walk into proxies.
2527 if (IsJSProxy(iter.GetCurrent())) return true;
2528 if (IsJSTypedArray(iter.GetCurrent())) return true;
2529 }
2530 return false;
2531}
2532
2533KeyedAccessStoreMode GetStoreMode(DirectHandle<JSObject> receiver,
2534 size_t index) {
2535 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2536 // Don't consider this a growing store if the store would send the receiver to
2537 // dictionary mode.
2538 bool allow_growth =
2539 IsJSArray(*receiver) && oob_access && index <= JSArray::kMaxArrayIndex &&
2540 !receiver->WouldConvertToSlowElements(static_cast<uint32_t>(index));
2541 if (allow_growth) {
2543 }
2544 if (receiver->map()->has_typed_array_or_rab_gsab_typed_array_elements() &&
2545 oob_access) {
2547 }
2548 return receiver->elements()->IsCowArray() ? KeyedAccessStoreMode::kHandleCOW
2550}
2551
2552} // namespace
2553
2556 DirectHandle<Object> value) {
2557 // TODO(verwaest): Let SetProperty do the migration, since storing a property
2558 // might deprecate the current map again, if value does not fit.
2559 if (MigrateDeprecated(isolate(), object)) {
2561 // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of StoreIC
2562 // so the logic doesn't get mixed here.
2564 isolate(), result,
2566 ? Runtime::DefineObjectOwnProperty(isolate(), object, key, value,
2568 : Runtime::SetObjectProperty(isolate(), object, key, value,
2570 return result;
2571 }
2572
2573 DirectHandle<Object> store_handle;
2574
2575 intptr_t maybe_index;
2576 Handle<Name> maybe_name;
2577 KeyType key_type = TryConvertKey(key, isolate(), &maybe_index, &maybe_name);
2578
2579 if (key_type == kName) {
2581 isolate(), store_handle,
2582 StoreIC::Store(object, maybe_name, value, StoreOrigin::kMaybeKeyed));
2583 if (vector_needs_update()) {
2585 set_slow_stub_reason("unhandled internalized string key");
2586 TraceIC("StoreIC", key);
2587 }
2588 }
2589 return store_handle;
2590 }
2591
2593
2594 // TODO(jkummerow): Refactor the condition logic here and below.
2595 bool use_ic = (state() != NO_FEEDBACK) && v8_flags.use_ic &&
2596 !IsStringWrapper(*object) && !IsAccessCheckNeeded(*object) &&
2597 !IsJSGlobalProxy(*object);
2598 if (use_ic && !IsSmi(*object)) {
2599 // Don't use ICs for maps of the objects in Array's prototype chain. We
2600 // expect to be able to trap element sets to objects with those maps in
2601 // the runtime to enable optimization of element hole access.
2602 DirectHandle<HeapObject> heap_object = Cast<HeapObject>(object);
2603 if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) {
2604 set_slow_stub_reason("map in array prototype");
2605 use_ic = false;
2606 }
2607#if V8_ENABLE_WEBASSEMBLY
2608 if (IsWasmObjectMap(heap_object->map())) {
2609 set_slow_stub_reason("wasm object");
2610 use_ic = false;
2611 }
2612#endif
2613 }
2614
2615 Handle<Map> old_receiver_map;
2616 bool is_arguments = false;
2617 bool key_is_valid_index = (key_type == kIntPtr);
2619 if (use_ic && IsJSReceiver(*object) && key_is_valid_index) {
2621 old_receiver_map = handle(receiver->map(), isolate());
2622 is_arguments = IsJSArgumentsObject(*receiver);
2623 bool is_jsobject = IsJSObject(*receiver);
2624 size_t index;
2625 key_is_valid_index = IntPtrKeyToSize(maybe_index, receiver, &index);
2626 if (is_jsobject && !is_arguments && key_is_valid_index) {
2627 DirectHandle<JSObject> receiver_object = Cast<JSObject>(object);
2628 store_mode = GetStoreMode(receiver_object, index);
2629 }
2630 }
2631
2632 DCHECK(store_handle.is_null());
2633 // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of StoreIC
2634 // so the logic doesn't get mixed here.
2637 ? Runtime::DefineObjectOwnProperty(isolate(), object, key, value,
2639 : Runtime::SetObjectProperty(isolate(), object, key, value,
2641 if (result.is_null()) {
2642 DCHECK(isolate()->has_exception());
2643 set_slow_stub_reason("failed to set property");
2644 use_ic = false;
2645 }
2646 if (use_ic) {
2647 if (!old_receiver_map.is_null()) {
2648 if (is_arguments) {
2649 set_slow_stub_reason("arguments receiver");
2650 } else if (IsJSArray(*object) && StoreModeCanGrow(store_mode) &&
2652 set_slow_stub_reason("array has read only length");
2653 } else if (IsJSObject(*object) &&
2654 MayHaveTypedArrayInPrototypeChain(isolate(),
2655 Cast<JSObject>(object))) {
2656 // Make sure we don't handle this in IC if there's any JSTypedArray in
2657 // the {receiver}'s prototype chain, since that prototype is going to
2658 // swallow all stores that are out-of-bounds for said prototype, and we
2659 // just let the runtime deal with the complexity of this.
2660 set_slow_stub_reason("typed array in the prototype chain");
2661 } else if (key_is_valid_index) {
2662 if (old_receiver_map->is_abandoned_prototype_map()) {
2663 set_slow_stub_reason("receiver with prototype map");
2664 } else if (old_receiver_map->has_dictionary_elements() ||
2665 !old_receiver_map
2666 ->ShouldCheckForReadOnlyElementsInPrototypeChain(
2667 isolate())) {
2668 // We should go generic if receiver isn't a dictionary, but our
2669 // prototype chain does have dictionary elements. This ensures that
2670 // other non-dictionary receivers in the polymorphic case benefit
2671 // from fast path keyed stores.
2673 UpdateStoreElement(old_receiver_map, store_mode,
2674 handle(receiver->map(), isolate()));
2675 } else {
2676 set_slow_stub_reason("prototype with potentially read-only elements");
2677 }
2678 } else {
2679 set_slow_stub_reason("non-smi-like key");
2680 }
2681 } else {
2682 set_slow_stub_reason("non-JSObject receiver");
2683 }
2684 }
2685
2686 if (vector_needs_update()) {
2688 }
2689 TraceIC("StoreIC", key);
2690
2691 return result;
2692}
2693
2694namespace {
2695Maybe<bool> StoreOwnElement(Isolate* isolate, DirectHandle<JSArray> array,
2696 Handle<Object> index, DirectHandle<Object> value) {
2697 DCHECK(IsNumber(*index));
2698 PropertyKey key(isolate, index);
2699 LookupIterator it(isolate, array, key, LookupIterator::OWN);
2700
2702 &it, value, NONE, Just(ShouldThrow::kThrowOnError)),
2703 Nothing<bool>());
2704 return Just(true);
2705}
2706} // namespace
2707
2710 DirectHandle<Object> value) {
2711 DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate()));
2712 DCHECK(IsNumber(*index));
2713
2714 if (!v8_flags.use_ic || state() == NO_FEEDBACK ||
2715 MigrateDeprecated(isolate(), array)) {
2716 MAYBE_RETURN_NULL(StoreOwnElement(isolate(), array, index, value));
2717 TraceIC("StoreInArrayLiteralIC", index);
2718 return value;
2719 }
2720
2721 // TODO(neis): Convert HeapNumber to Smi if possible?
2722
2724 if (IsSmi(*index)) {
2725 DCHECK_GE(Smi::ToInt(*index), 0);
2726 uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index));
2727 store_mode = GetStoreMode(array, index32);
2728 }
2729
2730 Handle<Map> old_array_map(array->map(), isolate());
2731 MAYBE_RETURN_NULL(StoreOwnElement(isolate(), array, index, value));
2732
2733 if (IsSmi(*index)) {
2734 DCHECK(!old_array_map->is_abandoned_prototype_map());
2735 UpdateStoreElement(old_array_map, store_mode,
2736 handle(array->map(), isolate()));
2737 } else {
2738 set_slow_stub_reason("index out of Smi range");
2739 }
2740
2741 if (vector_needs_update()) {
2743 }
2744 TraceIC("StoreInArrayLiteralIC", index);
2745 return value;
2746}
2747
2748// ----------------------------------------------------------------------------
2749// Static IC stub generators.
2750//
2751//
2752RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
2753 HandleScope scope(isolate);
2754 DCHECK_EQ(4, args.length());
2755 // Runtime functions don't follow the IC's calling convention.
2757 Handle<Name> key = args.at<Name>(1);
2758 int slot = args.tagged_index_value_at(2);
2760 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2761
2762 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
2763 // LoadIC miss handler if the handler misses. Since the vector Nexus is
2764 // set up outside the IC, handle that here.
2765 FeedbackSlotKind kind = vector->GetKind(vector_slot);
2766 if (IsLoadICKind(kind)) {
2767 LoadIC ic(isolate, vector, vector_slot, kind);
2768 ic.UpdateState(receiver, key);
2769 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2770
2771 } else if (IsLoadGlobalICKind(kind)) {
2772 DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
2773 receiver = isolate->global_object();
2774 LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2775 ic.UpdateState(receiver, key);
2776 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key));
2777
2778 } else {
2780 KeyedLoadIC ic(isolate, vector, vector_slot, kind);
2781 ic.UpdateState(receiver, key);
2782 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2783 }
2784}
2785
2786RUNTIME_FUNCTION(Runtime_LoadNoFeedbackIC_Miss) {
2787 HandleScope scope(isolate);
2788 DCHECK_EQ(3, args.length());
2789 // Runtime functions don't follow the IC's calling convention.
2791 Handle<Name> key = args.at<Name>(1);
2792 int slot_kind = args.smi_value_at(2);
2793 FeedbackSlotKind kind = static_cast<FeedbackSlotKind>(slot_kind);
2794
2796 FeedbackSlot vector_slot = FeedbackSlot::Invalid();
2797 // This function is only called after looking up in the ScriptContextTable so
2798 // it is safe to call LoadIC::Load for global loads as well.
2799 LoadIC ic(isolate, vector, vector_slot, kind);
2800 ic.UpdateState(receiver, key);
2801 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2802}
2803
2804RUNTIME_FUNCTION(Runtime_LoadWithReceiverNoFeedbackIC_Miss) {
2805 HandleScope scope(isolate);
2806 DCHECK_EQ(3, args.length());
2807 // Runtime functions don't follow the IC's calling convention.
2809 Handle<JSAny> object = args.at<JSAny>(1);
2810 Handle<Name> key = args.at<Name>(2);
2811
2813 FeedbackSlot vector_slot = FeedbackSlot::Invalid();
2814 LoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadProperty);
2815 ic.UpdateState(object, key);
2816 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(object, key, true, receiver));
2817}
2818
2819RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) {
2820 HandleScope scope(isolate);
2821 DCHECK_EQ(4, args.length());
2822 // Runtime functions don't follow the IC's calling convention.
2823 DirectHandle<JSGlobalObject> global = isolate->global_object();
2824 Handle<String> name = args.at<String>(0);
2825 int slot = args.tagged_index_value_at(1);
2826 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2827 int typeof_value = args.smi_value_at(3);
2828 TypeofMode typeof_mode = static_cast<TypeofMode>(typeof_value);
2829 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2830
2832 if (!IsUndefined(*maybe_vector, isolate)) {
2833 DCHECK(IsFeedbackVector(*maybe_vector));
2834 vector = Cast<FeedbackVector>(maybe_vector);
2835 }
2836
2837 FeedbackSlotKind kind = (typeof_mode == TypeofMode::kInside)
2840 LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2841 ic.UpdateState(global, name);
2842
2844 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name));
2845 return *result;
2846}
2847
2848RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
2849 HandleScope scope(isolate);
2850 DCHECK_EQ(3, args.length());
2851 Handle<String> name = args.at<String>(0);
2852
2853 int slot = args.tagged_index_value_at(1);
2855 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2856 FeedbackSlotKind kind = vector->GetKind(vector_slot);
2857
2858 LoadGlobalIC ic(isolate, vector, vector_slot, kind);
2860 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name, false));
2861 return *result;
2862}
2863
2864RUNTIME_FUNCTION(Runtime_LoadWithReceiverIC_Miss) {
2865 HandleScope scope(isolate);
2866 DCHECK_EQ(5, args.length());
2867 // Runtime functions don't follow the IC's calling convention.
2869 Handle<JSAny> object = args.at<JSAny>(1);
2870 Handle<Name> key = args.at<Name>(2);
2871 int slot = args.tagged_index_value_at(3);
2873 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2874
2875 DCHECK(IsLoadICKind(vector->GetKind(vector_slot)));
2876 LoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadProperty);
2877 ic.UpdateState(object, key);
2878 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(object, key, true, receiver));
2879}
2880
2881RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) {
2882 HandleScope scope(isolate);
2883 DCHECK_EQ(4, args.length());
2884 // Runtime functions don't follow the IC's calling convention.
2886 Handle<Object> key = args.at(1);
2887 int slot = args.tagged_index_value_at(2);
2888 Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
2889
2891 if (!IsUndefined(*maybe_vector, isolate)) {
2892 DCHECK(IsFeedbackVector(*maybe_vector));
2893 vector = Cast<FeedbackVector>(maybe_vector);
2894 }
2895 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2896 KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kLoadKeyed);
2897 ic.UpdateState(receiver, key);
2898 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
2899}
2900
2901RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
2902 HandleScope scope(isolate);
2903 DCHECK_EQ(5, args.length());
2904 // Runtime functions don't follow the IC's calling convention.
2905 DirectHandle<Object> value = args.at(0);
2906 int slot = args.tagged_index_value_at(1);
2907 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2909 Handle<Name> key = args.at<Name>(4);
2910
2911 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2912
2913 // When there is no feedback vector it is OK to use the SetNamedStrict as
2914 // the feedback slot kind. We only reuse this for DefineNamedOwnIC when
2915 // installing the handler for storing const properties. This will happen only
2916 // when feedback vector is available.
2919 if (!IsUndefined(*maybe_vector, isolate)) {
2920 DCHECK(IsFeedbackVector(*maybe_vector));
2921 DCHECK(!vector_slot.IsInvalid());
2922 vector = Cast<FeedbackVector>(maybe_vector);
2923 kind = vector->GetKind(vector_slot);
2924 }
2925
2927 StoreIC ic(isolate, vector, vector_slot, kind);
2928 ic.UpdateState(receiver, key);
2929 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2930}
2931
2932RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Miss) {
2933 HandleScope scope(isolate);
2934 DCHECK_EQ(5, args.length());
2935 // Runtime functions don't follow the IC's calling convention.
2936 DirectHandle<Object> value = args.at(0);
2937 int slot = args.tagged_index_value_at(1);
2938 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
2940 Handle<Name> key = args.at<Name>(4);
2941
2942 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2943
2944 // When there is no feedback vector it is OK to use the DefineNamedOwn
2945 // feedback kind. There _should_ be a vector, though.
2948 if (!IsUndefined(*maybe_vector, isolate)) {
2949 DCHECK(IsFeedbackVector(*maybe_vector));
2950 DCHECK(!vector_slot.IsInvalid());
2951 vector = Cast<FeedbackVector>(maybe_vector);
2952 kind = vector->GetKind(vector_slot);
2953 }
2954
2956
2957 // TODO(v8:12548): refactor DefineNamedOwnIC as a subclass of StoreIC, which
2958 // can be called here.
2959 StoreIC ic(isolate, vector, vector_slot, kind);
2960 ic.UpdateState(receiver, key);
2961 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
2962}
2963
2964RUNTIME_FUNCTION(Runtime_DefineNamedOwnIC_Slow) {
2965 HandleScope scope(isolate);
2966 DCHECK_EQ(3, args.length());
2967
2968 DirectHandle<Object> value = args.at(0);
2969 DirectHandle<JSAny> object = args.at<JSAny>(1);
2970 Handle<Object> key = args.at(2);
2971
2972 // Unlike DefineKeyedOwnIC, DefineNamedOwnIC doesn't handle private
2973 // fields and is used for defining data properties in object literals
2974 // and defining named public class fields.
2975 DCHECK(!IsSymbol(*key) || !Cast<Symbol>(*key)->is_private_name());
2976
2977 PropertyKey lookup_key(isolate, key);
2978 MAYBE_RETURN(JSReceiver::CreateDataProperty(isolate, object, lookup_key,
2979 value, Nothing<ShouldThrow>()),
2980 ReadOnlyRoots(isolate).exception());
2981 return *value;
2982}
2983
2984RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
2985 HandleScope scope(isolate);
2986 DCHECK_EQ(4, args.length());
2987 // Runtime functions don't follow the IC's calling convention.
2988 DirectHandle<Object> value = args.at(0);
2989 int slot = args.tagged_index_value_at(1);
2991 Handle<Name> key = args.at<Name>(3);
2992
2993 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
2994 FeedbackSlotKind kind = vector->GetKind(vector_slot);
2995 StoreGlobalIC ic(isolate, vector, vector_slot, kind);
2996 DirectHandle<JSGlobalObject> global = isolate->global_object();
2997 ic.UpdateState(global, key);
2998 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
2999}
3000
3001RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
3002 HandleScope scope(isolate);
3003 DCHECK_EQ(2, args.length());
3004 // Runtime functions don't follow the IC's calling convention.
3005 DirectHandle<Object> value = args.at(0);
3006 Handle<Name> key = args.at<Name>(1);
3007
3008 // TODO(mythria): Replace StoreGlobalStrict/Sloppy with SetNamedProperty.
3011 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
3012}
3013
3014// TODO(mythria): Remove Feedback vector and slot. Since they are not used apart
3015// from the DCHECK.
3016RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
3017 HandleScope scope(isolate);
3018 DCHECK_EQ(5, args.length());
3019 // Runtime functions don't follow the IC's calling convention.
3020 DirectHandle<Object> value = args.at(0);
3021 Handle<String> name = args.at<String>(4);
3022
3023#ifdef DEBUG
3024 {
3025 int slot = args.tagged_index_value_at(1);
3027 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
3028 FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
3029 DCHECK(IsStoreGlobalICKind(slot_kind));
3031 DCHECK(IsJSGlobalProxy(*receiver));
3032 }
3033#endif
3034
3035 Handle<JSGlobalObject> global = isolate->global_object();
3036 DirectHandle<Context> native_context = isolate->native_context();
3037 DirectHandle<ScriptContextTable> script_contexts(
3038 native_context->script_context_table(), isolate);
3039
3040 VariableLookupResult lookup_result;
3041 if (script_contexts->Lookup(name, &lookup_result)) {
3042 DirectHandle<Context> script_context(
3043 script_contexts->get(lookup_result.context_index), isolate);
3044 if (IsImmutableLexicalVariableMode(lookup_result.mode)) {
3046 isolate, NewTypeError(MessageTemplate::kConstAssign, global, name));
3047 }
3048
3049 {
3051 Tagged<Object> previous_value =
3052 script_context->get(lookup_result.slot_index);
3053
3054 if (IsTheHole(previous_value, isolate)) {
3057 isolate,
3058 NewReferenceError(MessageTemplate::kAccessedUninitializedVariable,
3059 name));
3060 }
3061 }
3062 if (v8_flags.script_context_mutable_heap_number ||
3063 v8_flags.const_tracking_let) {
3065 script_context, lookup_result.slot_index, value, isolate);
3066 } else {
3067 script_context->set(lookup_result.slot_index, *value);
3068 }
3069 return *value;
3070 }
3071
3073 isolate, Runtime::SetObjectProperty(isolate, global, name, value,
3075}
3076
3077RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
3078 HandleScope scope(isolate);
3079 DCHECK_EQ(5, args.length());
3080 // Runtime functions don't follow the IC's calling convention.
3081 DirectHandle<Object> value = args.at(0);
3082 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3084 Handle<Object> key = args.at(4);
3085 FeedbackSlot vector_slot;
3086
3087 // When the feedback vector is not valid the slot can only be of type
3088 // StoreKeyed. Storing in array literals falls back to
3089 // StoreInArrayLiterIC_Miss. This function is also used from store handlers
3090 // installed in feedback vectors. In such cases, we need to get the kind from
3091 // feedback vector slot since the handlers are used for both for StoreKeyed
3092 // and StoreInArrayLiteral kinds.
3095 if (!IsUndefined(*maybe_vector, isolate)) {
3096 DCHECK(IsFeedbackVector(*maybe_vector));
3097 vector = Cast<FeedbackVector>(maybe_vector);
3098 int slot = args.tagged_index_value_at(1);
3099 vector_slot = FeedbackVector::ToSlot(slot);
3100 kind = vector->GetKind(vector_slot);
3101 }
3102
3103 // The elements store stubs miss into this function, but they are shared by
3104 // different ICs.
3105 // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of KeyedStoreIC,
3106 // which can be called here.
3108 KeyedStoreIC ic(isolate, vector, vector_slot, kind);
3109 ic.UpdateState(receiver, key);
3110 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
3111 } else {
3113 DCHECK(IsJSArray(*receiver));
3114 DCHECK(IsNumber(*key));
3115 StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
3116 ic.UpdateState(receiver, key);
3118 ic.Store(Cast<JSArray>(receiver), key, value));
3119 }
3120}
3121
3122RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Miss) {
3123 HandleScope scope(isolate);
3124 DCHECK_EQ(5, args.length());
3125 // Runtime functions don't follow the IC's calling convention.
3126 DirectHandle<Object> value = args.at(0);
3127 int slot = args.tagged_index_value_at(1);
3128 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3130 Handle<Object> key = args.at(4);
3131 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
3132
3135 if (!IsUndefined(*maybe_vector, isolate)) {
3136 DCHECK(IsFeedbackVector(*maybe_vector));
3137 vector = Cast<FeedbackVector>(maybe_vector);
3138 kind = vector->GetKind(vector_slot);
3140 }
3141
3142 // TODO(v8:12548): refactor DefineKeyedOwnIC as a subclass of KeyedStoreIC,
3143 // which can be called here.
3144 KeyedStoreIC ic(isolate, vector, vector_slot, kind);
3145 ic.UpdateState(receiver, key);
3146 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
3147}
3148
3149RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
3150 HandleScope scope(isolate);
3151 DCHECK_EQ(5, args.length());
3152 // Runtime functions don't follow the IC's calling convention.
3153 DirectHandle<Object> value = args.at(0);
3154 int slot = args.tagged_index_value_at(1);
3155 Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
3157 Handle<Object> key = args.at(4);
3159 if (!IsUndefined(*maybe_vector, isolate)) {
3160 DCHECK(IsFeedbackVector(*maybe_vector));
3161 vector = Cast<FeedbackVector>(maybe_vector);
3162 }
3163 DCHECK(IsJSArray(*receiver));
3164 DCHECK(IsNumber(*key));
3165 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
3166 StoreInArrayLiteralIC ic(isolate, vector, vector_slot);
3168 ic.Store(Cast<JSArray>(receiver), key, value));
3169}
3170
3171RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
3172 HandleScope scope(isolate);
3173 DCHECK_EQ(3, args.length());
3174 // Runtime functions don't follow the IC's calling convention.
3175 DirectHandle<Object> value = args.at(0);
3176 DirectHandle<JSAny> object = args.at<JSAny>(1);
3179 isolate, Runtime::SetObjectProperty(isolate, object, key, value,
3181}
3182
3183RUNTIME_FUNCTION(Runtime_DefineKeyedOwnIC_Slow) {
3184 HandleScope scope(isolate);
3185 DCHECK_EQ(3, args.length());
3186 // Runtime functions don't follow the IC's calling convention.
3187 DirectHandle<Object> value = args.at(0);
3188 DirectHandle<JSAny> object = args.at<JSAny>(1);
3191 isolate, Runtime::DefineObjectOwnProperty(isolate, object, key, value,
3193}
3194
3195RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
3196 HandleScope scope(isolate);
3197 DCHECK_EQ(3, args.length());
3198 // Runtime functions don't follow the IC's calling convention.
3199 DirectHandle<Object> value = args.at(0);
3200 DirectHandle<Object> array = args.at(1);
3201 Handle<Object> index = args.at(2);
3202 StoreOwnElement(isolate, Cast<JSArray>(array), index, value);
3203 return *value;
3204}
3205
3206RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
3207 HandleScope scope(isolate);
3208 DCHECK_EQ(6, args.length());
3209 // Runtime functions don't follow the IC's calling convention.
3210 DirectHandle<JSAny> object = args.at<JSAny>(0);
3211 Handle<Object> key = args.at(1);
3212 DirectHandle<Object> value = args.at(2);
3213 DirectHandle<Map> map = args.at<Map>(3);
3214 int slot = args.tagged_index_value_at(4);
3216 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
3217 FeedbackSlotKind kind = vector->GetKind(vector_slot);
3218
3219 if (IsJSObject(*object)) {
3221 map->elements_kind());
3222 }
3223
3225 StoreOwnElement(isolate, Cast<JSArray>(object), key, value);
3226 return *value;
3227 } else {
3233 isolate, object, key, value, StoreOrigin::kNamed)
3234 : Runtime::SetObjectProperty(isolate, object, key, value,
3236 }
3237}
3238
3239namespace {
3240
3241enum class FastCloneObjectMode {
3242 // The clone has the same map as the input.
3243 kIdenticalMap,
3244 // The clone is the empty object literal.
3245 kEmptyObject,
3246 // The clone has an empty object literal map.
3247 kDifferentMap,
3248 // The source map is to complicated to handle.
3249 kNotSupported,
3250 // Returned by PreCheck
3251 kMaybeSupported
3252};
3253
3254FastCloneObjectMode GetCloneModeForMapPreCheck(DirectHandle<Map> map,
3255 bool null_proto_literal,
3256 Isolate* isolate) {
3258 if (!IsJSObjectMap(*map)) {
3259 // Everything that produces the empty object literal can be supported since
3260 // we have a special case for that.
3261 if (null_proto_literal) return FastCloneObjectMode::kNotSupported;
3262 return IsNullOrUndefinedMap(*map) || IsBooleanMap(*map) ||
3263 IsHeapNumberMap(*map)
3264 ? FastCloneObjectMode::kEmptyObject
3265 : FastCloneObjectMode::kNotSupported;
3266 }
3267 ElementsKind elements_kind = map->elements_kind();
3268 if (!IsSmiOrObjectElementsKind(elements_kind) &&
3269 !IsAnyNonextensibleElementsKind(elements_kind)) {
3270 return FastCloneObjectMode::kNotSupported;
3271 }
3272 if (!map->OnlyHasSimpleProperties()) {
3273 return FastCloneObjectMode::kNotSupported;
3274 }
3275
3276 // TODO(olivf): Think about cases where cross-context copies are safe.
3277 if (!map->BelongsToSameNativeContextAs(isolate->context())) {
3278 return FastCloneObjectMode::kNotSupported;
3279 }
3280
3281 return FastCloneObjectMode::kMaybeSupported;
3282}
3283
3284FastCloneObjectMode GetCloneModeForMap(DirectHandle<Map> map,
3285 bool null_proto_literal,
3286 Isolate* isolate) {
3287 FastCloneObjectMode pre_check =
3288 GetCloneModeForMapPreCheck(map, null_proto_literal, isolate);
3289 if (pre_check != FastCloneObjectMode::kMaybeSupported) {
3290 return pre_check;
3291 }
3292
3293 // The clone must always start from an object literal map, it must be an
3294 // instance of the object function, have the default prototype and not be a
3295 // prototype itself. Only if the source map fits that criterion we can
3296 // directly use it as the target map.
3297 FastCloneObjectMode mode =
3298 map->instance_type() == JS_OBJECT_TYPE &&
3299 !IsAnyNonextensibleElementsKind(map->elements_kind()) &&
3300 map->GetConstructor() == *isolate->object_function() &&
3301 map->prototype() == *isolate->object_function_prototype() &&
3302 !map->is_prototype_map()
3303 ? FastCloneObjectMode::kIdenticalMap
3304 : FastCloneObjectMode::kDifferentMap;
3305
3306 if (null_proto_literal || IsNull(map->prototype())) {
3307 mode = FastCloneObjectMode::kDifferentMap;
3308 }
3309
3310 Tagged<DescriptorArray> descriptors = map->instance_descriptors();
3311 for (InternalIndex i : map->IterateOwnDescriptors()) {
3312 PropertyDetails details = descriptors->GetDetails(i);
3313 Tagged<Name> key = descriptors->GetKey(i);
3314 if (details.kind() != PropertyKind::kData || !details.IsEnumerable() ||
3315 key->IsPrivateName()) {
3316 return FastCloneObjectMode::kNotSupported;
3317 }
3318 if (!details.IsConfigurable() || details.IsReadOnly()) {
3319 mode = FastCloneObjectMode::kDifferentMap;
3320 }
3321 }
3322
3323 DCHECK_IMPLIES(mode == FastCloneObjectMode::kIdenticalMap,
3324 !map->is_prototype_map());
3325
3326 return mode;
3327}
3328
3329bool CanCacheCloneTargetMapTransition(
3330 DirectHandle<Map> source_map, std::optional<DirectHandle<Map>> target_map,
3331 bool null_proto_literal, Isolate* isolate) {
3332 if (!v8_flags.clone_object_sidestep_transitions || null_proto_literal) {
3333 return false;
3334 }
3335 // As of now any R/O source object should end up in the kEmptyObject case, but
3336 // there is not really a way of ensuring it. Thus, we also check it below.
3337 // This is a performance dcheck. If it fails, the clone IC does not handle a
3338 // case it probably could.
3339 // TODO(olivf): Either remove that dcheck or move it to GetCloneModeForMap.
3340 DCHECK(!HeapLayout::InReadOnlySpace(*source_map));
3341 if (HeapLayout::InReadOnlySpace(*source_map) || source_map->is_deprecated() ||
3342 source_map->is_prototype_map()) {
3343 return false;
3344 }
3345 if (!target_map) {
3346 return true;
3347 }
3348 CHECK(!HeapLayout::InReadOnlySpace(**target_map));
3349 return !(*target_map)->is_deprecated();
3350}
3351
3352// Check if an object with `source_map` can be cloned by `FastCloneJSObject`
3353// when the result shall have `target_map`. Optionally `override_map` is the map
3354// of an already existing object that will be written into. If no `override_map`
3355// is given, we assume that a fresh target object can be allocated with
3356// already the correct `target_map`.
3357bool CanFastCloneObjectToObjectLiteral(DirectHandle<Map> source_map,
3358 DirectHandle<Map> target_map,
3359 DirectHandle<Map> override_map,
3360 bool null_proto_literal,
3361 Isolate* isolate) {
3363 DCHECK(!target_map->is_deprecated());
3364 DCHECK(source_map->OnlyHasSimpleProperties());
3365 DCHECK(!source_map->IsInobjectSlackTrackingInProgress());
3366 DCHECK(!target_map->IsInobjectSlackTrackingInProgress());
3367 DCHECK_EQ(*target_map->map(), *source_map->map());
3368 DCHECK_EQ(target_map->GetConstructor(), *isolate->object_function());
3370 !null_proto_literal,
3371 *target_map->prototype() == *isolate->object_function_prototype());
3372
3373 // Ensure source and target have identical binary representation of properties
3374 // and elements as the IC relies on copying the raw bytes. This also excludes
3375 // cases with non-enumerable properties or accessors on the source object.
3376 if (source_map->instance_type() != JS_OBJECT_TYPE ||
3377 target_map->instance_type() != JS_OBJECT_TYPE ||
3378 !target_map->OnlyHasSimpleProperties() ||
3379 !target_map->has_fast_elements()) {
3380 return false;
3381 }
3382 if (!override_map.is_null()) {
3383 // No cross-context object reuse.
3384 if (target_map->map() != override_map->map()) {
3385 return false;
3386 }
3387 // In case we want to clone into an existing target object, we must ensure
3388 // that this existing object has a compatible size. In particular we cannot
3389 // shrink or grow the already given object. We also exclude a different
3390 // start offset, since this doesn't allow us to change the object in-place
3391 // in a GC safe way.
3392 DCHECK_EQ(*override_map, isolate->object_function()->initial_map());
3393 DCHECK(override_map->instance_type() == JS_OBJECT_TYPE);
3394 DCHECK_EQ(override_map->NumberOfOwnDescriptors(), 0);
3395 DCHECK(!override_map->IsInobjectSlackTrackingInProgress());
3396 if (override_map->instance_size() != target_map->instance_size() ||
3397 override_map->GetInObjectPropertiesStartInWords() !=
3398 target_map->GetInObjectPropertiesStartInWords()) {
3399 return false;
3400 }
3401 }
3402#ifdef DEBUG
3403 ElementsKind source_elements_kind = source_map->elements_kind();
3404 ElementsKind target_elements_kind = target_map->elements_kind();
3405 DCHECK(IsSmiOrObjectElementsKind(source_elements_kind) ||
3406 IsAnyNonextensibleElementsKind(source_elements_kind));
3407 DCHECK(IsSmiOrObjectElementsKind(target_elements_kind));
3408 DCHECK_IMPLIES(IsHoleyElementsKindForRead(source_elements_kind),
3409 IsHoleyElementsKind(target_elements_kind));
3410#endif // DEBUG
3411 // There are no transitions between prototype maps.
3412 if (source_map->is_prototype_map() || target_map->is_prototype_map()) {
3413 return false;
3414 }
3415 // Exclude edge-cases like not copying a __proto__ property.
3416 if (source_map->NumberOfOwnDescriptors() !=
3417 target_map->NumberOfOwnDescriptors()) {
3418 return false;
3419 }
3420 // Check that the source inobject properties fit into the target.
3421 int source_used_inobj_properties = source_map->GetInObjectProperties() -
3422 source_map->UnusedInObjectProperties();
3423 int target_used_inobj_properties = target_map->GetInObjectProperties() -
3424 target_map->UnusedInObjectProperties();
3425 if (source_used_inobj_properties != target_used_inobj_properties) {
3426 return false;
3427 }
3428 // The properties backing store must be of the same size as the clone ic again
3429 // blindly copies it.
3430 if (source_map->HasOutOfObjectProperties() !=
3431 target_map->HasOutOfObjectProperties() ||
3432 (target_map->HasOutOfObjectProperties() &&
3433 source_map->UnusedPropertyFields() !=
3434 target_map->UnusedPropertyFields())) {
3435 return false;
3436 }
3437 Tagged<DescriptorArray> descriptors = source_map->instance_descriptors();
3438 Tagged<DescriptorArray> target_descriptors =
3439 target_map->instance_descriptors();
3440 for (InternalIndex i : target_map->IterateOwnDescriptors()) {
3441 if (descriptors->GetKey(i) != target_descriptors->GetKey(i)) {
3442 return false;
3443 }
3444 PropertyDetails details = descriptors->GetDetails(i);
3445 PropertyDetails target_details = target_descriptors->GetDetails(i);
3446 DCHECK_EQ(details.kind(), PropertyKind::kData);
3447 DCHECK_EQ(target_details.kind(), PropertyKind::kData);
3448 Tagged<FieldType> type = descriptors->GetFieldType(i);
3449 Tagged<FieldType> target_type = target_descriptors->GetFieldType(i);
3450 // This DCHECK rests on the fact that we only clear field types when there
3451 // are no instances of the host map left. Thus, to enter the clone IC at
3452 // least one object of the source map needs to be created, which in turn
3453 // will re-initialize the source maps field type. This is guaranteed to also
3454 // update the target map through the sidestep transition, unless the target
3455 // map is deprecated.
3456 DCHECK(!IsNone(type));
3457 DCHECK(!IsNone(target_type));
3458 // With move_prototype_transitions_first enabled field updates don't
3459 // generalize across prototype transitions, because the transitions happen
3460 // on root maps (i.e., before any field is added). In other words we cannot
3461 // rely on changes in the source map propagating to the target map when
3462 // there is a SetPrototype involved. NB, technically without
3463 // move_prototype_transitions_first we also don't update field types across
3464 // prototype transitions, however we preemptively generalize all fields of
3465 // prototype transition target maps.
3466 bool prototype_transition_is_shortcutted =
3467 v8_flags.move_prototype_transitions_first &&
3468 source_map->prototype() != target_map->prototype();
3469 if (!prototype_transition_is_shortcutted &&
3470 CanCacheCloneTargetMapTransition(source_map, target_map,
3471 null_proto_literal, isolate)) {
3472 if (!details.representation().fits_into(
3473 target_details.representation()) ||
3474 (target_details.representation().IsDouble() &&
3475 details.representation().IsSmi())) {
3476 return false;
3477 }
3478 if (!FieldType::NowIs(type, target_type)) {
3479 return false;
3480 }
3481 } else {
3482 // In the case we cannot connect the maps in the transition tree (e.g.,
3483 // the clone also involves a proto transition) we cannot keep track of
3484 // representation dependencies. We can only allow the most generic target
3485 // representation. The same goes for field types.
3486 if (!details.representation().MostGenericInPlaceChange().Equals(
3487 target_details.representation()) ||
3488 !IsAny(target_type)) {
3489 return false;
3490 }
3491 }
3492 }
3493 return true;
3494}
3495
3496} // namespace
3497
3499 Isolate* isolate, DirectHandle<Object> source, int flags) {
3500 DirectHandle<JSObject> new_object;
3502 new_object = isolate->factory()->NewJSObjectWithNullProto();
3503 } else if (IsJSObject(*source) &&
3504 Cast<JSObject>(*source)->map()->OnlyHasSimpleProperties()) {
3505 Tagged<Map> source_map = Cast<JSObject>(*source)->map();
3506 // TODO(olivf, chrome:1204540) It might be interesting to pick a map with
3507 // more properties, depending how many properties are added by the
3508 // surrounding literal.
3509 int properties = source_map->GetInObjectProperties() -
3510 source_map->UnusedInObjectProperties();
3511 DirectHandle<Map> map = isolate->factory()->ObjectLiteralMapFromCache(
3512 isolate->native_context(), properties);
3513 new_object = isolate->factory()->NewFastOrSlowJSObjectFromMap(map);
3514 } else {
3515 DirectHandle<JSFunction> constructor(
3516 isolate->native_context()->object_function(), isolate);
3517 new_object = isolate->factory()->NewJSObject(constructor);
3518 }
3519
3520 if (IsNullOrUndefined(*source)) {
3521 return new_object;
3522 }
3523
3526 isolate, new_object, source,
3529 return new_object;
3530}
3531
3532RUNTIME_FUNCTION(Runtime_CloneObjectIC_Slow) {
3533 HandleScope scope(isolate);
3534 DCHECK_EQ(2, args.length());
3535 DirectHandle<Object> source = args.at(0);
3536 int flags = args.smi_value_at(1);
3538 CloneObjectSlowPath(isolate, source, flags));
3539}
3540
3541namespace {
3542
3543template <SideStepTransition::Kind kind>
3544Tagged<Object> GetCloneTargetMap(Isolate* isolate, DirectHandle<Map> source_map,
3545 DirectHandle<Map> override_map) {
3548 if (!v8_flags.clone_object_sidestep_transitions) {
3550 }
3551
3552 // Ensure we can follow the sidestep transition NativeContext-wise.
3553 if (!source_map->BelongsToSameNativeContextAs(isolate->context())) {
3555 }
3557 TransitionsAccessor transitions(isolate, *source_map);
3558 if (transitions.HasSideStepTransitions()) {
3559 result = transitions.GetSideStepTransition(kind);
3560 if (result.IsHeapObject()) {
3561 // Exclude deprecated maps.
3562 auto map = Cast<Map>(result.GetHeapObject());
3563 bool is_valid = !map->is_deprecated();
3564 // In the case of object assign we need to check the prototype validity
3565 // cell on the override map. If the override map changed we cannot assume
3566 // that it is correct to set all properties without any getter/setter in
3567 // the prototype chain interfering.
3569 if (is_valid) {
3570 DCHECK_EQ(*override_map, isolate->object_function()->initial_map());
3571 Tagged<Object> validity_cell = transitions.GetSideStepTransition(
3573 is_valid = validity_cell.IsHeapObject() &&
3574 Cast<Cell>(validity_cell)->value().ToSmi().value() ==
3576 }
3577 }
3578 if (V8_LIKELY(is_valid)) {
3579 if (result.IsHeapObject()) {
3580 CHECK_EQ(GetCloneModeForMapPreCheck(source_map, false, isolate),
3581 FastCloneObjectMode::kMaybeSupported);
3582 }
3583 } else {
3585 }
3586 }
3587 }
3588#ifdef DEBUG
3589 FastCloneObjectMode clone_mode =
3590 GetCloneModeForMap(source_map, false, isolate);
3592 switch (clone_mode) {
3593 case FastCloneObjectMode::kNotSupported:
3594 case FastCloneObjectMode::kDifferentMap:
3595 break;
3596 case FastCloneObjectMode::kEmptyObject:
3597 case FastCloneObjectMode::kIdenticalMap:
3599 break;
3600 case FastCloneObjectMode::kMaybeSupported:
3601 UNREACHABLE();
3602 }
3603 } else if (result != SideStepTransition::Empty) {
3604 Tagged<Map> target = Cast<Map>(result.GetHeapObject());
3605 switch (clone_mode) {
3606 case FastCloneObjectMode::kIdenticalMap:
3608 DCHECK_EQ(*source_map, target);
3609 break;
3610 }
3612 [[fallthrough]];
3613 case FastCloneObjectMode::kDifferentMap:
3614 DCHECK(CanFastCloneObjectToObjectLiteral(source_map,
3615 direct_handle(target, isolate),
3616 override_map, false, isolate));
3617 break;
3618 default:
3619 UNREACHABLE();
3620 }
3621 } else {
3623 }
3624#endif // DEBUG
3625 return result;
3626}
3627
3628template <SideStepTransition::Kind kind>
3629void SetCloneTargetMap(Isolate* isolate, DirectHandle<Map> source_map,
3630 DirectHandle<Map> new_target_map,
3631 DirectHandle<Map> override_map) {
3632 if (!v8_flags.clone_object_sidestep_transitions) return;
3633 DCHECK(CanCacheCloneTargetMapTransition(source_map, new_target_map, false,
3634 isolate));
3635 DCHECK_EQ(GetCloneTargetMap<kind>(isolate, source_map, override_map),
3637 DCHECK(!new_target_map->is_deprecated());
3638
3639 // Adding this transition also ensures that when the source map field
3640 // generalizes, we also generalize the target map.
3641 DCHECK(IsSmiOrObjectElementsKind(new_target_map->elements_kind()));
3642
3643 constexpr bool need_validity_cell =
3645 DirectHandle<Cell> validity_cell;
3646 if constexpr (need_validity_cell) {
3647 // Since we only clone into empty object literals we only need one validity
3648 // cell on that prototype chain.
3649 DCHECK_EQ(*override_map, isolate->object_function()->initial_map());
3650 validity_cell = Cast<Cell>(
3651 Map::GetOrCreatePrototypeChainValidityCell(override_map, isolate));
3652 }
3654 TransitionsAccessor transitions(isolate, *source_map);
3655 transitions.SetSideStepTransition(kind, *new_target_map);
3656 if constexpr (need_validity_cell) {
3657 transitions.SetSideStepTransition(
3659 }
3660 DCHECK_EQ(GetCloneTargetMap<kind>(isolate, source_map, override_map),
3661 *new_target_map);
3662}
3663
3664template <SideStepTransition::Kind kind>
3665void SetCloneTargetMapUnsupported(Isolate* isolate,
3666 DirectHandle<Map> source_map,
3667 DirectHandle<Map> override_map) {
3668 if (!v8_flags.clone_object_sidestep_transitions) return;
3669 DCHECK_EQ(GetCloneTargetMap<kind>(isolate, source_map, override_map),
3671 DCHECK(CanCacheCloneTargetMapTransition(source_map, {}, false, isolate));
3672 // Adding this transition also ensures that when the source map field
3673 // generalizes, we also generalize the target map.
3675 TransitionsAccessor(isolate, *source_map)
3676 .SetSideStepTransition(kind, SideStepTransition::Unreachable);
3677 DCHECK_EQ(GetCloneTargetMap<kind>(isolate, source_map, override_map),
3679}
3680
3681} // namespace
3682
3683RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) {
3684 HandleScope scope(isolate);
3685 DCHECK_EQ(4, args.length());
3686 DirectHandle<Object> source = args.at(0);
3687 int flags = args.smi_value_at(1);
3688
3689 if (!MigrateDeprecated(isolate, source)) {
3690 Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
3691 std::optional<FeedbackNexus> nexus;
3692 if (IsFeedbackVector(*maybe_vector)) {
3693 int index = args.tagged_index_value_at(2);
3695 nexus.emplace(isolate, Cast<FeedbackVector>(maybe_vector), slot);
3696 }
3697 if (!IsSmi(*source) && (!nexus || !nexus->IsMegamorphic())) {
3698 bool null_proto_literal = flags & ObjectLiteral::kHasNullPrototype;
3699 Handle<Map> source_map(Cast<HeapObject>(source)->map(), isolate);
3700
3701 // In case we are still slack tracking let's defer a decision. The fast
3702 // case does not support it.
3703 if (!source_map->IsInobjectSlackTrackingInProgress()) {
3704 auto UpdateNexus = [&](Handle<Object> target_map) {
3705 if (!nexus) return;
3706 nexus->ConfigureCloneObject(source_map,
3707 MaybeObjectHandle(target_map));
3708 };
3709 ReadOnlyRoots roots(isolate);
3710 bool unsupported = false;
3711 if (!null_proto_literal) {
3712 auto maybe_target =
3713 GetCloneTargetMap<SideStepTransition::Kind::kCloneObject>(
3714 isolate, source_map, {});
3715 if (maybe_target == SideStepTransition::Unreachable) {
3716 unsupported = true;
3717 } else if (maybe_target != SideStepTransition::Empty) {
3718 Handle<Map> target =
3719 handle(Cast<Map>(maybe_target.GetHeapObject()), isolate);
3720 UpdateNexus(target);
3721 return *target;
3722 }
3723 }
3724
3725 FastCloneObjectMode clone_mode =
3726 unsupported
3727 ? FastCloneObjectMode::kNotSupported
3728 : GetCloneModeForMap(source_map, null_proto_literal, isolate);
3729 auto UpdateState = [&](Handle<Map> target_map) {
3730 UpdateNexus(target_map);
3731 if (CanCacheCloneTargetMapTransition(source_map, target_map,
3732 null_proto_literal, isolate)) {
3733 SetCloneTargetMap<SideStepTransition::Kind::kCloneObject>(
3734 isolate, source_map, target_map, {});
3735 }
3736 };
3737 switch (clone_mode) {
3738 case FastCloneObjectMode::kIdenticalMap: {
3739 UpdateState(source_map);
3740 // When returning a map the IC miss handler re-starts from the top.
3741 return *source_map;
3742 }
3743 case FastCloneObjectMode::kEmptyObject: {
3744 UpdateNexus(handle(Smi::zero(), isolate));
3746 isolate, CloneObjectSlowPath(isolate, source, flags));
3747 }
3748 case FastCloneObjectMode::kDifferentMap: {
3751 isolate, res, CloneObjectSlowPath(isolate, source, flags));
3752 Handle<Map> result_map(Cast<HeapObject>(res)->map(), isolate);
3753 if (result_map->IsInobjectSlackTrackingInProgress()) {
3754 return *res;
3755 }
3756 if (CanFastCloneObjectToObjectLiteral(
3757 source_map, result_map, {}, null_proto_literal, isolate)) {
3758 DCHECK(result_map->OnlyHasSimpleProperties());
3759 DCHECK_EQ(source_map->GetInObjectProperties() -
3760 source_map->UnusedInObjectProperties(),
3761 result_map->GetInObjectProperties() -
3762 result_map->UnusedInObjectProperties());
3763 UpdateState(result_map);
3764 } else {
3765 if (CanCacheCloneTargetMapTransition(
3766 source_map, {}, null_proto_literal, isolate)) {
3767 SetCloneTargetMapUnsupported<
3769 {});
3770 }
3771 if (nexus) {
3772 nexus->ConfigureMegamorphic();
3773 }
3774 }
3775 return *res;
3776 }
3777 case FastCloneObjectMode::kNotSupported: {
3778 break;
3779 }
3780 case FastCloneObjectMode::kMaybeSupported:
3781 UNREACHABLE();
3782 }
3783 DCHECK(clone_mode == FastCloneObjectMode::kNotSupported);
3784 if (nexus) {
3785 nexus->ConfigureMegamorphic();
3786 }
3787 }
3788 }
3789 }
3790
3792 CloneObjectSlowPath(isolate, source, flags));
3793}
3794
3795RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
3797 DirectHandle<JSObject> holder = args.at<JSObject>(1);
3799 DirectHandle<Name> name = args.at<Name>(3);
3800 DirectHandle<Object> value = args.at(4);
3801 HandleScope scope(isolate);
3802
3803#ifdef V8_RUNTIME_CALL_STATS
3804 if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) {
3806 isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
3808 }
3809#endif
3810
3811 PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
3813 std::ignore = arguments.CallAccessorSetter(info, name, value);
3815 return *value;
3816}
3817
3818namespace {
3819
3820bool MaybeCanCloneObjectForObjectAssign(DirectHandle<JSReceiver> source,
3821 DirectHandle<Map> source_map,
3822 DirectHandle<JSReceiver> target,
3823 Isolate* isolate) {
3824 FastCloneObjectMode clone_mode =
3825 GetCloneModeForMap(source_map, false, isolate);
3826 switch (clone_mode) {
3827 case FastCloneObjectMode::kIdenticalMap:
3828 case FastCloneObjectMode::kDifferentMap:
3829 break;
3830 case FastCloneObjectMode::kNotSupported:
3831 return false;
3832 case FastCloneObjectMode::kEmptyObject:
3833 case FastCloneObjectMode::kMaybeSupported:
3834 // Cannot happen since we should only be called with JSObjects.
3835 UNREACHABLE();
3836 }
3837
3838 // We need to be sure that there are no setters or other nastiness installed
3839 // on the Object.prototype which clash with the properties we intende to copy.
3840 DirectHandle<FixedArray> keys;
3841 auto res =
3844 CHECK(res.ToHandle(&keys));
3845 for (int i = 0; i < keys->length(); ++i) {
3846 Handle<Object> next_key(keys->get(i), isolate);
3847 PropertyKey key(isolate, next_key);
3848 LookupIterator it(isolate, target, key);
3849 switch (it.state()) {
3851 break;
3853 if (it.property_attributes() & PropertyAttributes::READ_ONLY) {
3854 return false;
3855 }
3856 break;
3857 default:
3858 return false;
3859 }
3860 }
3861 return true;
3862}
3863
3864} // namespace
3865
3866// Returns one of:
3867// * A map to be used with FastCloneJSObject
3868// * Undefined if fast cloning is not possible
3869// * True if assignment must be skipped (i.e., the runtime already did it)
3870RUNTIME_FUNCTION(Runtime_ObjectAssignTryFastcase) {
3871 HandleScope scope(isolate);
3872 DCHECK_EQ(2, args.length());
3873 auto source = Cast<JSReceiver>(args.at(0));
3874 auto target = Cast<JSReceiver>(args.at(1));
3875 DCHECK(IsJSObject(*source));
3876 DCHECK(IsJSObject(*target));
3877
3878 Handle<Map> source_map = handle(source->map(), isolate);
3879 Handle<Map> target_map = handle(target->map(), isolate);
3880
3881 DCHECK_EQ(target_map->NumberOfOwnDescriptors(), 0);
3882 DCHECK(!source_map->is_dictionary_map());
3883 DCHECK(!target_map->is_dictionary_map());
3884 DCHECK(!source_map->is_deprecated());
3885 DCHECK(!target_map->is_deprecated());
3886 DCHECK(target_map->is_extensible());
3887 DCHECK(!IsUndefined(*source, isolate) && !IsNull(*source, isolate));
3888 DCHECK(source_map->BelongsToSameNativeContextAs(isolate->context()));
3889
3890 ReadOnlyRoots roots(isolate);
3891 {
3892 Tagged<Object> maybe_clone_target =
3893 GetCloneTargetMap<SideStepTransition::Kind::kObjectAssign>(
3894 isolate, source_map, target_map);
3895 if (maybe_clone_target == SideStepTransition::Unreachable) {
3896 return roots.undefined_value();
3897 } else if (maybe_clone_target != SideStepTransition::Empty) {
3898 return Cast<Map>(maybe_clone_target.GetHeapObject());
3899 }
3900 }
3901
3902 auto UpdateCache = [&](Handle<Map> clone_target_map) {
3903 if (CanCacheCloneTargetMapTransition(source_map, clone_target_map, false,
3904 isolate)) {
3905 SetCloneTargetMap<SideStepTransition::Kind::kObjectAssign>(
3906 isolate, source_map, clone_target_map, target_map);
3907 }
3908 };
3909 auto UpdateCacheNotClonable = [&]() {
3910 if (CanCacheCloneTargetMapTransition(source_map, {}, false, isolate)) {
3911 SetCloneTargetMapUnsupported<SideStepTransition::Kind::kObjectAssign>(
3912 isolate, source_map, target_map);
3913 }
3914 };
3915
3916 // In case we are still slack tracking let's defer a decision. The fast case
3917 // does not support it.
3918 if (source_map->IsInobjectSlackTrackingInProgress() ||
3919 target_map->IsInobjectSlackTrackingInProgress()) {
3920 return roots.undefined_value();
3921 }
3922
3923 if (MaybeCanCloneObjectForObjectAssign(source, source_map, target, isolate)) {
3924 CHECK(target->map()->OnlyHasSimpleProperties());
3926 isolate, target, source, PropertiesEnumerationMode::kEnumerationOrder);
3927 DCHECK(res.FromJust());
3928 USE(res);
3929 Handle<Map> clone_target_map = handle(target->map(), isolate);
3930 if (clone_target_map->IsInobjectSlackTrackingInProgress()) {
3931 return roots.true_value();
3932 }
3933 if (CanFastCloneObjectToObjectLiteral(source_map, clone_target_map,
3934 target_map, false, isolate)) {
3935 CHECK(target->map()->OnlyHasSimpleProperties());
3936 UpdateCache(clone_target_map);
3937 } else {
3938 UpdateCacheNotClonable();
3939 }
3940 // We already did the copying here. Thus, returning true to cause the
3941 // CSA builtin to skip assigning anything.
3942 return roots.true_value();
3943 }
3944 UpdateCacheNotClonable();
3945 return roots.undefined_value();
3946}
3947
3952RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
3953 HandleScope scope(isolate);
3954 DCHECK_EQ(5, args.length());
3955 DirectHandle<Name> name = args.at<Name>(0);
3956 DirectHandle<Object> receiver_arg = args.at(1);
3957 Handle<JSObject> holder = args.at<JSObject>(2);
3958
3960 if (!TryCast<JSReceiver>(receiver_arg, &receiver)) {
3962 isolate, receiver, Object::ConvertReceiver(isolate, receiver_arg));
3963 }
3964
3965 {
3966 DirectHandle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(),
3967 isolate);
3968 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
3969 *holder, Just(kDontThrow));
3970
3971 DirectHandle<Object> result = arguments.CallNamedGetter(interceptor, name);
3972 // An exception was thrown in the interceptor. Propagate.
3973 RETURN_FAILURE_IF_EXCEPTION_DETECTOR(isolate, arguments);
3974
3975 if (!result.is_null()) {
3976 arguments.AcceptSideEffects();
3977 return *result;
3978 }
3979 // If the interceptor didn't handle the request, then there must be no
3980 // side effects.
3981 }
3982
3983 LookupIterator it(isolate, receiver, name, holder);
3984 // Skip any lookup work until we hit the (possibly non-masking) interceptor.
3985 while (it.state() != LookupIterator::INTERCEPTOR ||
3986 !it.GetHolder<JSObject>().is_identical_to(holder)) {
3987 DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess());
3988 it.Next();
3989 }
3990 // Skip past the interceptor.
3991 it.Next();
3994
3995 if (it.IsFound()) return *result;
3996
3997 int slot = args.tagged_index_value_at(3);
3999 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
4000 FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
4001 // It could actually be any kind of load IC slot here but the predicate
4002 // handles all the cases properly.
4003 if (!LoadIC::ShouldThrowReferenceError(slot_kind)) {
4004 return ReadOnlyRoots(isolate).undefined_value();
4005 }
4006
4007 // Throw a reference error.
4009 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
4010}
4011
4012RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
4013 HandleScope scope(isolate);
4014 DCHECK_EQ(3, args.length());
4015 // Runtime functions don't follow the IC's calling convention.
4016 DirectHandle<Object> value = args.at(0);
4018 DirectHandle<Name> name = args.at<Name>(2);
4019
4020 // TODO(ishell): Cache interceptor_holder in the store handler like we do
4021 // for LoadHandler::kInterceptor case.
4022 DirectHandle<JSObject> interceptor_holder = receiver;
4023 if (IsJSGlobalProxy(*receiver) &&
4024 (!receiver->HasNamedInterceptor() ||
4025 receiver->GetNamedInterceptor()->non_masking())) {
4026 interceptor_holder =
4027 direct_handle(Cast<JSObject>(receiver->map()->prototype()), isolate);
4028 }
4029 DCHECK(interceptor_holder->HasNamedInterceptor());
4030 {
4032 interceptor_holder->GetNamedInterceptor(), isolate);
4033
4034 DCHECK(!interceptor->non_masking());
4035 // TODO(ishell, 348688196): why is it known that it shouldn't throw?
4036 Maybe<ShouldThrow> should_throw = Just(kDontThrow);
4037 PropertyCallbackArguments callback_args(isolate, interceptor->data(),
4038 *receiver, *receiver, should_throw);
4039
4040 v8::Intercepted intercepted =
4041 callback_args.CallNamedSetter(interceptor, name, value);
4042 // Stores initiated by StoreICs don't care about the exact result of
4043 // the store operation returned by the callback as long as it doesn't
4044 // throw an exception.
4045 constexpr bool ignore_return_value = true;
4048 isolate, result,
4049 callback_args.GetBooleanReturnValue(intercepted, "Setter",
4050 ignore_return_value));
4051
4052 switch (result) {
4055 return *value;
4056
4058 // Proceed storing past the interceptor.
4059 break;
4060 }
4061 }
4062
4063 LookupIterator it(isolate, receiver, name, receiver);
4064 // Skip past any access check on the receiver.
4065 while (it.state() == LookupIterator::ACCESS_CHECK) {
4066 DCHECK(it.HasAccess());
4067 it.Next();
4068 }
4069 // Skip past the interceptor on the receiver.
4071 it.Next();
4072
4074 ReadOnlyRoots(isolate).exception());
4075 return *value;
4076}
4077
4078RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
4079 // TODO(verwaest): This should probably get the holder and receiver as input.
4080 HandleScope scope(isolate);
4082 DCHECK_GE(args.smi_value_at(1), 0);
4083 uint32_t index = args.smi_value_at(1);
4084
4085 DirectHandle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
4086 isolate);
4087 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
4089 DirectHandle<Object> result = arguments.CallIndexedGetter(interceptor, index);
4090 // An exception was thrown in the interceptor. Propagate.
4091 RETURN_FAILURE_IF_EXCEPTION_DETECTOR(isolate, arguments);
4092
4093 if (result.is_null()) {
4094 LookupIterator it(isolate, receiver, index, receiver);
4096 it.Next();
4098 Object::GetProperty(&it));
4099 }
4100
4101 return *result;
4102}
4103
4104RUNTIME_FUNCTION(Runtime_KeyedHasIC_Miss) {
4105 HandleScope scope(isolate);
4106 DCHECK_EQ(4, args.length());
4107 // Runtime functions don't follow the IC's calling convention.
4109 Handle<Object> key = args.at(1);
4110 int slot = args.tagged_index_value_at(2);
4111 Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
4112
4114 if (!IsUndefined(*maybe_vector, isolate)) {
4115 DCHECK(IsFeedbackVector(*maybe_vector));
4116 vector = Cast<FeedbackVector>(maybe_vector);
4117 }
4118 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot);
4119 KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kHasKeyed);
4120 ic.UpdateState(receiver, key);
4121 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
4122}
4123
4124RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) {
4125 HandleScope scope(isolate);
4127 DCHECK_GE(args.smi_value_at(1), 0);
4128 uint32_t index = args.smi_value_at(1);
4129
4130 {
4131 DirectHandle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
4132 isolate);
4133 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
4135
4136 if (interceptor->has_query()) {
4138 arguments.CallIndexedQuery(interceptor, index);
4139 // An exception was thrown in the interceptor. Propagate.
4140 RETURN_FAILURE_IF_EXCEPTION_DETECTOR(isolate, arguments);
4141 if (!result.is_null()) {
4142 int32_t value;
4143 CHECK(Object::ToInt32(*result, &value));
4144 // TODO(ishell): PropertyAttributes::ABSENT is not exposed in the Api,
4145 // so it can't be officially returned. We should fix the tests instead.
4146 if (value == ABSENT) return ReadOnlyRoots(isolate).false_value();
4147 arguments.AcceptSideEffects();
4148 return ReadOnlyRoots(isolate).true_value();
4149 }
4150 } else if (interceptor->has_getter()) {
4152 arguments.CallIndexedGetter(interceptor, index);
4153 // An exception was thrown in the interceptor. Propagate.
4154 RETURN_FAILURE_IF_EXCEPTION_DETECTOR(isolate, arguments);
4155 if (!result.is_null()) {
4156 arguments.AcceptSideEffects();
4157 return ReadOnlyRoots(isolate).true_value();
4158 }
4159 }
4160 // If the interceptor didn't handle the request, then there must be no
4161 // side effects.
4162 }
4163
4164 LookupIterator it(isolate, receiver, index, receiver);
4166 it.Next();
4168 if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
4169 return ReadOnlyRoots(isolate).boolean_value(maybe.FromJust());
4170}
4171
4172} // namespace internal
4173} // namespace v8
Isolate * isolate_
Builtins::Kind kind
Definition builtins.cc:40
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
PropertyT * getter
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
V8_INLINE bool IsNothing() const
Definition v8-maybe.h:35
uint32_t GetHash()
Definition api.cc:4282
static bool IsJSObjectFieldAccessor(Isolate *isolate, DirectHandle< Map > map, DirectHandle< Name > name, FieldIndex *field_index)
Definition accessors.cc:64
bool IsCompatibleReceiverMap(DirectHandle< JSObject > api_holder, Handle< JSObject > holder, HolderLookup) const
DirectHandle< FunctionTemplateInfo > api_call_info() const
Handle< JSObject > LookupHolderOfExpectedType(IsolateT *isolate, DirectHandle< Map > receiver_map, HolderLookup *holder_lookup) const
static DirectHandle< Object > LoadScriptContextElement(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:578
static void StoreScriptContextAndUpdateSlotProperty(DirectHandle< Context > script_context, int index, DirectHandle< Object > new_value, Isolate *isolate)
Definition contexts.cc:586
size_t size() const noexcept
Definition handles.h:1072
void erase(iterator erase_start)
Definition handles.h:1109
iterator begin() noexcept
Definition handles.h:893
iterator end() noexcept
Definition handles.h:897
void push_back(const DirectHandle< T > &x)
Definition handles.h:940
V8_INLINE bool is_null() const
Definition handles.h:693
V8_INLINE bool is_identical_to(Handle< S > other) const
Definition handles.h:716
static Tagged< Object > ThrowLoadFromNullOrUndefined(Isolate *isolate, DirectHandle< Object > object, MaybeDirectHandle< Object > key)
Definition messages.cc:1006
Handle< Boolean > ToBoolean(bool value)
DirectHandle< MegaDomHandler > NewMegaDomHandler(MaybeObjectDirectHandle accessor, MaybeObjectDirectHandle context)
Definition factory.cc:4111
Handle< StoreHandler > NewStoreHandler(int data_count)
Definition factory.cc:4141
FeedbackSlotKind kind() const
InlineCacheState ic_state() const
static FeedbackSlot Invalid()
Definition utils.h:648
static FeedbackSlot ToSlot(intptr_t index)
static bool NowIs(Tagged< FieldType > type, Tagged< FieldType > other)
Definition field-type.cc:68
V8_INLINE bool is_null() const
Definition handles.h:69
V8_INLINE bool is_identical_to(const HandleBase &that) const
Definition handles-inl.h:36
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
static V8_INLINE ICStats * instance()
Definition ic-stats.h:69
V8_INLINE ICInfo & Current()
Definition ic-stats.h:62
bool UpdatePolymorphicIC(DirectHandle< Name > name, const MaybeObjectDirectHandle &handler)
Definition ic.cc:620
State state_
Definition ic.h:170
void TraceIC(const char *type, DirectHandle< Object > name)
Definition ic.cc:108
bool IsDefineNamedOwnIC() const
Definition ic.h:128
void set_slow_stub_reason(const char *reason)
Definition ic.h:74
bool IsStoreInArrayLiteralIC() const
Definition ic.h:129
FeedbackSlotKind kind_
Definition ic.h:171
bool is_vector_set()
Definition ic.h:80
bool IsDefineKeyedOwnIC() const
Definition ic.h:134
Handle< Map > lookup_start_object_map()
Definition ic.h:141
void update_lookup_start_object_map(DirectHandle< Object > object)
Definition ic-inl.h:20
State state() const
Definition ic.h:38
bool IsLoadIC() const
Definition ic.h:123
bool IsAnyHas() const
Definition ic.h:52
bool vector_needs_update()
Definition ic-inl.h:39
bool IsStoreGlobalIC() const
Definition ic.h:126
const char * slow_stub_reason_
Definition ic.h:177
static bool IsHandler(Tagged< MaybeObject > object)
Definition ic-inl.h:29
void set_accessor(Handle< Object > accessor)
Definition ic.h:75
bool IsAnyStore() const
Definition ic.h:56
StubCache * stub_cache()
Definition ic.cc:825
bool IsKeyedHasIC() const
Definition ic.h:133
MaybeDirectHandle< Object > ReferenceError(Handle< Name > name)
Definition ic.cc:298
bool ShouldRecomputeHandler(DirectHandle< String > name)
Definition ic.cc:236
void MarkRecomputeHandler(DirectHandle< Object > name)
Definition ic.h:46
bool IsLoadGlobalIC() const
Definition ic.h:124
bool IsTransitionOfMonomorphicTarget(Tagged< Map > source_map, Tagged< Map > target_map)
Definition ic.cc:720
Isolate * isolate() const
Definition ic.h:78
Tagged< Map > FirstTargetMap()
Definition ic.h:151
MaybeHandle< Object > accessor() const
Definition ic.h:76
FeedbackSlotKind kind() const
Definition ic.h:121
MaybeDirectHandle< Object > TypeError(MessageTemplate, Handle< Object > object, Handle< Object > key)
Definition ic.cc:291
bool is_keyed() const
Definition ic.h:135
void UpdateState(DirectHandle< Object > lookup_start_object, DirectHandle< Object > name)
Definition ic.cc:275
void TargetMaps(MapHandles *list)
Definition ic.h:144
bool ConfigureVectorState(IC::State new_state, DirectHandle< Object > key)
Definition ic.cc:335
FeedbackNexus nexus_
Definition ic.h:179
Isolate * isolate_
Definition ic.h:166
void CopyICToMegamorphicCache(DirectHandle< Name > name)
Definition ic.cc:712
bool IsKeyedLoadIC() const
Definition ic.h:125
bool IsAnyLoad() const
Definition ic.h:53
bool RecomputeHandlerForName(DirectHandle< Object > name)
Definition ic.cc:264
bool vector_set_
Definition ic.h:168
char TransitionMarkFromState(IC::State state)
Definition ic.cc:55
State old_state_
Definition ic.h:169
void UpdateMegamorphicCache(DirectHandle< Map > map, DirectHandle< Name > name, const MaybeObjectDirectHandle &handler)
Definition ic.cc:839
bool IsAnyDefineOwn() const
Definition ic.h:61
bool UpdateMegaDOMIC(const MaybeObjectDirectHandle &handler, DirectHandle< Name > name)
Definition ic.cc:561
void UpdateMonomorphicIC(const MaybeObjectDirectHandle &handler, DirectHandle< Name > name)
Definition ic.cc:706
IC(Isolate *isolate, Handle< FeedbackVector > vector, FeedbackSlot slot, FeedbackSlotKind kind)
Definition ic.cc:181
bool IsKeyedStoreIC() const
Definition ic.h:132
const FeedbackNexus * nexus() const
Definition ic.h:156
static void OnFeedbackChanged(Isolate *isolate, Tagged< FeedbackVector > vector, FeedbackSlot slot, const char *reason)
Definition ic.cc:312
void SetCache(DirectHandle< Name > name, Handle< Object > handler)
Definition ic.cc:737
bool IsGlobalIC() const
Definition ic.h:122
Handle< JSGlobalObject > global_object()
StubCache * load_stub_cache() const
Definition isolate.h:1312
StubCache * store_stub_cache() const
Definition isolate.h:1313
StubCache * define_own_stub_cache() const
Definition isolate.h:1314
v8::internal::Factory * factory()
Definition isolate.h:1527
static constexpr uint32_t kMaxArrayIndex
Definition js-array.h:131
static bool MayHaveReadOnlyLength(Tagged< Map > js_array_map)
Definition objects.cc:4949
static bool HasReadOnlyLength(DirectHandle< JSArray > array)
Definition objects.cc:4962
static V8_WARN_UNUSED_RESULT HandleType< Object >::MaybeType DefineOwnPropertyIgnoreAttributes(LookupIterator *it, HandleType< T > value, PropertyAttributes attributes, AccessorInfoHandling handling=DONT_FORCE_FIELD, EnforceDefineSemantics semantics=EnforceDefineSemantics::kSet)
static constexpr uint32_t kMaxElementIndex
Definition js-objects.h:924
static V8_WARN_UNUSED_RESULT Maybe< bool > CheckIfCanDefineAsConfigurable(Isolate *isolate, LookupIterator *it, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
static void MakePrototypesFast(DirectHandle< Object > receiver, WhereToStart where_to_start, Isolate *isolate)
static V8_EXPORT_PRIVATE void TransitionElementsKind(DirectHandle< JSObject > object, ElementsKind to_kind)
static void MigrateInstance(Isolate *isolate, DirectHandle< JSObject > instance)
static V8_WARN_UNUSED_RESULT Maybe< bool > DefineOwnProperty(Isolate *isolate, DirectHandle< JSProxy > object, DirectHandle< Object > key, PropertyDescriptor *desc, Maybe< ShouldThrow > should_throw)
Definition objects.cc:3317
static V8_WARN_UNUSED_RESULT Maybe< bool > CreateDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > key, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
static V8_WARN_UNUSED_RESULT Maybe< bool > CheckPrivateNameStore(LookupIterator *it, bool is_define)
static V8_WARN_UNUSED_RESULT Maybe< bool > SetOrCopyDataProperties(Isolate *isolate, DirectHandle< JSReceiver > target, DirectHandle< Object > source, PropertiesEnumerationMode mode, base::Vector< DirectHandle< Object > > excluded_properties={}, bool use_set=true)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > HasProperty(LookupIterator *it)
Definition js-objects.cc:98
static V8_WARN_UNUSED_RESULT Maybe< bool > AddPrivateField(LookupIterator *it, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
Tagged< JSFunction > function() const override
Definition frames.cc:2492
static void CollectFunctionAndOffsetForICStats(Isolate *isolate, Tagged< JSFunction > function, Tagged< AbstractCode > code, int code_offset)
Definition frames.cc:2597
std::tuple< Tagged< AbstractCode >, int > GetActiveCodeAndOffset() const
Definition frames.cc:2453
static MaybeHandle< FixedArray > GetKeys(Isolate *isolate, DirectHandle< JSReceiver > object, KeyCollectionMode mode, PropertyFilter filter, GetKeysConversion keys_conversion=GetKeysConversion::kKeepNumbers, bool is_for_in=false, bool skip_indices=false)
Definition keys.cc:97
Handle< Object > LoadElementHandler(DirectHandle< Map > receiver_map, KeyedAccessLoadMode new_load_mode)
Definition ic.cc:1366
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > RuntimeLoad(DirectHandle< JSAny > object, DirectHandle< Object > key, bool *is_found=nullptr)
Definition ic.cc:1529
void LoadElementPolymorphicHandlers(MapHandles *receiver_maps, MaybeObjectHandles *handlers, KeyedAccessLoadMode new_load_mode)
Definition ic.cc:1425
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Load(Handle< JSAny > object, Handle< Object > key)
Definition ic.cc:1563
KeyedAccessLoadMode GetKeyedAccessLoadModeFor(DirectHandle< Map > receiver_map) const
Definition ic.cc:1143
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > LoadName(Handle< JSAny > object, DirectHandle< Object > key, Handle< Name > name)
Definition ic.cc:1547
void UpdateLoadElement(DirectHandle< HeapObject > receiver, KeyedAccessLoadMode new_load_mode)
Definition ic.cc:1162
KeyedAccessStoreMode GetKeyedAccessStoreMode()
Definition ic.h:312
Handle< Object > StoreElementHandler(DirectHandle< Map > receiver_map, KeyedAccessStoreMode store_mode, MaybeDirectHandle< UnionOf< Smi, Cell > > prev_validity_cell=kNullMaybeHandle)
Definition ic.cc:2377
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Store(Handle< JSAny > object, Handle< Object > name, DirectHandle< Object > value)
Definition ic.cc:2554
void UpdateStoreElement(Handle< Map > receiver_map, KeyedAccessStoreMode store_mode, Handle< Map > new_receiver_map)
Definition ic.cc:2237
void StoreElementPolymorphicHandlers(MapsAndHandlers *receiver_maps_and_handlers, KeyedAccessStoreMode store_mode)
Definition ic.cc:2453
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Load(Handle< Name > name, bool update_feedback=true)
Definition ic.cc:464
static Handle< Smi > LoadSlow(Isolate *isolate)
static DirectHandle< Smi > LoadAccessorFromPrototype(Isolate *isolate)
static Handle< Smi > LoadNativeDataProperty(Isolate *isolate, int descriptor)
static Handle< Smi > LoadConstantFromPrototype(Isolate *isolate)
static Handle< Smi > LoadProxy(Isolate *isolate)
static Handle< Smi > LoadNormal(Isolate *isolate)
static Handle< Smi > LoadField(Isolate *isolate, FieldIndex field_index)
static Handle< Smi > LoadNonExistent(Isolate *isolate)
static bool CanHandleHolderNotLookupStart(Tagged< Object > handler)
static Handle< Smi > LoadInterceptor(Isolate *isolate)
static KeyedAccessLoadMode GetKeyedAccessLoadMode(Tagged< MaybeObject > handler)
static Handle< Object > LoadFromPrototype(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< JSReceiver > holder, Tagged< Smi > smi_handler, MaybeObjectDirectHandle maybe_data1=MaybeObjectDirectHandle(), MaybeObjectDirectHandle maybe_data2=MaybeObjectDirectHandle())
static Handle< Smi > LoadModuleExport(Isolate *isolate, int index)
static Handle< Smi > LoadIndexedString(Isolate *isolate, KeyedAccessLoadMode load_mode)
static Handle< Smi > LoadApiGetter(Isolate *isolate)
static Handle< Smi > LoadElement(Isolate *isolate, ElementsKind elements_kind, bool is_js_array, KeyedAccessLoadMode load_mode)
static Handle< Smi > LoadGlobal(Isolate *isolate)
static Handle< Object > LoadFullChain(Isolate *isolate, DirectHandle< Map > receiver_map, const MaybeObjectDirectHandle &holder, Handle< Smi > smi_handler)
void UpdateCaches(LookupIterator *lookup)
Definition ic.cc:778
MaybeObjectHandle ComputeHandler(LookupIterator *lookup)
Definition ic.cc:846
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Load(Handle< JSAny > object, Handle< Name > name, bool update_feedback=true, DirectHandle< JSAny > receiver=DirectHandle< JSAny >())
Definition ic.cc:386
bool ShouldThrowReferenceError() const
Definition ic.h:196
PropertyDetails property_details() const
Definition lookup.h:229
int GetFieldDescriptorIndex() const
Definition lookup.cc:1029
bool TryLookupCachedProperty(DirectHandle< AccessorPair > accessor)
Definition lookup.cc:1443
FieldIndex GetFieldIndex() const
Definition lookup.cc:1046
DirectHandle< T > GetStoreTarget() const
Definition lookup-inl.h:395
DirectHandle< Object > GetAccessors() const
Definition lookup.cc:1064
DirectHandle< JSAny > GetReceiver() const
Definition lookup.h:188
DirectHandle< PropertyCell > transition_cell() const
Definition lookup-inl.h:277
DirectHandle< T > GetHolder() const
Definition lookup-inl.h:283
Handle< Object > GetDataValue(AllocationPolicy allocation_policy=AllocationPolicy::kAllocationAllowed) const
Definition lookup.cc:1069
DirectHandle< JSAny > lookup_start_object() const
Definition lookup.h:198
bool is_dictionary_holder() const
Definition lookup-inl.h:268
DirectHandle< Name > GetName()
Definition lookup-inl.h:246
bool HolderIsReceiverOrHiddenPrototype() const
Definition lookup.cc:915
DirectHandle< Name > name() const
Definition lookup-inl.h:241
Representation representation() const
Definition lookup.h:239
PropertyConstness constness() const
Definition lookup.h:243
DirectHandle< Map > transition_map() const
Definition lookup-inl.h:272
DirectHandle< PropertyCell > GetPropertyCell() const
Definition lookup.cc:1055
static Handle< UnionOf< Smi, Cell > > GetOrCreatePrototypeChainValidityCell(DirectHandle< Map > map, Isolate *isolate)
Definition map.cc:2419
static V8_EXPORT_PRIVATE MaybeHandle< Map > TryUpdate(Isolate *isolate, Handle< Map > map) V8_WARN_UNUSED_RESULT
Definition map.cc:751
static constexpr int kPrototypeChainValid
Definition map.h:517
void emplace_back(DirectHandle< Map > map, MaybeObjectDirectHandle handler)
base::Vector< DirectHandle< Map > > maps()
void set_handler(size_t i, MaybeObjectDirectHandle handler)
void reserve(size_t capacity)
void set_map(size_t i, DirectHandle< Map > map)
static MaybeObjectDirectHandle Weak(Tagged< Object > object, Isolate *isolate)
static MaybeObjectHandle Weak(Tagged< Object > object, Isolate *isolate)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > AddDataProperty(LookupIterator *it, DirectHandle< Object > value, PropertyAttributes attributes, Maybe< ShouldThrow > should_throw, StoreOrigin store_origin, EnforceDefineSemantics semantics=EnforceDefineSemantics::kSet)
Definition objects.cc:2667
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > SetProperty(LookupIterator *it, DirectHandle< Object > value, StoreOrigin store_origin, Maybe< ShouldThrow > should_throw=Nothing< ShouldThrow >())
Definition objects.cc:2439
static double NumberValue(Tagged< Number > obj)
static V8_EXPORT_PRIVATE bool ToInt32(Tagged< Object > obj, int32_t *value)
Definition objects.cc:1438
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > ConvertReceiver(Isolate *isolate, DirectHandle< Object > object)
Definition objects.cc:305
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
Definition objects.cc:1248
Maybe< InterceptorResult > GetBooleanReturnValue(v8::Intercepted intercepted, const char *callback_kind_for_error_message, bool ignore_return_value=false)
v8::Intercepted CallNamedSetter(DirectHandle< InterceptorInfo > interceptor, DirectHandle< Name > name, DirectHandle< Object > value)
void set_value(DirectHandle< JSAny > value)
void set_configurable(bool configurable)
PropertyLocation location() const
Tagged< T > GetCurrent() const
Definition prototype.h:52
V8_INLINE Tagged< Boolean > boolean_value(bool value) const
Definition roots-inl.h:119
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > HasProperty(Isolate *isolate, DirectHandle< Object > object, DirectHandle< Object > key)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetObjectProperty(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Object > key, DirectHandle< Object > value, MaybeDirectHandle< JSAny > receiver, StoreOrigin store_origin, Maybe< ShouldThrow > should_throw=Nothing< ShouldThrow >())
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetObjectProperty(Isolate *isolate, DirectHandle< JSAny > lookup_start_object, DirectHandle< Object > key, DirectHandle< JSAny > receiver={}, bool *is_found=nullptr)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > DefineObjectOwnProperty(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Object > key, DirectHandle< Object > value, StoreOrigin store_origin)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > zero()
Definition smi.h:99
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Store(Handle< Name > name, DirectHandle< Object > value)
Definition ic.cc:1695
static Handle< Smi > StoreNormal(Isolate *isolate)
static Handle< Object > StoreThroughPrototype(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< JSReceiver > holder, Tagged< Smi > smi_handler, MaybeObjectDirectHandle maybe_data1=MaybeObjectDirectHandle(), MaybeObjectDirectHandle maybe_data2=MaybeObjectDirectHandle())
static Handle< Smi > StoreSlow(Isolate *isolate, KeyedAccessStoreMode store_mode=KeyedAccessStoreMode::kInBounds)
static Handle< Smi > StoreSharedStructField(Isolate *isolate, int descriptor, FieldIndex field_index, Representation representation)
static Handle< Smi > StoreNativeDataProperty(Isolate *isolate, int descriptor)
static Handle< Smi > StoreField(Isolate *isolate, int descriptor, FieldIndex field_index, PropertyConstness constness, Representation representation)
static DirectHandle< Smi > StoreGlobalProxy(Isolate *isolate)
static Handle< Code > StoreFastElementBuiltin(Isolate *isolate, KeyedAccessStoreMode mode)
static DirectHandle< Smi > StoreApiSetter(Isolate *isolate)
static MaybeObjectHandle StoreGlobal(Handle< PropertyCell > cell)
static DirectHandle< Smi > StoreAccessorFromPrototype(Isolate *isolate)
static MaybeObjectHandle StoreTransition(Isolate *isolate, Handle< Map > transition_map)
static Handle< Smi > StoreInterceptor(Isolate *isolate)
static Handle< Code > StoreSloppyArgumentsBuiltin(Isolate *isolate, KeyedAccessStoreMode mode)
static MaybeObjectHandle StoreOwnTransition(Isolate *isolate, Handle< Map > transition_map)
static Handle< Object > StoreElementTransition(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< Map > transition, KeyedAccessStoreMode store_mode, MaybeDirectHandle< UnionOf< Smi, Cell > > prev_validity_cell=kNullMaybeHandle)
bool LookupForWrite(LookupIterator *it, DirectHandle< Object > value, StoreOrigin store_origin)
Definition ic.cc:1598
MaybeObjectHandle ComputeHandler(LookupIterator *lookup)
Definition ic.cc:1969
void UpdateCaches(LookupIterator *lookup, DirectHandle< Object > value, StoreOrigin store_origin)
Definition ic.cc:1943
V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Store(Handle< JSAny > object, Handle< Name > name, DirectHandle< Object > value, StoreOrigin store_origin=StoreOrigin::kNamed)
Definition ic.cc:1827
MaybeDirectHandle< Object > Store(DirectHandle< JSArray > array, Handle< Object > index, DirectHandle< Object > value)
Definition ic.cc:2708
void Set(Tagged< Name > name, Tagged< Map > map, Tagged< MaybeObject > handler)
Definition stub-cache.cc:89
bool GetHeapObject(Tagged< HeapObject > *result) const
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static void EnsureHasSideStepTransitions(Isolate *isolate, DirectHandle< Map > map)
Handle< Code > code
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL
Definition globals.h:249
const PropertyKind kind_
#define RUNTIME_FUNCTION(Name)
Definition arguments.h:162
#define RETURN_FAILURE_IF_EXCEPTION(isolate)
Definition isolate.h:205
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:284
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define RETURN_FAILURE(isolate, should_throw, call)
Definition isolate.h:398
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define RETURN_FAILURE_IF_EXCEPTION_DETECTOR(isolate, detector)
Definition isolate.h:213
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition isolate.h:294
#define MAYBE_RETURN_NULL(call)
Definition isolate.h:413
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
#define RETURN_RESULT_OR_FAILURE(isolate, call)
Definition isolate.h:264
#define MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:448
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Isolate * isolate
TNode< Object > target
TNode< Object > receiver
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
MovableLabel handler
#define LOG(isolate, Call)
Definition log.h:78
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
@ kEnumerationOrder
Definition globals.h:2859
@ kPropertyAdditionOrder
Definition globals.h:2861
bool IsStoreGlobalICKind(FeedbackSlotKind kind)
bool TryCast(Tagged< From > value, Tagged< To > *out)
Definition casting.h:77
bool StoreModeIsInBounds(KeyedAccessStoreMode store_mode)
Definition globals.h:2724
bool StoreModeCanGrow(KeyedAccessStoreMode store_mode)
Definition globals.h:2742
constexpr double kMaxSafeInteger
Definition globals.h:1985
static MaybeDirectHandle< JSObject > CloneObjectSlowPath(Isolate *isolate, DirectHandle< Object > source, int flags)
Definition ic.cc:3498
bool IsDefineNamedOwnICKind(FeedbackSlotKind kind)
bool IsNone(Tagged< FieldType > obj)
Definition field-type.h:50
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
constexpr bool IsHoleyElementsKind(ElementsKind kind)
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, ElementsKind to_kind)
bool IsNumber(Tagged< Object > obj)
bool IsSetNamedICKind(FeedbackSlotKind kind)
Tagged< DescriptorArray >
Definition map-inl.h:52
Tagged(T object) -> Tagged< T >
v8::MemorySpan< DirectHandle< Map > > MapHandlesSpan
Definition map.h:148
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
bool IsAnyNonextensibleElementsKind(ElementsKind kind)
bool IsLoadICKind(FeedbackSlotKind kind)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
bool IsImmutableLexicalVariableMode(VariableMode mode)
Definition globals.h:2145
bool IsHoleyElementsKindForRead(ElementsKind kind)
bool IsNullOrUndefined(Tagged< Object > obj, Isolate *isolate)
KeyedAccessLoadMode GeneralizeKeyedAccessLoadMode(KeyedAccessLoadMode mode1, KeyedAccessLoadMode mode2)
Definition globals.h:2682
static void LookupForRead(LookupIterator *it, bool is_has_property)
Definition ic.cc:195
bool IsSmiOrObjectElementsKind(ElementsKind kind)
ShouldThrow GetShouldThrow(Isolate *isolate, Maybe< ShouldThrow > should_throw)
Definition objects.cc:140
bool IsSloppyArgumentsElementsKind(ElementsKind kind)
bool AllowedHandlerChange(KeyedAccessLoadMode old_mode, KeyedAccessLoadMode new_mode)
Definition ic.cc:1152
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
bool IsBooleanMap(Tagged< Map > map)
Definition map-inl.h:745
bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind)
bool IsNullOrUndefinedMap(Tagged< Map > map)
Definition map-inl.h:749
typename detail::FlattenUnionHelper< Union<>, Ts... >::type UnionOf
Definition union.h:123
bool IsFastElementsKind(ElementsKind kind)
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsAny(Tagged< FieldType > obj)
Definition field-type.h:51
bool IsKeyedLoadICKind(FeedbackSlotKind kind)
V8_INLINE bool IsWasmObject(T obj, Isolate *=nullptr)
Definition objects.h:725
bool IsDefineKeyedOwnICKind(FeedbackSlotKind kind)
return value
Definition map-inl.h:893
bool IsLoadGlobalICKind(FeedbackSlotKind kind)
bool IsTypedArrayOrRabGsabTypedArrayElementsKind(ElementsKind kind)
bool LoadModeHandlesHoles(KeyedAccessLoadMode load_mode)
Definition globals.h:2695
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
@ kStartAtPrototype
Definition globals.h:1714
std::vector< MaybeObjectHandle > MaybeObjectHandles
bool IsKeyedStoreICKind(FeedbackSlotKind kind)
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
Intercepted
#define TRACE_HANDLER_STATS(...)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
std::string state
Definition ic-stats.h:43
unsigned number_of_own_descriptors
Definition ic-stats.h:49
std::string type
Definition ic-stats.h:35
std::string instance_type
Definition ic-stats.h:50
static constexpr Tagged< Smi > Empty
Definition transitions.h:40
static constexpr Tagged< Smi > Unreachable
Definition transitions.h:41
static bool is_ic_stats_enabled()
static V8_EXPORT_PRIVATE std::atomic_uint ic_stats
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
wasm::ValueType type