Line data Source code
1 : // Copyright 2017 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 : #ifndef V8_OBJECTS_MAP_INL_H_
6 : #define V8_OBJECTS_MAP_INL_H_
7 :
8 : #include "src/objects/map.h"
9 :
10 : #include "src/field-type.h"
11 : #include "src/heap/heap-write-barrier-inl.h"
12 : #include "src/layout-descriptor-inl.h"
13 : #include "src/objects-inl.h"
14 : #include "src/objects/api-callbacks-inl.h"
15 : #include "src/objects/cell-inl.h"
16 : #include "src/objects/descriptor-array-inl.h"
17 : #include "src/objects/instance-type-inl.h"
18 : #include "src/objects/prototype-info-inl.h"
19 : #include "src/objects/shared-function-info.h"
20 : #include "src/objects/templates-inl.h"
21 : #include "src/property.h"
22 : #include "src/transitions.h"
23 :
24 : // Has to be the last include (doesn't have include guards):
25 : #include "src/objects/object-macros.h"
26 :
27 : namespace v8 {
28 : namespace internal {
29 :
30 : OBJECT_CONSTRUCTORS_IMPL(Map, HeapObject)
31 : CAST_ACCESSOR(Map)
32 :
33 473390 : DescriptorArray Map::instance_descriptors() const {
34 759815317 : return DescriptorArray::cast(READ_FIELD(*this, kDescriptorsOffset));
35 : }
36 :
37 : DescriptorArray Map::synchronized_instance_descriptors() const {
38 26434850 : return DescriptorArray::cast(ACQUIRE_READ_FIELD(*this, kDescriptorsOffset));
39 : }
40 :
41 84462963 : void Map::set_synchronized_instance_descriptors(DescriptorArray value,
42 : WriteBarrierMode mode) {
43 84462963 : RELEASE_WRITE_FIELD(*this, kDescriptorsOffset, value);
44 168926007 : CONDITIONAL_WRITE_BARRIER(*this, kDescriptorsOffset, value, mode);
45 84462934 : }
46 :
47 : // A freshly allocated layout descriptor can be set on an existing map.
48 : // We need to use release-store and acquire-load accessor pairs to ensure
49 : // that the concurrent marking thread observes initializing stores of the
50 : // layout descriptor.
51 344048483 : SYNCHRONIZED_ACCESSORS_CHECKED(Map, layout_descriptor, LayoutDescriptor,
52 : kLayoutDescriptorOffset,
53 : FLAG_unbox_double_fields)
54 294975169 : WEAK_ACCESSORS(Map, raw_transitions, kTransitionsOrPrototypeInfoOffset)
55 :
56 : // |bit_field| fields.
57 : // Concurrent access to |has_prototype_slot| and |has_non_instance_prototype|
58 : // is explicitly whitelisted here. The former is never modified after the map
59 : // is setup but it's being read by concurrent marker when pointer compression
60 : // is enabled. The latter bit can be modified on a live objects.
61 799746 : BIT_FIELD_ACCESSORS(Map, relaxed_bit_field, has_non_instance_prototype,
62 : Map::HasNonInstancePrototypeBit)
63 262948 : BIT_FIELD_ACCESSORS(Map, bit_field, is_callable, Map::IsCallableBit)
64 1096 : BIT_FIELD_ACCESSORS(Map, bit_field, has_named_interceptor,
65 : Map::HasNamedInterceptorBit)
66 217 : BIT_FIELD_ACCESSORS(Map, bit_field, has_indexed_interceptor,
67 : Map::HasIndexedInterceptorBit)
68 261 : BIT_FIELD_ACCESSORS(Map, bit_field, is_undetectable, Map::IsUndetectableBit)
69 184303 : BIT_FIELD_ACCESSORS(Map, bit_field, is_access_check_needed,
70 : Map::IsAccessCheckNeededBit)
71 3083 : BIT_FIELD_ACCESSORS(Map, bit_field, is_constructor, Map::IsConstructorBit)
72 4995 : BIT_FIELD_ACCESSORS(Map, relaxed_bit_field, has_prototype_slot,
73 : Map::HasPrototypeSlotBit)
74 :
75 : // |bit_field2| fields.
76 138194 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_extensible, Map::IsExtensibleBit)
77 4617224 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_prototype_map, Map::IsPrototypeMapBit)
78 46713 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_in_retained_map_list,
79 : Map::IsInRetainedMapListBit)
80 :
81 : // |bit_field3| fields.
82 20820064 : BIT_FIELD_ACCESSORS(Map, bit_field3, owns_descriptors, Map::OwnsDescriptorsBit)
83 63462404 : BIT_FIELD_ACCESSORS(Map, bit_field3, has_hidden_prototype,
84 : Map::HasHiddenPrototypeBit)
85 46702 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
86 504658 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_migration_target,
87 : Map::IsMigrationTargetBit)
88 270 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_immutable_proto,
89 : Map::IsImmutablePrototypeBit)
90 62482814 : BIT_FIELD_ACCESSORS(Map, bit_field3, new_target_is_base,
91 : Map::NewTargetIsBaseBit)
92 3695944 : BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_symbols,
93 : Map::MayHaveInterestingSymbolsBit)
94 2174564 : BIT_FIELD_ACCESSORS(Map, bit_field3, construction_counter,
95 : Map::ConstructionCounterBits)
96 :
97 1602577 : InterceptorInfo Map::GetNamedInterceptor() {
98 : DCHECK(has_named_interceptor());
99 1602577 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
100 1602577 : return InterceptorInfo::cast(info->GetNamedPropertyHandler());
101 : }
102 :
103 668416 : InterceptorInfo Map::GetIndexedInterceptor() {
104 : DCHECK(has_indexed_interceptor());
105 668416 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
106 668416 : return InterceptorInfo::cast(info->GetIndexedPropertyHandler());
107 : }
108 :
109 : bool Map::IsMostGeneralFieldType(Representation representation,
110 : FieldType field_type) {
111 650 : return !representation.IsHeapObject() || field_type->IsAny();
112 : }
113 :
114 : bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) {
115 17391678 : return instance_type == JS_ARRAY_TYPE || instance_type == JS_VALUE_TYPE ||
116 : instance_type == JS_ARGUMENTS_TYPE;
117 : }
118 :
119 : bool Map::CanHaveFastTransitionableElementsKind() const {
120 : return CanHaveFastTransitionableElementsKind(instance_type());
121 : }
122 :
123 : // static
124 17320266 : void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
125 : Isolate* isolate, InstanceType instance_type, PropertyConstness* constness,
126 : Representation* representation, Handle<FieldType>* field_type) {
127 17320266 : if (CanHaveFastTransitionableElementsKind(instance_type)) {
128 : // We don't support propagation of field generalization through elements
129 : // kind transitions because they are inserted into the transition tree
130 : // before field transitions. In order to avoid complexity of handling
131 : // such a case we ensure that all maps with transitionable elements kinds
132 : // have the most general field type.
133 129698 : if (representation->IsHeapObject()) {
134 : // The field type is either already Any or should become Any if it was
135 : // something else.
136 108055 : *field_type = FieldType::Any(isolate);
137 : }
138 : }
139 17320266 : }
140 :
141 102928977 : bool Map::IsUnboxedDoubleField(FieldIndex index) const {
142 : if (!FLAG_unbox_double_fields) return false;
143 205857964 : if (index.is_hidden_field() || !index.is_inobject()) return false;
144 22623789 : return !layout_descriptor()->IsTagged(index.property_index());
145 : }
146 :
147 18268943 : bool Map::TooManyFastProperties(StoreOrigin store_origin) const {
148 18268943 : if (UnusedPropertyFields() != 0) return false;
149 3154924 : if (is_prototype_map()) return false;
150 2605159 : if (store_origin == StoreOrigin::kNamed) {
151 2558155 : int limit = Max(kMaxFastProperties, GetInObjectProperties());
152 2558154 : FieldCounts counts = GetFieldCounts();
153 : // Only count mutable fields so that objects with large numbers of
154 : // constant functions do not go to dictionary mode. That would be bad
155 : // because such objects have often been used as modules.
156 2558154 : int external = counts.mutable_count() - GetInObjectProperties();
157 5116304 : return external > limit || counts.GetTotal() > kMaxNumberOfDescriptors;
158 : } else {
159 47004 : int limit = Max(kFastPropertiesSoftLimit, GetInObjectProperties());
160 47004 : int external = NumberOfFields() - GetInObjectProperties();
161 47004 : return external > limit;
162 : }
163 : }
164 :
165 80540617 : PropertyDetails Map::GetLastDescriptorDetails() const {
166 80540617 : return instance_descriptors()->GetDetails(LastAdded());
167 : }
168 :
169 : int Map::LastAdded() const {
170 : int number_of_own_descriptors = NumberOfOwnDescriptors();
171 : DCHECK_GT(number_of_own_descriptors, 0);
172 163581982 : return number_of_own_descriptors - 1;
173 : }
174 :
175 1695753 : int Map::NumberOfOwnDescriptors() const {
176 1695753 : return NumberOfOwnDescriptorsBits::decode(bit_field3());
177 : }
178 :
179 84473330 : void Map::SetNumberOfOwnDescriptors(int number) {
180 : DCHECK_LE(number, instance_descriptors()->number_of_descriptors());
181 84473330 : CHECK_LE(static_cast<unsigned>(number),
182 : static_cast<unsigned>(kMaxNumberOfDescriptors));
183 : set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number));
184 84473330 : }
185 :
186 : int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); }
187 :
188 89636 : void Map::SetEnumLength(int length) {
189 89636 : if (length != kInvalidEnumCacheSentinel) {
190 : DCHECK_LE(length, NumberOfOwnDescriptors());
191 61688 : CHECK_LE(static_cast<unsigned>(length),
192 : static_cast<unsigned>(kMaxNumberOfDescriptors));
193 : }
194 : set_bit_field3(EnumLengthBits::update(bit_field3(), length));
195 89636 : }
196 :
197 38587446 : FixedArrayBase Map::GetInitialElements() const {
198 : FixedArrayBase result;
199 38587446 : if (has_fast_elements() || has_fast_string_wrapper_elements()) {
200 : result = GetReadOnlyRoots().empty_fixed_array();
201 7540 : } else if (has_fast_sloppy_arguments_elements()) {
202 : result = GetReadOnlyRoots().empty_sloppy_arguments_elements();
203 7540 : } else if (has_fixed_typed_array_elements()) {
204 : result =
205 : GetReadOnlyRoots().EmptyFixedTypedArrayForTypedArray(elements_kind());
206 3321 : } else if (has_dictionary_elements()) {
207 : result = GetReadOnlyRoots().empty_slow_element_dictionary();
208 : } else {
209 0 : UNREACHABLE();
210 : }
211 : DCHECK(!ObjectInYoungGeneration(result));
212 38587446 : return result;
213 : }
214 :
215 : VisitorId Map::visitor_id() const {
216 : return static_cast<VisitorId>(
217 1671706369 : RELAXED_READ_BYTE_FIELD(*this, kVisitorIdOffset));
218 : }
219 :
220 55718630 : void Map::set_visitor_id(VisitorId id) {
221 55718630 : CHECK_LT(static_cast<unsigned>(id), 256);
222 55718630 : RELAXED_WRITE_BYTE_FIELD(*this, kVisitorIdOffset, static_cast<byte>(id));
223 55718630 : }
224 :
225 : int Map::instance_size_in_words() const {
226 5791585595 : return RELAXED_READ_BYTE_FIELD(*this, kInstanceSizeInWordsOffset);
227 : }
228 :
229 : void Map::set_instance_size_in_words(int value) {
230 31356815 : RELAXED_WRITE_BYTE_FIELD(*this, kInstanceSizeInWordsOffset,
231 : static_cast<byte>(value));
232 : }
233 :
234 4865567 : int Map::instance_size() const {
235 2476104313 : return instance_size_in_words() << kTaggedSizeLog2;
236 : }
237 :
238 31356815 : void Map::set_instance_size(int value) {
239 31356815 : CHECK(IsAligned(value, kTaggedSize));
240 31356815 : value >>= kTaggedSizeLog2;
241 62713630 : CHECK_LT(static_cast<unsigned>(value), 256);
242 : set_instance_size_in_words(value);
243 31356815 : }
244 :
245 : int Map::inobject_properties_start_or_constructor_function_index() const {
246 1092033920 : return RELAXED_READ_BYTE_FIELD(
247 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset);
248 : }
249 :
250 31090018 : void Map::set_inobject_properties_start_or_constructor_function_index(
251 : int value) {
252 62180036 : CHECK_LT(static_cast<unsigned>(value), 256);
253 31090018 : RELAXED_WRITE_BYTE_FIELD(
254 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
255 : static_cast<byte>(value));
256 31090018 : }
257 :
258 : int Map::GetInObjectPropertiesStartInWords() const {
259 : DCHECK(IsJSObjectMap());
260 : return inobject_properties_start_or_constructor_function_index();
261 : }
262 :
263 31079873 : void Map::SetInObjectPropertiesStartInWords(int value) {
264 31079873 : CHECK(IsJSObjectMap());
265 31079873 : set_inobject_properties_start_or_constructor_function_index(value);
266 31079885 : }
267 :
268 342165795 : int Map::GetInObjectProperties() const {
269 : DCHECK(IsJSObjectMap());
270 342165795 : return instance_size_in_words() - GetInObjectPropertiesStartInWords();
271 : }
272 :
273 : int Map::GetConstructorFunctionIndex() const {
274 : DCHECK(IsPrimitiveMap());
275 : return inobject_properties_start_or_constructor_function_index();
276 : }
277 :
278 1288 : void Map::SetConstructorFunctionIndex(int value) {
279 1288 : CHECK(IsPrimitiveMap());
280 1288 : set_inobject_properties_start_or_constructor_function_index(value);
281 1288 : }
282 :
283 : int Map::GetInObjectPropertyOffset(int index) const {
284 165473133 : return (GetInObjectPropertiesStartInWords() + index) * kTaggedSize;
285 : }
286 :
287 : Handle<Map> Map::AddMissingTransitionsForTesting(
288 : Isolate* isolate, Handle<Map> split_map,
289 : Handle<DescriptorArray> descriptors,
290 : Handle<LayoutDescriptor> full_layout_descriptor) {
291 : return AddMissingTransitions(isolate, split_map, descriptors,
292 65 : full_layout_descriptor);
293 : }
294 :
295 4540783 : InstanceType Map::instance_type() const {
296 : return static_cast<InstanceType>(
297 22469706304 : READ_UINT16_FIELD(*this, kInstanceTypeOffset));
298 : }
299 :
300 : void Map::set_instance_type(InstanceType value) {
301 30938924 : WRITE_UINT16_FIELD(*this, kInstanceTypeOffset, value);
302 : }
303 :
304 106308213 : int Map::UnusedPropertyFields() const {
305 : int value = used_or_unused_instance_size_in_words();
306 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
307 : int unused;
308 106308213 : if (value >= JSObject::kFieldsAdded) {
309 58902754 : unused = instance_size_in_words() - value;
310 : } else {
311 : // For out of object properties "used_or_unused_instance_size_in_words"
312 : // byte encodes the slack in the property array.
313 : unused = value;
314 : }
315 106308213 : return unused;
316 : }
317 :
318 369 : int Map::UnusedInObjectProperties() const {
319 : // Like Map::UnusedPropertyFields(), but returns 0 for out of object
320 : // properties.
321 : int value = used_or_unused_instance_size_in_words();
322 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
323 369 : if (value >= JSObject::kFieldsAdded) {
324 324 : return instance_size_in_words() - value;
325 : }
326 : return 0;
327 : }
328 :
329 : int Map::used_or_unused_instance_size_in_words() const {
330 389514936 : return RELAXED_READ_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset);
331 : }
332 :
333 73933977 : void Map::set_used_or_unused_instance_size_in_words(int value) {
334 147867954 : CHECK_LE(static_cast<unsigned>(value), 255);
335 73933977 : RELAXED_WRITE_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset,
336 : static_cast<byte>(value));
337 73933977 : }
338 :
339 46620686 : int Map::UsedInstanceSize() const {
340 : int words = used_or_unused_instance_size_in_words();
341 46620686 : if (words < JSObject::kFieldsAdded) {
342 : // All in-object properties are used and the words is tracking the slack
343 : // in the property array.
344 5083006 : return instance_size();
345 : }
346 41537680 : return words * kTaggedSize;
347 : }
348 :
349 31884734 : void Map::SetInObjectUnusedPropertyFields(int value) {
350 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
351 31884734 : if (!IsJSObjectMap()) {
352 8850 : CHECK_EQ(0, value);
353 8850 : set_used_or_unused_instance_size_in_words(0);
354 : DCHECK_EQ(0, UnusedPropertyFields());
355 8850 : return;
356 : }
357 31875884 : CHECK_LE(0, value);
358 : DCHECK_LE(value, GetInObjectProperties());
359 31875884 : int used_inobject_properties = GetInObjectProperties() - value;
360 : set_used_or_unused_instance_size_in_words(
361 31875882 : GetInObjectPropertyOffset(used_inobject_properties) / kTaggedSize);
362 : DCHECK_EQ(value, UnusedPropertyFields());
363 : }
364 :
365 221099 : void Map::SetOutOfObjectUnusedPropertyFields(int value) {
366 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
367 442198 : CHECK_LT(static_cast<unsigned>(value), JSObject::kFieldsAdded);
368 : // For out of object properties "used_instance_size_in_words" byte encodes
369 : // the slack in the property array.
370 221099 : set_used_or_unused_instance_size_in_words(value);
371 : DCHECK_EQ(value, UnusedPropertyFields());
372 221099 : }
373 :
374 24806801 : void Map::CopyUnusedPropertyFields(Map map) {
375 : set_used_or_unused_instance_size_in_words(
376 24806801 : map->used_or_unused_instance_size_in_words());
377 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
378 24806804 : }
379 :
380 324 : void Map::CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map map) {
381 : int value = map->used_or_unused_instance_size_in_words();
382 324 : if (value >= JSValue::kFieldsAdded) {
383 : // Unused in-object fields. Adjust the offset from the object’s start
384 : // so it matches the distance to the object’s end.
385 279 : value += instance_size_in_words() - map->instance_size_in_words();
386 : }
387 324 : set_used_or_unused_instance_size_in_words(value);
388 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
389 324 : }
390 :
391 17021075 : void Map::AccountAddedPropertyField() {
392 : // Update used instance size and unused property fields number.
393 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
394 : #ifdef DEBUG
395 : int new_unused = UnusedPropertyFields() - 1;
396 : if (new_unused < 0) new_unused += JSObject::kFieldsAdded;
397 : #endif
398 : int value = used_or_unused_instance_size_in_words();
399 17021075 : if (value >= JSObject::kFieldsAdded) {
400 9107573 : if (value == instance_size_in_words()) {
401 784634 : AccountAddedOutOfObjectPropertyField(0);
402 : } else {
403 : // The property is added in-object, so simply increment the counter.
404 8322939 : set_used_or_unused_instance_size_in_words(value + 1);
405 : }
406 : } else {
407 7913502 : AccountAddedOutOfObjectPropertyField(value);
408 : }
409 : DCHECK_EQ(new_unused, UnusedPropertyFields());
410 17021074 : }
411 :
412 8698137 : void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
413 8698137 : unused_in_property_array--;
414 8698137 : if (unused_in_property_array < 0) {
415 3134413 : unused_in_property_array += JSObject::kFieldsAdded;
416 : }
417 17396274 : CHECK_LT(static_cast<unsigned>(unused_in_property_array),
418 : JSObject::kFieldsAdded);
419 8698137 : set_used_or_unused_instance_size_in_words(unused_in_property_array);
420 : DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
421 8698136 : }
422 :
423 294750397 : byte Map::bit_field() const { return READ_BYTE_FIELD(*this, kBitFieldOffset); }
424 :
425 : void Map::set_bit_field(byte value) {
426 56580272 : WRITE_BYTE_FIELD(*this, kBitFieldOffset, value);
427 : }
428 :
429 : byte Map::relaxed_bit_field() const {
430 58921012 : return RELAXED_READ_BYTE_FIELD(*this, kBitFieldOffset);
431 : }
432 :
433 : void Map::set_relaxed_bit_field(byte value) {
434 268247 : RELAXED_WRITE_BYTE_FIELD(*this, kBitFieldOffset, value);
435 : }
436 :
437 : byte Map::bit_field2() const {
438 730445019 : return READ_BYTE_FIELD(*this, kBitField2Offset);
439 : }
440 :
441 : void Map::set_bit_field2(byte value) {
442 92442338 : WRITE_BYTE_FIELD(*this, kBitField2Offset, value);
443 : }
444 :
445 443094 : bool Map::is_abandoned_prototype_map() const {
446 464524 : return is_prototype_map() && !owns_descriptors();
447 : }
448 :
449 32170655 : bool Map::should_be_fast_prototype_map() const {
450 32170643 : if (!prototype_info()->IsPrototypeInfo()) return false;
451 : return PrototypeInfo::cast(prototype_info())->should_be_fast_map();
452 : }
453 :
454 31250979 : void Map::set_elements_kind(ElementsKind elements_kind) {
455 31250979 : CHECK_LT(static_cast<int>(elements_kind), kElementsKindCount);
456 31250979 : set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
457 31250979 : }
458 :
459 : ElementsKind Map::elements_kind() const {
460 : return Map::ElementsKindBits::decode(bit_field2());
461 : }
462 :
463 : bool Map::has_fast_smi_elements() const {
464 : return IsSmiElementsKind(elements_kind());
465 : }
466 :
467 : bool Map::has_fast_object_elements() const {
468 : return IsObjectElementsKind(elements_kind());
469 : }
470 :
471 : bool Map::has_fast_smi_or_object_elements() const {
472 : return IsSmiOrObjectElementsKind(elements_kind());
473 : }
474 :
475 : bool Map::has_fast_double_elements() const {
476 : return IsDoubleElementsKind(elements_kind());
477 : }
478 :
479 : bool Map::has_fast_elements() const {
480 : return IsFastElementsKind(elements_kind());
481 : }
482 :
483 : bool Map::has_sloppy_arguments_elements() const {
484 : return IsSloppyArgumentsElementsKind(elements_kind());
485 : }
486 :
487 : bool Map::has_fast_sloppy_arguments_elements() const {
488 : return elements_kind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
489 : }
490 :
491 : bool Map::has_fast_string_wrapper_elements() const {
492 : return elements_kind() == FAST_STRING_WRAPPER_ELEMENTS;
493 : }
494 :
495 : bool Map::has_fixed_typed_array_elements() const {
496 : return IsFixedTypedArrayElementsKind(elements_kind());
497 : }
498 :
499 : bool Map::has_dictionary_elements() const {
500 : return IsDictionaryElementsKind(elements_kind());
501 : }
502 :
503 : bool Map::has_frozen_or_sealed_elements() const {
504 : return IsPackedFrozenOrSealedElementsKind(elements_kind());
505 : }
506 :
507 : bool Map::has_sealed_elements() const {
508 : return IsSealedElementsKind(elements_kind());
509 : }
510 :
511 : bool Map::has_frozen_elements() const {
512 : return IsFrozenElementsKind(elements_kind());
513 : }
514 :
515 773438 : void Map::set_is_dictionary_map(bool value) {
516 : uint32_t new_bit_field3 = IsDictionaryMapBit::update(bit_field3(), value);
517 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, value);
518 : set_bit_field3(new_bit_field3);
519 773438 : }
520 :
521 : bool Map::is_dictionary_map() const {
522 : return IsDictionaryMapBit::decode(bit_field3());
523 : }
524 :
525 18802984 : void Map::mark_unstable() {
526 : set_bit_field3(IsUnstableBit::update(bit_field3(), true));
527 18802984 : }
528 :
529 549909 : bool Map::is_stable() const { return !IsUnstableBit::decode(bit_field3()); }
530 :
531 25213831 : bool Map::CanBeDeprecated() const {
532 : int descriptor = LastAdded();
533 150104603 : for (int i = 0; i <= descriptor; i++) {
534 70448119 : PropertyDetails details = instance_descriptors()->GetDetails(i);
535 70448068 : if (details.representation().IsNone()) return true;
536 70448756 : if (details.representation().IsSmi()) return true;
537 67632279 : if (details.representation().IsDouble()) return true;
538 67631543 : if (details.representation().IsHeapObject()) return true;
539 76068053 : if (details.kind() == kData && details.location() == kDescriptor) {
540 : return true;
541 : }
542 : }
543 : return false;
544 : }
545 :
546 34894764 : void Map::NotifyLeafMapLayoutChange(Isolate* isolate) {
547 34894764 : if (is_stable()) {
548 18802759 : mark_unstable();
549 37605523 : dependent_code()->DeoptimizeDependentCodeGroup(
550 18802761 : isolate, DependentCode::kPrototypeCheckGroup);
551 : }
552 34894767 : }
553 :
554 : bool Map::CanTransition() const {
555 : // Only JSObject and subtypes have map transitions and back pointers.
556 : return InstanceTypeChecker::IsJSObject(instance_type());
557 : }
558 :
559 : #define DEF_TESTER(Type, ...) \
560 : bool Map::Is##Type##Map() const { \
561 : return InstanceTypeChecker::Is##Type(instance_type()); \
562 : }
563 : INSTANCE_TYPE_CHECKERS(DEF_TESTER)
564 : #undef DEF_TESTER
565 :
566 : bool Map::IsBooleanMap() const {
567 : return *this == GetReadOnlyRoots().boolean_map();
568 : }
569 :
570 : bool Map::IsNullOrUndefinedMap() const {
571 1143 : return *this == GetReadOnlyRoots().null_map() ||
572 : *this == GetReadOnlyRoots().undefined_map();
573 : }
574 :
575 : bool Map::IsPrimitiveMap() const {
576 : return instance_type() <= LAST_PRIMITIVE_TYPE;
577 : }
578 :
579 : HeapObject Map::prototype() const {
580 402372021 : return HeapObject::cast(READ_FIELD(*this, kPrototypeOffset));
581 : }
582 :
583 31642519 : void Map::set_prototype(HeapObject value, WriteBarrierMode mode) {
584 : DCHECK(value->IsNull() || value->IsJSReceiver());
585 62578042 : WRITE_FIELD(*this, kPrototypeOffset, value);
586 57771501 : CONDITIONAL_WRITE_BARRIER(*this, kPrototypeOffset, value, mode);
587 31642502 : }
588 :
589 : LayoutDescriptor Map::layout_descriptor_gc_safe() const {
590 : DCHECK(FLAG_unbox_double_fields);
591 : // The loaded value can be dereferenced on background thread to load the
592 : // bitmap. We need acquire load in order to ensure that the bitmap
593 : // initializing stores are also visible to the background thread.
594 179040 : Object layout_desc = ACQUIRE_READ_FIELD(*this, kLayoutDescriptorOffset);
595 : return LayoutDescriptor::cast_gc_safe(layout_desc);
596 : }
597 :
598 : bool Map::HasFastPointerLayout() const {
599 : DCHECK(FLAG_unbox_double_fields);
600 : // The loaded value is used for SMI check only and is not dereferenced,
601 : // so relaxed load is safe.
602 127833038 : Object layout_desc = RELAXED_READ_FIELD(*this, kLayoutDescriptorOffset);
603 : return LayoutDescriptor::IsFastPointerLayout(layout_desc);
604 : }
605 :
606 28894774 : void Map::UpdateDescriptors(Isolate* isolate, DescriptorArray descriptors,
607 : LayoutDescriptor layout_desc,
608 : int number_of_own_descriptors) {
609 28894774 : SetInstanceDescriptors(isolate, descriptors, number_of_own_descriptors);
610 : if (FLAG_unbox_double_fields) {
611 28894779 : if (layout_descriptor()->IsSlowLayout()) {
612 2806 : set_layout_descriptor(layout_desc);
613 : }
614 : #ifdef VERIFY_HEAP
615 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
616 : if (FLAG_verify_heap) {
617 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
618 : CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
619 : }
620 : #else
621 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
622 : DCHECK(visitor_id() == Map::GetVisitorId(*this));
623 : #endif
624 : }
625 28894779 : }
626 :
627 24598979 : void Map::InitializeDescriptors(Isolate* isolate, DescriptorArray descriptors,
628 : LayoutDescriptor layout_desc) {
629 24598979 : SetInstanceDescriptors(isolate, descriptors,
630 24598979 : descriptors->number_of_descriptors());
631 :
632 : if (FLAG_unbox_double_fields) {
633 24598992 : set_layout_descriptor(layout_desc);
634 : #ifdef VERIFY_HEAP
635 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
636 : if (FLAG_verify_heap) {
637 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
638 : }
639 : #else
640 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
641 : #endif
642 24598987 : set_visitor_id(Map::GetVisitorId(*this));
643 : }
644 24598983 : }
645 :
646 : void Map::set_bit_field3(uint32_t bits) {
647 237122326 : RELAXED_WRITE_UINT32_FIELD(*this, kBitField3Offset, bits);
648 : }
649 :
650 : uint32_t Map::bit_field3() const {
651 1760666108 : return RELAXED_READ_UINT32_FIELD(*this, kBitField3Offset);
652 : }
653 :
654 : void Map::clear_padding() {
655 : if (FIELD_SIZE(kOptionalPaddingOffset) == 0) return;
656 : DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
657 56389228 : memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
658 : FIELD_SIZE(kOptionalPaddingOffset));
659 : }
660 :
661 : LayoutDescriptor Map::GetLayoutDescriptor() const {
662 : return FLAG_unbox_double_fields ? layout_descriptor()
663 : : LayoutDescriptor::FastPointerLayout();
664 : }
665 :
666 10328 : void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) {
667 10328 : DescriptorArray descriptors = instance_descriptors();
668 : int number_of_own_descriptors = NumberOfOwnDescriptors();
669 : DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
670 : {
671 : // The following two operations need to happen before the marking write
672 : // barrier.
673 10328 : descriptors->Append(desc);
674 10328 : SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
675 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
676 : number_of_own_descriptors + 1);
677 : }
678 : // Properly mark the map if the {desc} is an "interesting symbol".
679 10328 : if (desc->GetKey()->IsInterestingSymbol()) {
680 111 : set_may_have_interesting_symbols(true);
681 : }
682 : PropertyDetails details = desc->GetDetails();
683 10328 : if (details.location() == kField) {
684 : DCHECK_GT(UnusedPropertyFields(), 0);
685 3219 : AccountAddedPropertyField();
686 : }
687 :
688 : // This function does not support appending double field descriptors and
689 : // it should never try to (otherwise, layout descriptor must be updated too).
690 : #ifdef DEBUG
691 : DCHECK(details.location() != kField || !details.representation().IsDouble());
692 : #endif
693 10328 : }
694 :
695 127807471 : HeapObject Map::GetBackPointer() const {
696 : Object object = constructor_or_backpointer();
697 127807481 : if (object->IsMap()) {
698 76415814 : return Map::cast(object);
699 : }
700 51391667 : return GetReadOnlyRoots().undefined_value();
701 : }
702 :
703 8282237 : Map Map::ElementsTransitionMap() {
704 : DisallowHeapAllocation no_gc;
705 : // TODO(delphick): While it's safe to pass nullptr for Isolate* here as
706 : // SearchSpecial doesn't need it, this is really ugly. Perhaps factor out a
707 : // base class for methods not requiring an Isolate?
708 : return TransitionsAccessor(nullptr, *this, &no_gc)
709 8282247 : .SearchSpecial(GetReadOnlyRoots().elements_transition_symbol());
710 : }
711 :
712 : Object Map::prototype_info() const {
713 : DCHECK(is_prototype_map());
714 90628350 : return READ_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset);
715 : }
716 :
717 9446889 : void Map::set_prototype_info(Object value, WriteBarrierMode mode) {
718 9446889 : CHECK(is_prototype_map());
719 9446889 : WRITE_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset, value);
720 18893781 : CONDITIONAL_WRITE_BARRIER(*this, Map::kTransitionsOrPrototypeInfoOffset,
721 : value, mode);
722 9446891 : }
723 :
724 7340217 : void Map::SetBackPointer(Object value, WriteBarrierMode mode) {
725 7340217 : CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE);
726 7340217 : CHECK(value->IsMap());
727 14680442 : CHECK(GetBackPointer()->IsUndefined());
728 22020664 : CHECK_IMPLIES(value->IsMap(), Map::cast(value)->GetConstructor() ==
729 : constructor_or_backpointer());
730 7340222 : set_constructor_or_backpointer(value, mode);
731 7340220 : }
732 :
733 51090725 : ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
734 181236787 : ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
735 1358889054 : ACCESSORS(Map, constructor_or_backpointer, Object,
736 : kConstructorOrBackPointerOffset)
737 :
738 : bool Map::IsPrototypeValidityCellValid() const {
739 : Object validity_cell = prototype_validity_cell();
740 : Object value = validity_cell->IsSmi() ? Smi::cast(validity_cell)
741 1376690 : : Cell::cast(validity_cell)->value();
742 : return value == Smi::FromInt(Map::kPrototypeChainValid);
743 : }
744 :
745 87636675 : Object Map::GetConstructor() const {
746 : Object maybe_constructor = constructor_or_backpointer();
747 : // Follow any back pointers.
748 1851981615 : while (maybe_constructor->IsMap()) {
749 : maybe_constructor =
750 : Map::cast(maybe_constructor)->constructor_or_backpointer();
751 : }
752 87636703 : return maybe_constructor;
753 : }
754 :
755 2270993 : FunctionTemplateInfo Map::GetFunctionTemplateInfo() const {
756 2270993 : Object constructor = GetConstructor();
757 2270993 : if (constructor->IsJSFunction()) {
758 : DCHECK(JSFunction::cast(constructor)->shared()->IsApiFunction());
759 : return JSFunction::cast(constructor)->shared()->get_api_func_data();
760 : }
761 : DCHECK(constructor->IsFunctionTemplateInfo());
762 : return FunctionTemplateInfo::cast(constructor);
763 : }
764 :
765 9660308 : void Map::SetConstructor(Object constructor, WriteBarrierMode mode) {
766 : // Never overwrite a back pointer with a constructor.
767 9660308 : CHECK(!constructor_or_backpointer()->IsMap());
768 9660308 : set_constructor_or_backpointer(constructor, mode);
769 9660307 : }
770 :
771 416383 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map) {
772 : return CopyInitialMap(isolate, map, map->instance_size(),
773 : map->GetInObjectProperties(),
774 1249149 : map->UnusedPropertyFields());
775 : }
776 :
777 : bool Map::IsInobjectSlackTrackingInProgress() const {
778 6410 : return construction_counter() != Map::kNoSlackTracking;
779 : }
780 :
781 231241 : void Map::InobjectSlackTrackingStep(Isolate* isolate) {
782 : // Slack tracking should only be performed on an initial map.
783 : DCHECK(GetBackPointer()->IsUndefined());
784 231241 : if (!IsInobjectSlackTrackingInProgress()) return;
785 : int counter = construction_counter();
786 231241 : set_construction_counter(counter - 1);
787 231241 : if (counter == kSlackTrackingCounterEnd) {
788 294 : CompleteInobjectSlackTracking(isolate);
789 : }
790 : }
791 :
792 2390160 : int Map::SlackForArraySize(int old_size, int size_limit) {
793 2390160 : const int max_slack = size_limit - old_size;
794 2390160 : CHECK_LE(0, max_slack);
795 2390160 : if (old_size < 4) {
796 : DCHECK_LE(1, max_slack);
797 : return 1;
798 : }
799 2536040 : return Min(max_slack, old_size / 4);
800 : }
801 :
802 : int Map::InstanceSizeFromSlack(int slack) const {
803 274659 : return instance_size() - slack * kTaggedSize;
804 : }
805 :
806 : OBJECT_CONSTRUCTORS_IMPL(NormalizedMapCache, WeakFixedArray)
807 : CAST_ACCESSOR(NormalizedMapCache)
808 : NEVER_READ_ONLY_SPACE_IMPL(NormalizedMapCache)
809 :
810 : int NormalizedMapCache::GetIndex(Handle<Map> map) {
811 761963 : return map->Hash() % NormalizedMapCache::kEntries;
812 : }
813 :
814 : bool HeapObject::IsNormalizedMapCache() const {
815 : if (!IsWeakFixedArray()) return false;
816 : if (WeakFixedArray::cast(*this)->length() != NormalizedMapCache::kEntries) {
817 : return false;
818 : }
819 : return true;
820 : }
821 :
822 : } // namespace internal
823 : } // namespace v8
824 :
825 : #include "src/objects/object-macros-undef.h"
826 :
827 : #endif // V8_OBJECTS_MAP_INL_H_
|