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 16632 : OBJECT_CONSTRUCTORS_IMPL(Map, HeapObject)
31 16632 : CAST_ACCESSOR(Map)
32 :
33 473488 : DescriptorArray Map::instance_descriptors() const {
34 775061229 : return DescriptorArray::cast(READ_FIELD(*this, kDescriptorsOffset));
35 : }
36 :
37 : DescriptorArray Map::synchronized_instance_descriptors() const {
38 53682122 : return DescriptorArray::cast(ACQUIRE_READ_FIELD(*this, kDescriptorsOffset));
39 : }
40 :
41 84392189 : void Map::set_synchronized_instance_descriptors(DescriptorArray value,
42 : WriteBarrierMode mode) {
43 84392189 : RELEASE_WRITE_FIELD(*this, kDescriptorsOffset, value);
44 168784420 : CONDITIONAL_WRITE_BARRIER(*this, kDescriptorsOffset, value, mode);
45 84392107 : }
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 0 : SYNCHRONIZED_ACCESSORS_CHECKED(Map, layout_descriptor, LayoutDescriptor,
52 : kLayoutDescriptorOffset,
53 : FLAG_unbox_double_fields)
54 295720721 : 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 792036 : BIT_FIELD_ACCESSORS(Map, relaxed_bit_field, has_non_instance_prototype,
62 : Map::HasNonInstancePrototypeBit)
63 263128 : 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 181719 : 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 137075 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_extensible, Map::IsExtensibleBit)
77 4510401 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_prototype_map, Map::IsPrototypeMapBit)
78 45629 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_in_retained_map_list,
79 : Map::IsInRetainedMapListBit)
80 :
81 : // |bit_field3| fields.
82 20740574 : BIT_FIELD_ACCESSORS(Map, bit_field3, owns_descriptors, Map::OwnsDescriptorsBit)
83 62650604 : BIT_FIELD_ACCESSORS(Map, bit_field3, has_hidden_prototype,
84 : Map::HasHiddenPrototypeBit)
85 71614 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
86 501768 : 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 62892002 : BIT_FIELD_ACCESSORS(Map, bit_field3, new_target_is_base,
91 : Map::NewTargetIsBaseBit)
92 3680966 : BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_symbols,
93 : Map::MayHaveInterestingSymbolsBit)
94 2191922 : BIT_FIELD_ACCESSORS(Map, bit_field3, construction_counter,
95 : Map::ConstructionCounterBits)
96 :
97 1626139 : InterceptorInfo Map::GetNamedInterceptor() {
98 : DCHECK(has_named_interceptor());
99 1626139 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
100 1626139 : 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 637 : return !representation.IsHeapObject() || field_type->IsAny();
112 : }
113 :
114 : bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) {
115 17245341 : 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 17175971 : void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
125 : Isolate* isolate, InstanceType instance_type, PropertyConstness* constness,
126 : Representation* representation, Handle<FieldType>* field_type) {
127 17175971 : 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 128461 : if (representation->IsHeapObject()) {
134 : // The field type is either already Any or should become Any if it was
135 : // something else.
136 106857 : *field_type = FieldType::Any(isolate);
137 : }
138 : }
139 17175972 : }
140 :
141 : bool Map::IsUnboxedDoubleField(FieldIndex index) const {
142 : if (!FLAG_unbox_double_fields) return false;
143 : if (index.is_hidden_field() || !index.is_inobject()) return false;
144 : return !layout_descriptor()->IsTagged(index.property_index());
145 : }
146 :
147 18080042 : bool Map::TooManyFastProperties(StoreOrigin store_origin) const {
148 18080042 : if (UnusedPropertyFields() != 0) return false;
149 3160552 : if (is_prototype_map()) return false;
150 2616577 : if (store_origin == StoreOrigin::kNamed) {
151 2567062 : int limit = Max(kMaxFastProperties, GetInObjectProperties());
152 2567061 : 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 2567063 : int external = counts.mutable_count() - GetInObjectProperties();
157 5134124 : return external > limit || counts.GetTotal() > kMaxNumberOfDescriptors;
158 : } else {
159 49515 : int limit = Max(kFastPropertiesSoftLimit, GetInObjectProperties());
160 49515 : int external = NumberOfFields() - GetInObjectProperties();
161 49515 : return external > limit;
162 : }
163 : }
164 :
165 80371224 : PropertyDetails Map::GetLastDescriptorDetails() const {
166 80371224 : 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 163449451 : return number_of_own_descriptors - 1;
173 : }
174 :
175 2107659 : int Map::NumberOfOwnDescriptors() const {
176 2107659 : return NumberOfOwnDescriptorsBits::decode(bit_field3());
177 : }
178 :
179 84402455 : void Map::SetNumberOfOwnDescriptors(int number) {
180 : DCHECK_LE(number, instance_descriptors()->number_of_descriptors());
181 84402455 : CHECK_LE(static_cast<unsigned>(number),
182 : static_cast<unsigned>(kMaxNumberOfDescriptors));
183 : set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number));
184 84402455 : }
185 :
186 : int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); }
187 :
188 95537 : void Map::SetEnumLength(int length) {
189 95537 : if (length != kInvalidEnumCacheSentinel) {
190 : DCHECK_LE(length, NumberOfOwnDescriptors());
191 61897 : CHECK_LE(static_cast<unsigned>(length),
192 : static_cast<unsigned>(kMaxNumberOfDescriptors));
193 : }
194 : set_bit_field3(EnumLengthBits::update(bit_field3(), length));
195 95537 : }
196 :
197 39512908 : FixedArrayBase Map::GetInitialElements() const {
198 : FixedArrayBase result;
199 39512908 : 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 39512908 : return result;
213 : }
214 :
215 : VisitorId Map::visitor_id() const {
216 : return static_cast<VisitorId>(
217 1648127383 : RELAXED_READ_BYTE_FIELD(*this, kVisitorIdOffset));
218 : }
219 :
220 31289350 : void Map::set_visitor_id(VisitorId id) {
221 31289350 : CHECK_LT(static_cast<unsigned>(id), 256);
222 31289350 : RELAXED_WRITE_BYTE_FIELD(*this, kVisitorIdOffset, static_cast<byte>(id));
223 31289350 : }
224 :
225 2632956 : int Map::instance_size_in_words() const {
226 6067742009 : return RELAXED_READ_BYTE_FIELD(*this, kInstanceSizeInWordsOffset);
227 : }
228 :
229 2912 : void Map::set_instance_size_in_words(int value) {
230 31544746 : RELAXED_WRITE_BYTE_FIELD(*this, kInstanceSizeInWordsOffset,
231 : static_cast<byte>(value));
232 2912 : }
233 :
234 5166203 : int Map::instance_size() const {
235 2587924500 : return instance_size_in_words() << kTaggedSizeLog2;
236 : }
237 :
238 31544746 : void Map::set_instance_size(int value) {
239 31544746 : CHECK(IsAligned(value, kTaggedSize));
240 31544746 : value >>= kTaggedSizeLog2;
241 63089492 : CHECK_LT(static_cast<unsigned>(value), 256);
242 2912 : set_instance_size_in_words(value);
243 31544746 : }
244 :
245 24736 : int Map::inobject_properties_start_or_constructor_function_index() const {
246 1429382932 : return RELAXED_READ_BYTE_FIELD(
247 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset);
248 : }
249 :
250 31290708 : void Map::set_inobject_properties_start_or_constructor_function_index(
251 : int value) {
252 62581416 : CHECK_LT(static_cast<unsigned>(value), 256);
253 31290708 : RELAXED_WRITE_BYTE_FIELD(
254 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
255 : static_cast<byte>(value));
256 31290708 : }
257 :
258 24736 : int Map::GetInObjectPropertiesStartInWords() const {
259 : DCHECK(IsJSObjectMap());
260 24736 : return inobject_properties_start_or_constructor_function_index();
261 : }
262 :
263 31280554 : void Map::SetInObjectPropertiesStartInWords(int value) {
264 31280554 : CHECK(IsJSObjectMap());
265 31280554 : set_inobject_properties_start_or_constructor_function_index(value);
266 31280578 : }
267 :
268 370172340 : int Map::GetInObjectProperties() const {
269 : DCHECK(IsJSObjectMap());
270 370172340 : 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 1344 : void Map::SetConstructorFunctionIndex(int value) {
279 1344 : CHECK(IsPrimitiveMap());
280 1344 : set_inobject_properties_start_or_constructor_function_index(value);
281 1344 : }
282 :
283 24736 : int Map::GetInObjectPropertyOffset(int index) const {
284 305929372 : 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 : full_layout_descriptor);
293 : }
294 :
295 5137717 : InstanceType Map::instance_type() const {
296 : return static_cast<InstanceType>(
297 21777657643 : READ_UINT16_FIELD(*this, kInstanceTypeOffset));
298 : }
299 :
300 2912 : void Map::set_instance_type(InstanceType value) {
301 31141715 : WRITE_UINT16_FIELD(*this, kInstanceTypeOffset, value);
302 2912 : }
303 :
304 107491812 : int Map::UnusedPropertyFields() const {
305 : int value = used_or_unused_instance_size_in_words();
306 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
307 : int unused;
308 107491812 : if (value >= JSObject::kFieldsAdded) {
309 56842270 : 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 107491812 : return unused;
316 : }
317 :
318 360 : 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 360 : if (value >= JSObject::kFieldsAdded) {
324 315 : return instance_size_in_words() - value;
325 : }
326 : return 0;
327 : }
328 :
329 : int Map::used_or_unused_instance_size_in_words() const {
330 391786018 : return RELAXED_READ_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset);
331 : }
332 :
333 73699385 : void Map::set_used_or_unused_instance_size_in_words(int value) {
334 147398770 : CHECK_LE(static_cast<unsigned>(value), 255);
335 73699385 : RELAXED_WRITE_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset,
336 : static_cast<byte>(value));
337 73699385 : }
338 :
339 47012551 : int Map::UsedInstanceSize() const {
340 : int words = used_or_unused_instance_size_in_words();
341 47012551 : if (words < JSObject::kFieldsAdded) {
342 : // All in-object properties are used and the words is tracking the slack
343 : // in the property array.
344 5123731 : return instance_size();
345 : }
346 41888820 : return words * kTaggedSize;
347 : }
348 :
349 32090867 : void Map::SetInObjectUnusedPropertyFields(int value) {
350 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
351 32090867 : if (!IsJSObjectMap()) {
352 8794 : CHECK_EQ(0, value);
353 8794 : set_used_or_unused_instance_size_in_words(0);
354 : DCHECK_EQ(0, UnusedPropertyFields());
355 8794 : return;
356 : }
357 32082073 : CHECK_LE(0, value);
358 : DCHECK_LE(value, GetInObjectProperties());
359 32082073 : int used_inobject_properties = GetInObjectProperties() - value;
360 24736 : set_used_or_unused_instance_size_in_words(
361 32106814 : GetInObjectPropertyOffset(used_inobject_properties) / kTaggedSize);
362 : DCHECK_EQ(value, UnusedPropertyFields());
363 : }
364 :
365 220282 : void Map::SetOutOfObjectUnusedPropertyFields(int value) {
366 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
367 440564 : 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 220282 : set_used_or_unused_instance_size_in_words(value);
371 : DCHECK_EQ(value, UnusedPropertyFields());
372 220282 : }
373 :
374 24521399 : void Map::CopyUnusedPropertyFields(Map map) {
375 : set_used_or_unused_instance_size_in_words(
376 24521399 : map->used_or_unused_instance_size_in_words());
377 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
378 24521403 : }
379 :
380 315 : void Map::CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map map) {
381 : int value = map->used_or_unused_instance_size_in_words();
382 315 : 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 270 : value += instance_size_in_words() - map->instance_size_in_words();
386 : }
387 315 : set_used_or_unused_instance_size_in_words(value);
388 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
389 315 : }
390 :
391 16866572 : 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 16866572 : if (value >= JSObject::kFieldsAdded) {
400 8953236 : if (value == instance_size_in_words()) {
401 794985 : AccountAddedOutOfObjectPropertyField(0);
402 : } else {
403 : // The property is added in-object, so simply increment the counter.
404 8158251 : set_used_or_unused_instance_size_in_words(value + 1);
405 : }
406 : } else {
407 7913336 : AccountAddedOutOfObjectPropertyField(value);
408 : }
409 : DCHECK_EQ(new_unused, UnusedPropertyFields());
410 16866579 : }
411 :
412 8708319 : void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
413 8708319 : unused_in_property_array--;
414 8708319 : if (unused_in_property_array < 0) {
415 3139761 : unused_in_property_array += JSObject::kFieldsAdded;
416 : }
417 17416638 : CHECK_LT(static_cast<unsigned>(unused_in_property_array),
418 : JSObject::kFieldsAdded);
419 8708319 : set_used_or_unused_instance_size_in_words(unused_in_property_array);
420 : DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
421 8708321 : }
422 :
423 294253624 : byte Map::bit_field() const { return READ_BYTE_FIELD(*this, kBitFieldOffset); }
424 :
425 3024 : void Map::set_bit_field(byte value) {
426 56491024 : WRITE_BYTE_FIELD(*this, kBitFieldOffset, value);
427 3024 : }
428 :
429 : byte Map::relaxed_bit_field() const {
430 135960754 : return RELAXED_READ_BYTE_FIELD(*this, kBitFieldOffset);
431 : }
432 :
433 : void Map::set_relaxed_bit_field(byte value) {
434 265677 : RELAXED_WRITE_BYTE_FIELD(*this, kBitFieldOffset, value);
435 : }
436 :
437 3091 : byte Map::bit_field2() const {
438 760924928 : return READ_BYTE_FIELD(*this, kBitField2Offset);
439 : }
440 :
441 6003 : void Map::set_bit_field2(byte value) {
442 92464317 : WRITE_BYTE_FIELD(*this, kBitField2Offset, value);
443 6003 : }
444 :
445 442815 : bool Map::is_abandoned_prototype_map() const {
446 464145 : return is_prototype_map() && !owns_descriptors();
447 : }
448 :
449 31827246 : bool Map::should_be_fast_prototype_map() const {
450 31827229 : if (!prototype_info()->IsPrototypeInfo()) return false;
451 : return PrototypeInfo::cast(prototype_info())->should_be_fast_map();
452 : }
453 :
454 31468648 : void Map::set_elements_kind(ElementsKind elements_kind) {
455 31471683 : CHECK_LT(static_cast<int>(elements_kind), kElementsKindCount);
456 31468648 : set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
457 31468648 : }
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 766379 : void Map::set_is_dictionary_map(bool value) {
504 : uint32_t new_bit_field3 = IsDictionaryMapBit::update(bit_field3(), value);
505 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, value);
506 : set_bit_field3(new_bit_field3);
507 766379 : }
508 :
509 : bool Map::is_dictionary_map() const {
510 : return IsDictionaryMapBit::decode(bit_field3());
511 : }
512 :
513 18618303 : void Map::mark_unstable() {
514 224 : set_bit_field3(IsUnstableBit::update(bit_field3(), true));
515 18618303 : }
516 :
517 529163 : bool Map::is_stable() const { return !IsUnstableBit::decode(bit_field3()); }
518 :
519 25177498 : bool Map::CanBeDeprecated() const {
520 : int descriptor = LastAdded();
521 149921334 : for (int i = 0; i <= descriptor; i++) {
522 70362230 : PropertyDetails details = instance_descriptors()->GetDetails(i);
523 70362224 : if (details.representation().IsNone()) return true;
524 70362925 : if (details.representation().IsSmi()) return true;
525 67550379 : if (details.representation().IsDouble()) return true;
526 67549635 : if (details.representation().IsHeapObject()) return true;
527 75987583 : if (details.kind() == kData && details.location() == kDescriptor) {
528 : return true;
529 : }
530 : }
531 : return false;
532 : }
533 :
534 34630141 : void Map::NotifyLeafMapLayoutChange(Isolate* isolate) {
535 34630141 : if (is_stable()) {
536 18618083 : mark_unstable();
537 37236141 : dependent_code()->DeoptimizeDependentCodeGroup(
538 18618080 : isolate, DependentCode::kPrototypeCheckGroup);
539 : }
540 34630119 : }
541 :
542 : bool Map::CanTransition() const {
543 : // Only JSObject and subtypes have map transitions and back pointers.
544 : return InstanceTypeChecker::IsJSObject(instance_type());
545 : }
546 :
547 : #define DEF_TESTER(Type, ...) \
548 : bool Map::Is##Type##Map() const { \
549 : return InstanceTypeChecker::Is##Type(instance_type()); \
550 : }
551 55192 : INSTANCE_TYPE_CHECKERS(DEF_TESTER)
552 : #undef DEF_TESTER
553 :
554 : bool Map::IsBooleanMap() const {
555 : return *this == GetReadOnlyRoots().boolean_map();
556 : }
557 :
558 : bool Map::IsNullOrUndefinedMap() const {
559 1125 : return *this == GetReadOnlyRoots().null_map() ||
560 : *this == GetReadOnlyRoots().undefined_map();
561 : }
562 :
563 1344 : bool Map::IsPrimitiveMap() const {
564 1344 : return instance_type() <= LAST_PRIMITIVE_TYPE;
565 : }
566 :
567 401366135 : Object Map::prototype() const { return READ_FIELD(*this, kPrototypeOffset); }
568 :
569 31237858 : void Map::set_prototype(Object value, WriteBarrierMode mode) {
570 : DCHECK(value->IsNull() || value->IsJSReceiver());
571 62376228 : WRITE_FIELD(*this, kPrototypeOffset, value);
572 56960455 : CONDITIONAL_WRITE_BARRIER(*this, kPrototypeOffset, value, mode);
573 31237839 : }
574 :
575 : LayoutDescriptor Map::layout_descriptor_gc_safe() const {
576 : DCHECK(FLAG_unbox_double_fields);
577 : // The loaded value can be dereferenced on background thread to load the
578 : // bitmap. We need acquire load in order to ensure that the bitmap
579 : // initializing stores are also visible to the background thread.
580 : Object layout_desc = ACQUIRE_READ_FIELD(*this, kLayoutDescriptorOffset);
581 : return LayoutDescriptor::cast_gc_safe(layout_desc);
582 : }
583 :
584 : bool Map::HasFastPointerLayout() const {
585 : DCHECK(FLAG_unbox_double_fields);
586 : // The loaded value is used for SMI check only and is not dereferenced,
587 : // so relaxed load is safe.
588 : Object layout_desc = RELAXED_READ_FIELD(*this, kLayoutDescriptorOffset);
589 : return LayoutDescriptor::IsFastPointerLayout(layout_desc);
590 : }
591 :
592 : void Map::UpdateDescriptors(Isolate* isolate, DescriptorArray descriptors,
593 : LayoutDescriptor layout_desc,
594 : int number_of_own_descriptors) {
595 28907038 : SetInstanceDescriptors(isolate, descriptors, number_of_own_descriptors);
596 : if (FLAG_unbox_double_fields) {
597 : if (layout_descriptor()->IsSlowLayout()) {
598 : set_layout_descriptor(layout_desc);
599 : }
600 : #ifdef VERIFY_HEAP
601 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
602 : if (FLAG_verify_heap) {
603 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
604 : CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
605 : }
606 : #else
607 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
608 : DCHECK(visitor_id() == Map::GetVisitorId(*this));
609 : #endif
610 : }
611 : }
612 :
613 24310368 : void Map::InitializeDescriptors(Isolate* isolate, DescriptorArray descriptors,
614 : LayoutDescriptor layout_desc) {
615 24310368 : SetInstanceDescriptors(isolate, descriptors,
616 24310368 : descriptors->number_of_descriptors());
617 :
618 : if (FLAG_unbox_double_fields) {
619 : set_layout_descriptor(layout_desc);
620 : #ifdef VERIFY_HEAP
621 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
622 : if (FLAG_verify_heap) {
623 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
624 : }
625 : #else
626 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
627 : #endif
628 : set_visitor_id(Map::GetVisitorId(*this));
629 : }
630 24310336 : }
631 :
632 3136 : void Map::set_bit_field3(uint32_t bits) {
633 236550098 : RELAXED_WRITE_UINT32_FIELD(*this, kBitField3Offset, bits);
634 3136 : }
635 :
636 224 : uint32_t Map::bit_field3() const {
637 1797056520 : return RELAXED_READ_UINT32_FIELD(*this, kBitField3Offset);
638 : }
639 :
640 : void Map::clear_padding() {
641 : if (FIELD_SIZE(kOptionalPaddingOffset) == 0) return;
642 : DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
643 : memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
644 : FIELD_SIZE(kOptionalPaddingOffset));
645 : }
646 :
647 : LayoutDescriptor Map::GetLayoutDescriptor() const {
648 : return FLAG_unbox_double_fields ? layout_descriptor()
649 : : LayoutDescriptor::FastPointerLayout();
650 : }
651 :
652 10328 : void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) {
653 10328 : DescriptorArray descriptors = instance_descriptors();
654 : int number_of_own_descriptors = NumberOfOwnDescriptors();
655 : DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
656 : {
657 : // The following two operations need to happen before the marking write
658 : // barrier.
659 10328 : descriptors->Append(desc);
660 10328 : SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
661 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
662 : number_of_own_descriptors + 1);
663 : }
664 : // Properly mark the map if the {desc} is an "interesting symbol".
665 10328 : if (desc->GetKey()->IsInterestingSymbol()) {
666 111 : set_may_have_interesting_symbols(true);
667 : }
668 : PropertyDetails details = desc->GetDetails();
669 10328 : if (details.location() == kField) {
670 : DCHECK_GT(UnusedPropertyFields(), 0);
671 3219 : AccountAddedPropertyField();
672 : }
673 :
674 : // This function does not support appending double field descriptors and
675 : // it should never try to (otherwise, layout descriptor must be updated too).
676 : #ifdef DEBUG
677 : DCHECK(details.location() != kField || !details.representation().IsDouble());
678 : #endif
679 10328 : }
680 :
681 127051545 : Object Map::GetBackPointer() const {
682 : Object object = constructor_or_backpointer();
683 127051564 : if (object->IsMap()) {
684 76447456 : return object;
685 : }
686 50604108 : return GetReadOnlyRoots().undefined_value();
687 : }
688 :
689 8264899 : Map Map::ElementsTransitionMap() {
690 : DisallowHeapAllocation no_gc;
691 : // TODO(delphick): While it's safe to pass nullptr for Isolate* here as
692 : // SearchSpecial doesn't need it, this is really ugly. Perhaps factor out a
693 : // base class for methods not requiring an Isolate?
694 : return TransitionsAccessor(nullptr, *this, &no_gc)
695 8264915 : .SearchSpecial(GetReadOnlyRoots().elements_transition_symbol());
696 : }
697 :
698 : Object Map::prototype_info() const {
699 : DCHECK(is_prototype_map());
700 89710424 : return READ_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset);
701 : }
702 :
703 9340827 : void Map::set_prototype_info(Object value, WriteBarrierMode mode) {
704 9340827 : CHECK(is_prototype_map());
705 9340827 : WRITE_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset, value);
706 18681658 : CONDITIONAL_WRITE_BARRIER(*this, Map::kTransitionsOrPrototypeInfoOffset,
707 : value, mode);
708 9340833 : }
709 :
710 7344098 : void Map::SetBackPointer(Object value, WriteBarrierMode mode) {
711 7344098 : CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE);
712 7344098 : CHECK(value->IsMap());
713 14688202 : CHECK(GetBackPointer()->IsUndefined());
714 22032307 : CHECK_IMPLIES(value->IsMap(), Map::cast(value)->GetConstructor() ==
715 : constructor_or_backpointer());
716 7344103 : set_constructor_or_backpointer(value, mode);
717 7344105 : }
718 :
719 50927201 : ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
720 182209644 : ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
721 1356930218 : ACCESSORS(Map, constructor_or_backpointer, Object,
722 : kConstructorOrBackPointerOffset)
723 :
724 1418185 : bool Map::IsPrototypeValidityCellValid() const {
725 : Object validity_cell = prototype_validity_cell();
726 : Object value = validity_cell->IsSmi() ? Smi::cast(validity_cell)
727 1418185 : : Cell::cast(validity_cell)->value();
728 1418185 : return value == Smi::FromInt(Map::kPrototypeChainValid);
729 : }
730 :
731 86413611 : Object Map::GetConstructor() const {
732 : Object maybe_constructor = constructor_or_backpointer();
733 : // Follow any back pointers.
734 1855824255 : while (maybe_constructor->IsMap()) {
735 : maybe_constructor =
736 : Map::cast(maybe_constructor)->constructor_or_backpointer();
737 : }
738 86413559 : return maybe_constructor;
739 : }
740 :
741 2294555 : FunctionTemplateInfo Map::GetFunctionTemplateInfo() const {
742 2294555 : Object constructor = GetConstructor();
743 2294555 : if (constructor->IsJSFunction()) {
744 : DCHECK(JSFunction::cast(constructor)->shared()->IsApiFunction());
745 : return JSFunction::cast(constructor)->shared()->get_api_func_data();
746 : }
747 : DCHECK(constructor->IsFunctionTemplateInfo());
748 : return FunctionTemplateInfo::cast(constructor);
749 : }
750 :
751 9444996 : void Map::SetConstructor(Object constructor, WriteBarrierMode mode) {
752 : // Never overwrite a back pointer with a constructor.
753 9444996 : CHECK(!constructor_or_backpointer()->IsMap());
754 9444996 : set_constructor_or_backpointer(constructor, mode);
755 9445001 : }
756 :
757 418264 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map) {
758 : return CopyInitialMap(isolate, map, map->instance_size(),
759 : map->GetInObjectProperties(),
760 1254792 : map->UnusedPropertyFields());
761 : }
762 :
763 : bool Map::IsInobjectSlackTrackingInProgress() const {
764 6415 : return construction_counter() != Map::kNoSlackTracking;
765 : }
766 :
767 230087 : void Map::InobjectSlackTrackingStep(Isolate* isolate) {
768 : // Slack tracking should only be performed on an initial map.
769 : DCHECK(GetBackPointer()->IsUndefined());
770 230087 : if (!IsInobjectSlackTrackingInProgress()) return;
771 : int counter = construction_counter();
772 230087 : set_construction_counter(counter - 1);
773 230087 : if (counter == kSlackTrackingCounterEnd) {
774 288 : CompleteInobjectSlackTracking(isolate);
775 : }
776 : }
777 :
778 2381246 : int Map::SlackForArraySize(int old_size, int size_limit) {
779 2381246 : const int max_slack = size_limit - old_size;
780 2381246 : CHECK_LE(0, max_slack);
781 2381246 : if (old_size < 4) {
782 : DCHECK_LE(1, max_slack);
783 : return 1;
784 : }
785 2527030 : return Min(max_slack, old_size / 4);
786 : }
787 :
788 : int Map::InstanceSizeFromSlack(int slack) const {
789 261858 : return instance_size() - slack * kTaggedSize;
790 : }
791 :
792 : OBJECT_CONSTRUCTORS_IMPL(NormalizedMapCache, WeakFixedArray)
793 : CAST_ACCESSOR(NormalizedMapCache)
794 : NEVER_READ_ONLY_SPACE_IMPL(NormalizedMapCache)
795 :
796 : int NormalizedMapCache::GetIndex(Handle<Map> map) {
797 756903 : return map->Hash() % NormalizedMapCache::kEntries;
798 : }
799 :
800 : bool HeapObject::IsNormalizedMapCache() const {
801 : if (!IsWeakFixedArray()) return false;
802 : if (WeakFixedArray::cast(*this)->length() != NormalizedMapCache::kEntries) {
803 : return false;
804 : }
805 : return true;
806 : }
807 :
808 : } // namespace internal
809 : } // namespace v8
810 :
811 : #include "src/objects/object-macros-undef.h"
812 :
813 : #endif // V8_OBJECTS_MAP_INL_H_
|