v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
access-info.cc
Go to the documentation of this file.
1
2// Copyright 2015 the V8 project authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
7
8#include <optional>
9#include <ostream>
10
27
28namespace v8 {
29namespace internal {
30namespace compiler {
31
32namespace {
33
34bool CanInlinePropertyAccess(MapRef map, AccessMode access_mode) {
35 // We can inline property access to prototypes of all primitives, except
36 // the special Oddball ones that have no wrapper counterparts (i.e. Null,
37 // Undefined and TheHole).
38 // We can only inline accesses to dictionary mode holders if the access is a
39 // load and the holder is a prototype. The latter ensures a 1:1
40 // relationship between the map and the object (and therefore the property
41 // dictionary).
42 static_assert(ODDBALL_TYPE == LAST_PRIMITIVE_HEAP_OBJECT_TYPE);
43 if (IsBooleanMap(*map.object())) return true;
44 if (map.instance_type() < LAST_PRIMITIVE_HEAP_OBJECT_TYPE) return true;
45 if (IsJSObjectMap(*map.object())) {
46 if (map.is_dictionary_map()) {
47 if (!V8_DICT_PROPERTY_CONST_TRACKING_BOOL) return false;
48 return access_mode == AccessMode::kLoad &&
49 map.object()->is_prototype_map();
50 }
51 return !map.object()->has_named_interceptor() &&
52 // TODO(verwaest): Allowlist contexts to which we have access.
53 !map.is_access_check_needed();
54 }
55 return false;
56}
57
58#ifdef DEBUG
59bool HasFieldRepresentationDependenciesOnMap(
60 ZoneVector<CompilationDependency const*>& dependencies,
61 Handle<Map> const& field_owner_map) {
62 for (auto dep : dependencies) {
63 if (CompilationDependencies::IsFieldRepresentationDependencyOnMap(
64 dep, field_owner_map)) {
65 return true;
66 }
67 }
68 return false;
69}
70#endif
71
72} // namespace
73
74std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
75 switch (access_mode) {
77 return os << "Load";
79 return os << "Store";
81 return os << "StoreInLiteral";
83 return os << "Has";
85 return os << "Define";
86 }
88}
89
91 ZoneVector<MapRef>&& lookup_start_object_maps, ElementsKind elements_kind,
92 Zone* zone)
93 : elements_kind_(elements_kind),
94 lookup_start_object_maps_(lookup_start_object_maps),
95 transition_sources_(zone) {
97}
98
99// static
103
104// static
106 OptionalJSObjectRef holder) {
107 return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone});
108}
109
110// static
112 JSHeapBroker* broker, Zone* zone, MapRef receiver_map,
114 FieldIndex field_index, Representation field_representation,
115 Type field_type, MapRef field_owner_map, OptionalMapRef field_map,
116 OptionalJSObjectRef holder, OptionalMapRef transition_map) {
120 HasFieldRepresentationDependenciesOnMap(
121 dependencies, transition_map.has_value() ? transition_map->object()
122 : holder.has_value() ? holder->map(broker).object()
123 : receiver_map.object()));
125 field_representation, field_type, field_owner_map,
126 field_map, {{receiver_map}, zone},
127 std::move(dependencies));
128}
129
130// static
132 Zone* zone, MapRef receiver_map,
134 FieldIndex field_index, Representation field_representation,
135 Type field_type, MapRef field_owner_map, OptionalMapRef field_map,
136 OptionalJSObjectRef holder, OptionalMapRef transition_map) {
140 field_owner_map, field_map, {{receiver_map}, zone},
141 std::move(dependencies));
142}
143
144// static
146 Zone* zone, MapRef receiver_map, OptionalJSObjectRef holder,
147 OptionalObjectRef constant, OptionalJSObjectRef api_holder) {
148 return PropertyAccessInfo(zone, kFastAccessorConstant, holder, constant,
149 api_holder, {} /* name */, {{receiver_map}, zone});
150}
151
152// static
154 MapRef receiver_map,
155 CellRef cell) {
156 return PropertyAccessInfo(zone, kModuleExport, {} /* holder */,
157 cell /* constant */, {} /* api_holder */,
158 {} /* name */, {{receiver_map}, zone});
159}
160
161// static
163 MapRef receiver_map) {
164 return PropertyAccessInfo(zone, kStringLength, {}, {{receiver_map}, zone});
165}
166
167// static
169 Zone* zone, MapRef receiver_map) {
171 {{receiver_map}, zone});
172}
173
174// static
176 MapRef receiver_map) {
178 {{receiver_map}, zone});
179 result.set_elements_kind(receiver_map.elements_kind());
180 return result;
181}
182
183// static
185 Zone* zone, MapRef receiver_map, JSObjectRef holder,
186 InternalIndex dictionary_index, NameRef name) {
188 {{receiver_map}, zone}, dictionary_index, name);
189}
190
191// static
193 Zone* zone, MapRef receiver_map, OptionalJSObjectRef holder,
194 ObjectRef constant, OptionalJSObjectRef api_holder, NameRef property_name) {
196 constant, api_holder, property_name,
197 {{receiver_map}, zone});
198}
199
201 : kind_(kInvalid),
202 lookup_start_object_maps_(zone),
203 unrecorded_dependencies_(zone),
204 field_representation_(Representation::None()),
205 field_type_(Type::None()),
206 dictionary_index_(InternalIndex::NotFound()) {}
207
209 Zone* zone, Kind kind, OptionalJSObjectRef holder,
210 ZoneVector<MapRef>&& lookup_start_object_maps)
211 : kind_(kind),
212 lookup_start_object_maps_(lookup_start_object_maps),
213 holder_(holder),
214 unrecorded_dependencies_(zone),
215 field_representation_(Representation::None()),
216 field_type_(Type::None()),
217 dictionary_index_(InternalIndex::NotFound()) {}
218
220 Zone* zone, Kind kind, OptionalJSObjectRef holder,
221 OptionalObjectRef constant, OptionalJSObjectRef api_holder,
222 OptionalNameRef name, ZoneVector<MapRef>&& lookup_start_object_maps)
223 : kind_(kind),
224 lookup_start_object_maps_(lookup_start_object_maps),
225 constant_(constant),
226 holder_(holder),
227 api_holder_(api_holder),
228 unrecorded_dependencies_(zone),
229 field_representation_(Representation::None()),
230 field_type_(Type::Any()),
231 dictionary_index_(InternalIndex::NotFound()),
232 name_(name) {
234}
235
237 Kind kind, OptionalJSObjectRef holder, OptionalMapRef transition_map,
238 FieldIndex field_index, Representation field_representation,
239 Type field_type, MapRef field_owner_map, OptionalMapRef field_map,
240 ZoneVector<MapRef>&& lookup_start_object_maps,
241 ZoneVector<CompilationDependency const*>&& unrecorded_dependencies)
242 : kind_(kind),
243 lookup_start_object_maps_(lookup_start_object_maps),
244 holder_(holder),
245 unrecorded_dependencies_(std::move(unrecorded_dependencies)),
246 transition_map_(transition_map),
247 field_index_(field_index),
248 field_representation_(field_representation),
249 field_type_(field_type),
250 field_owner_map_(field_owner_map),
251 field_map_(field_map),
252 dictionary_index_(InternalIndex::NotFound()) {
253 DCHECK_IMPLIES(transition_map.has_value(),
254 field_owner_map.equals(transition_map.value()));
255}
256
258 Zone* zone, Kind kind, OptionalJSObjectRef holder,
259 ZoneVector<MapRef>&& lookup_start_object_maps,
260 InternalIndex dictionary_index, NameRef name)
261 : kind_(kind),
262 lookup_start_object_maps_(lookup_start_object_maps),
263 holder_(holder),
264 unrecorded_dependencies_(zone),
265 field_representation_(Representation::None()),
266 field_type_(Type::Any()),
267 dictionary_index_(dictionary_index),
268 name_{name} {}
269
270namespace {
271
272template <class RefT>
273bool OptionalRefEquals(OptionalRef<RefT> lhs, OptionalRef<RefT> rhs) {
274 if (!lhs.has_value()) return !rhs.has_value();
275 if (!rhs.has_value()) return false;
276 return lhs->equals(rhs.value());
277}
278
279template <class T>
280void AppendVector(ZoneVector<T>* dst, const ZoneVector<T>& src) {
281 dst->insert(dst->end(), src.begin(), src.end());
282}
283
284} // namespace
285
287 AccessMode access_mode, Zone* zone) {
288 if (kind_ != that->kind_) return false;
289 if (!OptionalRefEquals(holder_, that->holder_)) return false;
290
291 switch (kind_) {
292 case kInvalid:
293 DCHECK_EQ(that->kind_, kInvalid);
294 return true;
295
296 case kDataField:
297 case kFastDataConstant: {
298 // Check if we actually access the same field (we use the
299 // GetFieldAccessStubKey method here just like the ICs do
300 // since that way we only compare the relevant bits of the
301 // field indices).
303 that->field_index_.GetFieldAccessStubKey()) {
304 return false;
305 }
306
307 switch (access_mode) {
308 case AccessMode::kHas:
309 case AccessMode::kLoad: {
310 if (!field_representation_.Equals(that->field_representation_)) {
312 that->field_representation_.IsDouble()) {
313 return false;
314 }
316 }
317 if (!OptionalRefEquals(field_map_, that->field_map_)) {
318 field_map_ = {};
319 }
320 break;
321 }
324 case AccessMode::kDefine: {
325 // For stores, the field map and field representation information
326 // must match exactly, otherwise we cannot merge the stores. We
327 // also need to make sure that in case of transitioning stores,
328 // the transition targets match.
329 if (!OptionalRefEquals(field_map_, that->field_map_) ||
330 !field_representation_.Equals(that->field_representation_) ||
331 !OptionalRefEquals(transition_map_, that->transition_map_)) {
332 return false;
333 }
334 break;
335 }
336 }
337
338 field_type_ = Type::Union(field_type_, that->field_type_, zone);
339 AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_);
340 AppendVector(&unrecorded_dependencies_, that->unrecorded_dependencies_);
341 return true;
342 }
343
346 // Check if we actually access the same constant.
347 if (!OptionalRefEquals(constant_, that->constant_)) return false;
348
350 DCHECK(that->unrecorded_dependencies_.empty());
351 AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_);
352 return true;
353 }
354
356 DCHECK_EQ(AccessMode::kLoad, access_mode);
357 if (dictionary_index_ != that->dictionary_index_) return false;
358 AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_);
359 return true;
360 }
361
362 case kNotFound:
363 case kStringLength:
366 DCHECK(that->unrecorded_dependencies_.empty());
367 AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_);
368 return true;
369 }
372 DCHECK_EQ(that->lookup_start_object_maps_.size(), 1);
373 return lookup_start_object_maps_[0] == that->lookup_start_object_maps_[0];
374 case kModuleExport:
375 return false;
376 }
377}
378
383
386
387std::optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
388 MapRef map, AccessMode access_mode) const {
389 if (!map.CanInlineElementAccess()) return {};
390 return ElementAccessInfo({{map}, zone()}, map.elements_kind(), zone());
391}
392
394 ElementAccessFeedback const& feedback,
395 ZoneVector<ElementAccessInfo>* access_infos) const {
396 AccessMode access_mode = feedback.keyed_mode().access_mode();
397 if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
398 // For polymorphic loads of similar elements kinds (i.e. all tagged or all
399 // double), always use the "worst case" code without a transition. This is
400 // much faster than transitioning the elements to the worst case, trading a
401 // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
402 std::optional<ElementAccessInfo> access_info =
403 ConsolidateElementLoad(feedback);
404 if (access_info.has_value()) {
405 access_infos->push_back(*access_info);
406 return true;
407 }
408 }
409
410 for (auto const& group : feedback.transition_groups()) {
411 DCHECK(!group.empty());
412 OptionalMapRef target = group.front();
413 std::optional<ElementAccessInfo> access_info =
414 ComputeElementAccessInfo(target.value(), access_mode);
415 if (!access_info.has_value()) return false;
416
417 for (size_t i = 1; i < group.size(); ++i) {
418 OptionalMapRef map_ref = group[i];
419 if (!map_ref.has_value()) continue;
420 access_info->AddTransitionSource(map_ref.value());
421 }
422 access_infos->push_back(*access_info);
423 }
424 return true;
425}
426
428 MapRef receiver_map, MapRef map, NameRef name, OptionalJSObjectRef holder,
429 InternalIndex descriptor, AccessMode access_mode) const {
430 DCHECK(descriptor.is_found());
431 // TODO(jgruber,v8:7790): Use DescriptorArrayRef instead.
433 map.instance_descriptors(broker()).object();
434 PropertyDetails const details = descriptors->GetDetails(descriptor);
435 int index = descriptors->GetFieldIndex(descriptor);
436 Representation details_representation = details.representation();
437 if (details_representation.IsNone()) {
438 // The ICs collect feedback in PREMONOMORPHIC state already,
439 // but at this point the {receiver_map} might still contain
440 // fields for which the representation has not yet been
441 // determined by the runtime. So we need to catch this case
442 // here and fall back to use the regular IC logic instead.
443 return Invalid();
444 }
445 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map.object(), index,
446 details_representation);
447 // Private brands are used when loading private methods, which are stored in a
448 // BlockContext, an internal object.
449 Type field_type = name.object()->IsPrivateBrand() ? Type::OtherInternal()
450 : Type::NonInternal();
451 OptionalMapRef field_map;
452
453 ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone());
454
455 Handle<FieldType> descriptors_field_type =
457 descriptors->GetFieldType(descriptor));
458 OptionalObjectRef descriptors_field_type_ref =
459 TryMakeRef<Object>(broker(), descriptors_field_type);
460 if (!descriptors_field_type_ref.has_value()) return Invalid();
461
462 // Note: FindFieldOwner may be called multiple times throughout one
463 // compilation. This is safe since its result is fixed for a given map and
464 // descriptor.
465 MapRef field_owner_map = map.FindFieldOwner(broker(), descriptor);
466
467 if (details_representation.IsSmi()) {
468 field_type = Type::SignedSmall();
469 unrecorded_dependencies.push_back(
470 dependencies()->FieldRepresentationDependencyOffTheRecord(
471 map, field_owner_map, descriptor, details_representation));
472 } else if (details_representation.IsDouble()) {
473 field_type = type_cache_->kFloat64;
474 unrecorded_dependencies.push_back(
475 dependencies()->FieldRepresentationDependencyOffTheRecord(
476 map, field_owner_map, descriptor, details_representation));
477 } else if (details_representation.IsHeapObject()) {
478 if (IsNone(*descriptors_field_type)) {
479 // Cleared field-types are pre-monomorphic states. The field type was
480 // garbge collected and we need to record an updated type.
482 switch (access_mode) {
486 return Invalid();
488 case AccessMode::kHas:
489 break;
490 }
491 }
492 unrecorded_dependencies.push_back(
493 dependencies()->FieldRepresentationDependencyOffTheRecord(
494 map, field_owner_map, descriptor, details_representation));
495 if (IsClass(*descriptors_field_type)) {
496 // Remember the field map, and try to infer a useful type.
497 OptionalMapRef maybe_field_map =
498 TryMakeRef(broker(), FieldType::AsClass(*descriptors_field_type));
499 if (!maybe_field_map.has_value()) return Invalid();
500 field_map = maybe_field_map;
501 // field_type can only be inferred from field_map if it is stable and we
502 // add a stability dependency. This happens on use in the access builder.
503 }
504 } else {
505 CHECK(details_representation.IsTagged());
506 }
507 // TODO(turbofan): We may want to do this only depending on the use
508 // of the access info.
509 unrecorded_dependencies.push_back(
510 dependencies()->FieldTypeDependencyOffTheRecord(
511 map, field_owner_map, descriptor,
512 descriptors_field_type_ref.value()));
513
514 PropertyConstness constness =
515 map.GetPropertyDetails(broker_, descriptor).constness();
516 switch (constness) {
519 broker(), zone(), receiver_map, std::move(unrecorded_dependencies),
520 field_index, details_representation, field_type, field_owner_map,
521 field_map, holder, {});
524 map, field_owner_map, descriptor);
525 unrecorded_dependencies.push_back(constness_dep);
527 zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
528 details_representation, field_type, field_owner_map, field_map,
529 holder, {});
530 }
531 UNREACHABLE();
532}
533
534namespace {
535
536using AccessorsObjectGetter = std::function<Handle<Object>()>;
537
538PropertyAccessInfo AccessorAccessInfoHelper(
539 Isolate* isolate, Zone* zone, JSHeapBroker* broker,
540 const AccessInfoFactory* ai_factory, MapRef receiver_map, NameRef name,
541 MapRef holder_map, OptionalJSObjectRef holder, AccessMode access_mode,
542 AccessorsObjectGetter get_accessors) {
543 if (holder_map.instance_type() == JS_MODULE_NAMESPACE_TYPE) {
544 DCHECK(holder_map.object()->is_prototype_map());
546 Cast<PrototypeInfo>(holder_map.object()->prototype_info()));
547 DirectHandle<JSModuleNamespace> module_namespace =
549 Cast<JSModuleNamespace>(proto_info->module_namespace()));
551 Cast<Cell>(module_namespace->module()->exports()->Lookup(
552 isolate, name.object(),
553 Smi::ToInt(Object::GetHash(*name.object())))));
554 if (IsAnyStore(access_mode)) {
555 // ES#sec-module-namespace-exotic-objects-set-p-v-receiver
556 // ES#sec-module-namespace-exotic-objects-defineownproperty-p-desc
557 //
558 // Storing to a module namespace object is always an error or a no-op in
559 // JS.
560 return PropertyAccessInfo::Invalid(zone);
561 }
562 if (IsTheHole(cell->value(kRelaxedLoad), isolate)) {
563 // This module has not been fully initialized yet.
564 return PropertyAccessInfo::Invalid(zone);
565 }
566 OptionalCellRef cell_ref = TryMakeRef(broker, cell);
567 if (!cell_ref.has_value()) {
568 return PropertyAccessInfo::Invalid(zone);
569 }
570 return PropertyAccessInfo::ModuleExport(zone, receiver_map,
571 cell_ref.value());
572 }
573 if (access_mode == AccessMode::kHas) {
574 // kHas is not supported for dictionary mode objects.
575 DCHECK(!holder_map.is_dictionary_map());
576
577 // HasProperty checks don't call getter/setters, existence is sufficient.
578 return PropertyAccessInfo::FastAccessorConstant(zone, receiver_map, holder,
579 {}, {});
580 }
581 DirectHandle<Object> maybe_accessors = get_accessors();
582 if (!IsAccessorPair(*maybe_accessors)) {
583 return PropertyAccessInfo::Invalid(zone);
584 }
585 DirectHandle<AccessorPair> accessors = Cast<AccessorPair>(maybe_accessors);
586 Handle<Object> accessor = broker->CanonicalPersistentHandle(
587 access_mode == AccessMode::kLoad ? accessors->getter(kAcquireLoad)
588 : accessors->setter(kAcquireLoad));
589
590 OptionalObjectRef accessor_ref = TryMakeRef(broker, accessor);
591 if (!accessor_ref.has_value()) return PropertyAccessInfo::Invalid(zone);
592
593 OptionalJSObjectRef api_holder_ref;
594 if (!IsJSFunction(*accessor)) {
595 CallOptimization optimization(broker->local_isolate_or_isolate(), accessor);
596 if (!optimization.is_simple_api_call() ||
597 optimization.IsCrossContextLazyAccessorPair(
598 *broker->target_native_context().object(), *holder_map.object())) {
599 return PropertyAccessInfo::Invalid(zone);
600 }
601 if (DEBUG_BOOL && holder.has_value()) {
602 std::optional<Tagged<NativeContext>> holder_creation_context =
603 holder->object()->GetCreationContext();
604 CHECK(holder_creation_context.has_value());
606 holder_creation_context.value());
607 }
608
609 CallOptimization::HolderLookup holder_lookup;
611 optimization.LookupHolderOfExpectedType(
612 broker->local_isolate_or_isolate(), receiver_map.object(),
613 &holder_lookup));
614 if (holder_lookup == CallOptimization::kHolderNotFound) {
615 return PropertyAccessInfo::Invalid(zone);
616 }
618 api_holder.is_null());
620 !api_holder.is_null());
621
622 if (!api_holder.is_null()) {
623 api_holder_ref = TryMakeRef(broker, api_holder);
624 if (!api_holder_ref.has_value()) return PropertyAccessInfo::Invalid(zone);
625 }
626 }
627 if (access_mode == AccessMode::kLoad) {
628 std::optional<Tagged<Name>> cached_property_name =
630 if (cached_property_name.has_value()) {
631 OptionalNameRef cached_property_name_ref =
632 TryMakeRef(broker, cached_property_name.value());
633 if (cached_property_name_ref.has_value()) {
634 PropertyAccessInfo access_info = ai_factory->ComputePropertyAccessInfo(
635 holder_map, cached_property_name_ref.value(), access_mode);
636 if (!access_info.IsInvalid()) return access_info;
637 }
638 }
639 }
640
641 if (holder_map.is_dictionary_map()) {
642 CHECK(!api_holder_ref.has_value());
644 zone, receiver_map, holder, accessor_ref.value(), api_holder_ref, name);
645 } else {
647 zone, receiver_map, holder, accessor_ref.value(), api_holder_ref);
648 }
649}
650
651} // namespace
652
654 MapRef receiver_map, NameRef name, MapRef holder_map,
655 OptionalJSObjectRef holder, InternalIndex descriptor,
656 AccessMode access_mode) const {
657 DCHECK(descriptor.is_found());
659 holder_map.object()->instance_descriptors(kRelaxedLoad));
660 SLOW_DCHECK(descriptor ==
661 descriptors->Search(*name.object(), *holder_map.object(), true));
662
663 auto get_accessors = [&]() {
665 descriptors->GetStrongValue(descriptor));
666 };
667 return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
668 receiver_map, name, holder_map, holder,
669 access_mode, get_accessors);
670}
671
673 MapRef receiver_map, NameRef name, JSObjectRef holder,
674 InternalIndex dictionary_index, AccessMode access_mode,
675 PropertyDetails details) const {
677 DCHECK(holder.map(broker()).object()->is_prototype_map());
678 DCHECK_EQ(access_mode, AccessMode::kLoad);
679
680 // We can only inline accesses to constant properties.
681 if (details.constness() != PropertyConstness::kConst) {
682 return Invalid();
683 }
684
685 if (details.kind() == PropertyKind::kData) {
687 zone(), receiver_map, holder, dictionary_index, name);
688 }
689
690 auto get_accessors = [&]() {
692 dictionary_index);
693 };
694 return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
695 receiver_map, name, holder.map(broker()),
696 holder, access_mode, get_accessors);
697}
698
700 MapRef map, OptionalJSObjectRef maybe_holder, NameRef name,
701 InternalIndex* index_out, PropertyDetails* details_out) const {
702 if (map.is_dictionary_map()) {
704 DCHECK(map.object()->is_prototype_map());
705
707
708 if (!maybe_holder.has_value()) {
709 // TODO(v8:11457) In this situation, we have a dictionary mode prototype
710 // as a receiver. Consider other means of obtaining the holder in this
711 // situation.
712
713 // Without the holder, we can't get the property details.
714 return false;
715 }
716
717 DirectHandle<JSObject> holder = maybe_holder->object();
719 Tagged<SwissNameDictionary> dict = holder->property_dictionary_swiss();
720 *index_out = dict->FindEntry(isolate(), name.object());
721 if (index_out->is_found()) {
722 *details_out = dict->DetailsAt(*index_out);
723 }
724 } else {
725 Tagged<NameDictionary> dict = holder->property_dictionary();
726 *index_out = dict->FindEntry(isolate(), name.object());
727 if (index_out->is_found()) {
728 *details_out = dict->DetailsAt(*index_out);
729 }
730 }
731 } else {
732 Tagged<DescriptorArray> descriptors =
733 *map.instance_descriptors(broker()).object();
734 *index_out = descriptors->Search(*name.object(), *map.object(), true);
735 if (index_out->is_found()) {
736 *details_out = descriptors->GetDetails(*index_out);
737 }
738 }
739
740 return true;
741}
742
744 MapRef map, NameRef name, AccessMode access_mode) const {
745 CHECK(name.IsUniqueName());
746
747 // Dictionary property const tracking is unsupported with concurrent inlining.
749
751
752 if (access_mode == AccessMode::kHas && !IsJSReceiverMap(*map.object())) {
753 return Invalid();
754 }
755
756 // Check if it is safe to inline property access for the {map}.
757 if (!CanInlinePropertyAccess(map, access_mode)) {
758 return Invalid();
759 }
760
761 // We support fast inline cases for certain JSObject getters.
762 if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
763 PropertyAccessInfo access_info = LookupSpecialFieldAccessor(map, name);
764 if (!access_info.IsInvalid()) return access_info;
765 }
766
767 // Only relevant if V8_DICT_PROPERTY_CONST_TRACKING enabled.
768 bool dictionary_prototype_on_chain = false;
769 bool fast_mode_prototype_on_chain = false;
770
771 // Remember the receiver map. We use {map} as loop variable.
772 MapRef receiver_map = map;
773 OptionalJSObjectRef holder;
774
775 // Perform the implicit ToObject for primitives here.
776 // Implemented according to ES6 section 7.3.2 GetV (V, P).
777 // Note: Keep sync'd with
778 // CompilationDependencies::DependOnStablePrototypeChains.
779 if (receiver_map.IsPrimitiveMap()) {
780 OptionalJSFunctionRef constructor =
782 receiver_map);
783 if (!constructor.has_value()) return Invalid();
784 map = constructor->initial_map(broker());
785 DCHECK(!map.IsPrimitiveMap());
786 }
787
788 while (true) {
791 if (!TryLoadPropertyDetails(map, holder, name, &index, &details)) {
792 return Invalid();
793 }
794
795 if (index.is_found()) {
796 if (IsAnyStore(access_mode)) {
797 DCHECK(!map.is_dictionary_map());
798
799 // Don't bother optimizing stores to read-only properties.
800 if (details.IsReadOnly()) return Invalid();
801
802 if (details.kind() == PropertyKind::kData && holder.has_value()) {
803 // This is a store to a property not found on the receiver but on a
804 // prototype. According to ES6 section 9.1.9 [[Set]], we need to
805 // create a new data property on the receiver. We can still optimize
806 // if such a transition already exists.
807 return LookupTransition(receiver_map, name, holder, NONE);
808 }
809 }
810
811 if (IsDefiningStore(access_mode)) {
812 if (details.attributes() != PropertyAttributes::NONE) {
813 // We should store the property with WEC attributes, but that's not
814 // the attributes of the property that we found. We just bail out and
815 // let the runtime figure out what to do (which probably requires
816 // changing the object's map).
817 return Invalid();
818 }
819 }
820
821 if (map.is_dictionary_map()) {
823
824 if (fast_mode_prototype_on_chain) {
825 // TODO(v8:11248) While the work on dictionary mode prototypes is in
826 // progress, we may still see fast mode objects on the chain prior to
827 // reaching a dictionary mode prototype holding the property . Due to
828 // this only being an intermediate state, we don't stupport these kind
829 // of heterogenous prototype chains.
830 return Invalid();
831 }
832
833 // TryLoadPropertyDetails only succeeds if we know the holder.
835 receiver_map, name, holder.value(), index, access_mode, details);
836 }
837
838 if (dictionary_prototype_on_chain) {
839 // If V8_DICT_PROPERTY_CONST_TRACKING_BOOL was disabled, then a
840 // dictionary prototype would have caused a bailout earlier.
842
843 // TODO(v8:11248) We have a fast mode holder, but there was a dictionary
844 // mode prototype earlier on the chain. Note that seeing a fast mode
845 // prototype even though V8_DICT_PROPERTY_CONST_TRACKING is enabled
846 // should only be possible while the implementation of dictionary mode
847 // prototypes is work in progress. Eventually, enabling
848 // V8_DICT_PROPERTY_CONST_TRACKING will guarantee that all prototypes
849 // are always in dictionary mode, making this case unreachable. However,
850 // due to the complications of checking dictionary mode prototypes for
851 // modification, we don't attempt to support dictionary mode prototypes
852 // occuring before a fast mode holder on the chain.
853 return Invalid();
854 }
855 if (details.location() == PropertyLocation::kField) {
856 if (details.kind() == PropertyKind::kData) {
857 return ComputeDataFieldAccessInfo(receiver_map, map, name, holder,
858 index, access_mode);
859 } else {
861 // TODO(turbofan): Add support for general accessors?
862 return Invalid();
863 }
864 } else {
867 return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map,
868 holder, index, access_mode);
869 }
870
871 UNREACHABLE();
872 }
873
874 // The property wasn't found on {map}. Look on the prototype if appropriate.
875 DCHECK(!index.is_found());
876
877 // Don't search on the prototype chain for special indices in case of
878 // integer indexed exotic objects (see ES6 section 9.4.5).
879 if (IsJSTypedArrayMap(*map.object()) && name.IsString()) {
880 StringRef name_str = name.AsString();
882 *name_str.object(), broker()->local_isolate_or_isolate());
883 if (IsSpecialIndex(*name_str.object(), access_guard)) return Invalid();
884 }
885
886 // Don't search on the prototype when storing in literals, or performing a
887 // Define operation
888 if (access_mode == AccessMode::kStoreInLiteral ||
889 access_mode == AccessMode::kDefine) {
890 PropertyAttributes attrs = NONE;
891 if (name.object()->IsPrivate()) {
892 // When PrivateNames are added to an object, they are by definition
893 // non-enumerable.
894 attrs = DONT_ENUM;
895 }
896 return LookupTransition(receiver_map, name, holder, attrs);
897 }
898
899 // Don't lookup private symbols on the prototype chain.
900 if (name.object()->IsPrivate()) {
901 return Invalid();
902 }
903
904 if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && holder.has_value()) {
905 // At this point, we are past the first loop iteration.
906 DCHECK(holder->object()->map()->is_prototype_map());
907 DCHECK(!holder->map(broker()).equals(receiver_map));
908
909 fast_mode_prototype_on_chain =
910 fast_mode_prototype_on_chain || !map.is_dictionary_map();
911 dictionary_prototype_on_chain =
912 dictionary_prototype_on_chain || map.is_dictionary_map();
913 }
914
915 // Walk up the prototype chain.
916 // Load the map's prototype's map to guarantee that every time we use it,
917 // we use the same Map.
918 HeapObjectRef prototype = map.prototype(broker());
919
920 MapRef map_prototype_map = prototype.map(broker());
921 if (!IsJSObjectMap(*map_prototype_map.object())) {
922 // Don't allow proxies on the prototype chain.
923 if (!prototype.IsNull()) {
924 DCHECK(IsJSProxy(*prototype.object()) ||
925 IsWasmObject(*prototype.object()));
926 return Invalid();
927 }
928
929 DCHECK(prototype.IsNull());
930
931 if (dictionary_prototype_on_chain) {
932 // TODO(v8:11248) See earlier comment about
933 // dictionary_prototype_on_chain. We don't support absent properties
934 // with dictionary mode prototypes on the chain, either. This is again
935 // just due to how we currently deal with dependencies for dictionary
936 // properties during finalization.
937 return Invalid();
938 }
939
940 // Store to property not found on the receiver or any prototype, we need
941 // to transition to a new data property.
942 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
943 if (access_mode == AccessMode::kStore) {
944 return LookupTransition(receiver_map, name, holder, NONE);
945 }
946
947 // The property was not found (access returns undefined or throws
948 // depending on the language mode of the load operation.
949 // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
950 return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
951 }
952
953 CHECK(prototype.IsJSObject());
954 holder = prototype.AsJSObject();
955 map = map_prototype_map;
956
957 if (!CanInlinePropertyAccess(map, access_mode)) {
958 return Invalid();
959 }
960
961 // Successful lookup on prototype chain needs to guarantee that all the
962 // prototypes up to the holder have stable maps, except for dictionary-mode
963 // prototypes. We currently do this by taking a
964 // DependOnStablePrototypeChains dependency in the caller.
965 //
966 // TODO(jgruber): This is brittle and easy to miss. Consider a refactor
967 // that moves the responsibility of taking the dependency into
968 // AccessInfoFactory.
969 }
970 UNREACHABLE();
971}
972
974 ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode) const {
975 ZoneVector<PropertyAccessInfo> merged_access_infos(zone());
976 MergePropertyAccessInfos(access_infos, access_mode, &merged_access_infos);
977 if (merged_access_infos.size() == 1) {
978 PropertyAccessInfo& result = merged_access_infos.front();
979 if (!result.IsInvalid()) {
980 result.RecordDependencies(dependencies());
981 return result;
982 }
983 }
984 return Invalid();
985}
986
988 CompilationDependencies* dependencies) {
990 dependencies->RecordDependency(d);
991 }
993}
994
996 ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode,
998 if (access_infos.empty()) return false;
999 MergePropertyAccessInfos(access_infos, access_mode, result);
1000 for (PropertyAccessInfo const& info : *result) {
1001 if (info.IsInvalid()) return false;
1002 }
1003 for (PropertyAccessInfo& info : *result) {
1004 info.RecordDependencies(dependencies());
1005 }
1006 return true;
1007}
1008
1010 ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
1012 DCHECK(result->empty());
1013 for (auto it = infos.begin(), end = infos.end(); it != end; ++it) {
1014 bool merged = false;
1015 for (auto ot = it + 1; ot != end; ++ot) {
1016 if (ot->Merge(&(*it), access_mode, zone())) {
1017 merged = true;
1018 break;
1019 }
1020 }
1021 if (!merged) result->push_back(*it);
1022 }
1023 CHECK(!result->empty());
1024}
1025
1030
1031namespace {
1032
1033Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
1034 ElementsKind that_kind) {
1035 if (IsHoleyElementsKind(this_kind)) {
1036 that_kind = GetHoleyElementsKind(that_kind);
1037 } else if (IsHoleyElementsKind(that_kind)) {
1038 this_kind = GetHoleyElementsKind(this_kind);
1039 }
1040 if (this_kind == that_kind) return Just(this_kind);
1041 if (IsDoubleElementsKind(that_kind) == IsDoubleElementsKind(this_kind)) {
1042 if (IsMoreGeneralElementsKindTransition(that_kind, this_kind)) {
1043 return Just(this_kind);
1044 }
1045 if (IsMoreGeneralElementsKindTransition(this_kind, that_kind)) {
1046 return Just(that_kind);
1047 }
1048 }
1049 return Nothing<ElementsKind>();
1050}
1051
1052} // namespace
1053
1054std::optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
1055 ElementAccessFeedback const& feedback) const {
1056 if (feedback.transition_groups().empty()) return {};
1057
1058 DCHECK(!feedback.transition_groups().front().empty());
1059 MapRef first_map = feedback.transition_groups().front().front();
1060 InstanceType instance_type = first_map.instance_type();
1061 ElementsKind elements_kind = first_map.elements_kind();
1062
1063 ZoneVector<MapRef> maps(zone());
1064 for (auto const& group : feedback.transition_groups()) {
1065 for (MapRef map : group) {
1066 if (map.instance_type() != instance_type ||
1067 !map.CanInlineElementAccess()) {
1068 return {};
1069 }
1070 if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
1071 .To(&elements_kind)) {
1072 return {};
1073 }
1074 maps.push_back(map);
1075 }
1076 }
1077
1078 return ElementAccessInfo(std::move(maps), elements_kind, zone());
1079}
1080
1082 MapRef map, NameRef name) const {
1083 // Check for String::length field accessor.
1084 if (IsStringMap(*map.object())) {
1085 if (Name::Equals(isolate(), name.object(),
1086 isolate()->factory()->length_string())) {
1088 }
1089 return Invalid();
1090 }
1091 if (IsJSPrimitiveWrapperMap(*map.object()) &&
1092 (map.elements_kind() == FAST_STRING_WRAPPER_ELEMENTS ||
1093 map.elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS)) {
1094 if (Name::Equals(isolate(), name.object(),
1095 isolate()->factory()->length_string())) {
1097 }
1098 }
1099 if (v8_flags.typed_array_length_loading && IsJSTypedArrayMap(*map.object()) &&
1100 !IsRabGsabTypedArrayElementsKind(map.elements_kind()) &&
1101 Name::Equals(isolate(), name.object(),
1102 isolate()->factory()->length_string()) &&
1105 // TODO(388844115): If we cannot depend on the detaching protector, add a
1106 // different kind of TypedArrayLength operator which checks for detached
1107 // before reading the byte_length.
1109 }
1110 // Check for special JSObject field accessors.
1111 FieldIndex field_index;
1112 if (Accessors::IsJSObjectFieldAccessor(isolate(), map.object(), name.object(),
1113 &field_index)) {
1114 Type field_type = Type::NonInternal();
1115 Representation field_representation = Representation::Tagged();
1116 if (IsJSArrayMap(*map.object())) {
1117 DCHECK(Name::Equals(isolate(), isolate()->factory()->length_string(),
1118 name.object()));
1119 // The JSArray::length property is a smi in the range
1120 // [0, FixedDoubleArray::kMaxLength] in case of fast double
1121 // elements, a smi in the range [0, FixedArray::kMaxLength]
1122 // in case of other fast elements, and [0, kMaxUInt32] in
1123 // case of other arrays.
1124 if (IsDoubleElementsKind(map.elements_kind())) {
1126 field_representation = Representation::Smi();
1127 } else if (IsFastElementsKind(map.elements_kind())) {
1128 field_type = type_cache_->kFixedArrayLengthType;
1129 field_representation = Representation::Smi();
1130 } else {
1131 field_type = type_cache_->kJSArrayLengthType;
1132 }
1133 }
1134 // Special fields are always mutable.
1135 return PropertyAccessInfo::DataField(broker(), zone(), map, {{}, zone()},
1136 field_index, field_representation,
1137 field_type, map, {}, {}, {});
1138 }
1139 return Invalid();
1140}
1141
1143 MapRef map, NameRef name, OptionalJSObjectRef holder,
1144 PropertyAttributes attrs) const {
1145 // Check if the {map} has a data transition with the given {name}.
1146 Tagged<Map> transition =
1147 TransitionsAccessor(isolate(), *map.object(), true)
1148 .SearchTransition(*name.object(), PropertyKind::kData, attrs);
1149 if (transition.is_null()) return Invalid();
1150 OptionalMapRef maybe_transition_map = TryMakeRef(broker(), transition);
1151 if (!maybe_transition_map.has_value()) return Invalid();
1152 MapRef transition_map = maybe_transition_map.value();
1153
1154 InternalIndex const number = transition_map.object()->LastAdded();
1155 DirectHandle<DescriptorArray> descriptors =
1156 transition_map.instance_descriptors(broker()).object();
1157 PropertyDetails const details = descriptors->GetDetails(number);
1158
1159 // Don't bother optimizing stores to read-only properties.
1160 if (details.IsReadOnly()) return Invalid();
1161
1162 // TODO(bmeurer): Handle transition to data constant?
1163 if (details.location() != PropertyLocation::kField) return Invalid();
1164
1165 int const index = details.field_index();
1166 Representation details_representation = details.representation();
1167 if (details_representation.IsNone()) return Invalid();
1168
1170 *transition_map.object(), index, details_representation);
1171 Type field_type = Type::NonInternal();
1172 OptionalMapRef field_map;
1173
1174 DCHECK_EQ(transition_map, transition_map.FindFieldOwner(broker(), number));
1175
1176 ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone());
1177 if (details_representation.IsSmi()) {
1178 field_type = Type::SignedSmall();
1179 unrecorded_dependencies.push_back(
1180 dependencies()->FieldRepresentationDependencyOffTheRecord(
1181 transition_map, transition_map, number, details_representation));
1182 } else if (details_representation.IsDouble()) {
1183 field_type = type_cache_->kFloat64;
1184 unrecorded_dependencies.push_back(
1185 dependencies()->FieldRepresentationDependencyOffTheRecord(
1186 transition_map, transition_map, number, details_representation));
1187 } else if (details_representation.IsHeapObject()) {
1188 // Extract the field type from the property details (make sure its
1189 // representation is TaggedPointer to reflect the heap object case).
1190 // TODO(jgruber,v8:7790): Use DescriptorArrayRef instead.
1191 Handle<FieldType> descriptors_field_type =
1192 broker()->CanonicalPersistentHandle(descriptors->GetFieldType(number));
1193 OptionalObjectRef descriptors_field_type_ref =
1194 TryMakeRef<Object>(broker(), descriptors_field_type);
1195 if (!descriptors_field_type_ref.has_value()) return Invalid();
1196
1197 if (IsNone(*descriptors_field_type)) {
1198 // Cleared field-types are pre-monomorphic states. The field type was
1199 // garbge collected and we need to record an updated type.
1201 return Invalid();
1202 }
1203 unrecorded_dependencies.push_back(
1204 dependencies()->FieldRepresentationDependencyOffTheRecord(
1205 transition_map, transition_map, number, details_representation));
1206 if (IsClass(*descriptors_field_type)) {
1207 unrecorded_dependencies.push_back(
1208 dependencies()->FieldTypeDependencyOffTheRecord(
1209 transition_map, transition_map, number,
1210 *descriptors_field_type_ref));
1211 // Remember the field map, and try to infer a useful type.
1212 OptionalMapRef maybe_field_map =
1213 TryMakeRef(broker(), FieldType::AsClass(*descriptors_field_type));
1214 if (!maybe_field_map.has_value()) return Invalid();
1215 field_map = maybe_field_map;
1216 // field_type can only be inferred from field_map if it is stable and we
1217 // add a stability dependency. This happens on use in the access builder.
1218 }
1219 }
1220
1221 unrecorded_dependencies.push_back(
1222 dependencies()->TransitionDependencyOffTheRecord(transition_map));
1223 // Transitioning stores *may* store to const fields. The resulting
1224 // DataConstant access infos can be distinguished from later, i.e. redundant,
1225 // stores to the same constant field by the presence of a transition map.
1226
1227 PropertyConstness constness =
1228 transition_map.GetPropertyDetails(broker_, number).constness();
1229 switch (constness) {
1232 broker(), zone(), map, std::move(unrecorded_dependencies),
1233 field_index, details_representation, field_type, transition_map,
1234 field_map, holder, transition_map);
1236 auto constness_dep = dependencies()->FieldConstnessDependencyOffTheRecord(
1237 transition_map, transition_map, number);
1238 unrecorded_dependencies.push_back(constness_dep);
1240 zone(), map, std::move(unrecorded_dependencies), field_index,
1241 details_representation, field_type, transition_map, field_map, holder,
1242 transition_map);
1243 }
1244 UNREACHABLE();
1245}
1246
1247} // namespace compiler
1248} // namespace internal
1249} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
#define SLOW_DCHECK(condition)
Definition checks.h:21
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
static FieldIndex ForPropertyIndex(Tagged< Map > map, int index, Representation representation=Representation::Tagged())
int GetFieldAccessStubKey() const
Definition field-index.h:71
static Tagged< Map > AsClass(Tagged< FieldType > type)
Definition field-type.cc:51
static constexpr bool kFieldTypesCanBeClearedOnGC
Definition field-type.h:21
static std::optional< Tagged< Name > > TryGetCachedPropertyName(Isolate *isolate, Tagged< Object > getter)
Definition templates.cc:153
static InternalIndex NotFound()
static Handle< Object > DictionaryPropertyAt(Isolate *isolate, DirectHandle< JSObject > object, InternalIndex dict_index)
bool Equals(Tagged< Name > other)
Definition name-inl.h:76
PropertyAttributes attributes() const
PropertyLocation location() const
Representation representation() const
static constexpr PropertyDetails Empty(PropertyCellType cell_type=PropertyCellType::kNoCell)
PropertyConstness constness() const
constexpr bool IsHeapObject() const
constexpr bool IsNone() const
constexpr bool IsTagged() const
bool Equals(const Representation &other) const
constexpr bool IsSmi() const
static constexpr Representation Smi()
static constexpr Representation Tagged()
constexpr bool IsDouble() const
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
Tagged< Map > SearchTransition(Tagged< Name > name, PropertyKind kind, PropertyAttributes attributes)
T * insert(const T *pos, It first, It last)
void push_back(const T &value)
bool ComputeElementAccessInfos(ElementAccessFeedback const &feedback, ZoneVector< ElementAccessInfo > *access_infos) const
AccessInfoFactory(JSHeapBroker *broker, Zone *zone)
std::optional< ElementAccessInfo > ConsolidateElementLoad(ElementAccessFeedback const &feedback) const
PropertyAccessInfo LookupTransition(MapRef map, NameRef name, OptionalJSObjectRef holder, PropertyAttributes attrs) const
bool FinalizePropertyAccessInfos(ZoneVector< PropertyAccessInfo > infos, AccessMode access_mode, ZoneVector< PropertyAccessInfo > *result) const
PropertyAccessInfo ComputeDictionaryProtoAccessInfo(MapRef receiver_map, NameRef name, JSObjectRef holder, InternalIndex dict_index, AccessMode access_mode, PropertyDetails details) const
PropertyAccessInfo LookupSpecialFieldAccessor(MapRef map, NameRef name) const
bool TryLoadPropertyDetails(MapRef map, OptionalJSObjectRef maybe_holder, NameRef name, InternalIndex *index_out, PropertyDetails *details_out) const
void MergePropertyAccessInfos(ZoneVector< PropertyAccessInfo > infos, AccessMode access_mode, ZoneVector< PropertyAccessInfo > *result) const
PropertyAccessInfo Invalid() const
PropertyAccessInfo FinalizePropertyAccessInfosAsOne(ZoneVector< PropertyAccessInfo > infos, AccessMode access_mode) const
PropertyAccessInfo ComputePropertyAccessInfo(MapRef map, NameRef name, AccessMode access_mode) const
std::optional< ElementAccessInfo > ComputeElementAccessInfo(MapRef map, AccessMode access_mode) const
PropertyAccessInfo ComputeDataFieldAccessInfo(MapRef receiver_map, MapRef map, NameRef name, OptionalJSObjectRef holder, InternalIndex descriptor, AccessMode access_mode) const
PropertyAccessInfo ComputeAccessorDescriptorAccessInfo(MapRef receiver_map, NameRef name, MapRef map, OptionalJSObjectRef holder, InternalIndex descriptor, AccessMode access_mode) const
CompilationDependencies * dependencies() const
CompilationDependency const * FieldConstnessDependencyOffTheRecord(MapRef map, MapRef owner, InternalIndex descriptor)
void RecordDependency(CompilationDependency const *dependency)
IndirectHandle< DescriptorArray > object() const
ZoneVector< MapRef > const & lookup_start_object_maps() const
Definition access-info.h:39
ElementAccessInfo(ZoneVector< MapRef > &&lookup_start_object_maps, ElementsKind elements_kind, Zone *zone)
V8_EXPORT_PRIVATE MapRef map(JSHeapBroker *broker) const
LocalIsolate * local_isolate_or_isolate() const
Handle< T > CanonicalPersistentHandle(Tagged< T > object)
CompilationDependencies * dependencies() const
NativeContextRef target_native_context() const
IndirectHandle< JSObject > object() const
PropertyDetails GetPropertyDetails(JSHeapBroker *broker, InternalIndex descriptor_index) const
DescriptorArrayRef instance_descriptors(JSHeapBroker *broker) const
IndirectHandle< Map > object() const
InstanceType instance_type() const
ElementsKind elements_kind() const
MapRef FindFieldOwner(JSHeapBroker *broker, InternalIndex descriptor_index) const
IndirectHandle< NativeContext > object() const
OptionalJSFunctionRef GetConstructorFunction(JSHeapBroker *broker, MapRef map) const
constexpr bool has_value() const
Definition heap-refs.h:341
Representation field_representation() const
static PropertyAccessInfo TypedArrayLength(Zone *zone, MapRef receiver_map)
static PropertyAccessInfo FastAccessorConstant(Zone *zone, MapRef receiver_map, OptionalJSObjectRef holder, OptionalObjectRef constant, OptionalJSObjectRef api_holder)
static PropertyAccessInfo NotFound(Zone *zone, MapRef receiver_map, OptionalJSObjectRef holder)
bool Merge(PropertyAccessInfo const *that, AccessMode access_mode, Zone *zone) V8_WARN_UNUSED_RESULT
static PropertyAccessInfo StringWrapperLength(Zone *zone, MapRef receiver_map)
OptionalJSObjectRef holder() const
void set_elements_kind(ElementsKind elements_kind)
static PropertyAccessInfo DictionaryProtoDataConstant(Zone *zone, MapRef receiver_map, JSObjectRef holder, InternalIndex dict_index, NameRef name)
ZoneVector< CompilationDependency const * > unrecorded_dependencies_
static PropertyAccessInfo StringLength(Zone *zone, MapRef receiver_map)
static PropertyAccessInfo Invalid(Zone *zone)
static PropertyAccessInfo ModuleExport(Zone *zone, MapRef receiver_map, CellRef cell)
static PropertyAccessInfo DataField(JSHeapBroker *broker, Zone *zone, MapRef receiver_map, ZoneVector< CompilationDependency const * > &&unrecorded_dependencies, FieldIndex field_index, Representation field_representation, Type field_type, MapRef field_owner_map, OptionalMapRef field_map, OptionalJSObjectRef holder, OptionalMapRef transition_map)
void RecordDependencies(CompilationDependencies *dependencies)
static PropertyAccessInfo FastDataConstant(Zone *zone, MapRef receiver_map, ZoneVector< CompilationDependency const * > &&unrecorded_dependencies, FieldIndex field_index, Representation field_representation, Type field_type, MapRef field_owner_map, OptionalMapRef field_map, OptionalJSObjectRef holder, OptionalMapRef transition_map)
static PropertyAccessInfo DictionaryProtoAccessorConstant(Zone *zone, MapRef receiver_map, OptionalJSObjectRef holder, ObjectRef constant, OptionalJSObjectRef api_holder, NameRef name)
IndirectHandle< String > object() const
static Type Union(Type type1, Type type2, Zone *zone)
Zone * zone_
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL
Definition globals.h:249
#define DEBUG_BOOL
Definition globals.h:87
const PropertyKind kind_
JSObjectRef const holder_
JSHeapBroker *const broker_
const ObjectRef constant_
int end
JSHeapBroker * broker
ElementsKind elements_kind_
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
const char * name_
STL namespace.
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
bool IsAnyStore(AccessMode mode)
Definition heap-refs.h:65
OptionalRef< typename ref_traits< T >::ref_type > TryMakeRef(JSHeapBroker *broker, ObjectData *data)
bool IsDefiningStore(AccessMode mode)
Definition heap-refs.h:70
std::ostream & operator<<(std::ostream &os, AccessMode access_mode)
bool IsNone(Tagged< FieldType > obj)
Definition field-type.h:50
constexpr bool IsHoleyElementsKind(ElementsKind kind)
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, ElementsKind to_kind)
Map::Bits1::HasPrototypeSlotBit Map::Bits1::HasNamedInterceptorBit Map::Bits1::IsUndetectableBit Map::Bits1::IsConstructorBit Map::Bits2::IsImmutablePrototypeBit Map::Bits3::IsDeprecatedBit is_prototype_map
Definition map-inl.h:133
bool IsRabGsabTypedArrayElementsKind(ElementsKind kind)
bool IsSpecialIndex(Tagged< String > string)
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget maximum bytecode size to be considered for turbofan optimization
Definition flags.cc:1368
@ SLOW_STRING_WRAPPER_ELEMENTS
@ FAST_STRING_WRAPPER_ELEMENTS
bool IsClass(Tagged< FieldType > obj)
Definition field-type.cc:48
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
bool IsBooleanMap(Tagged< Map > map)
Definition map-inl.h:745
bool IsFastElementsKind(ElementsKind kind)
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_INLINE bool IsWasmObject(T obj, Isolate *=nullptr)
Definition objects.h:725
constexpr bool IsDoubleElementsKind(ElementsKind kind)
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
static constexpr RelaxedLoadTag kRelaxedLoad
Definition globals.h:2909
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
uint32_t equals
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485