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 3866267432 : OBJECT_CONSTRUCTORS_IMPL(Map, HeapObject)
31 1935020386 : CAST_ACCESSOR(Map)
32 :
33 765989711 : DescriptorArray Map::instance_descriptors() const {
34 1531979436 : return DescriptorArray::cast(READ_FIELD(*this, kDescriptorsOffset));
35 : }
36 :
37 28443310 : DescriptorArray Map::synchronized_instance_descriptors() const {
38 56907107 : return DescriptorArray::cast(ACQUIRE_READ_FIELD(*this, kDescriptorsOffset));
39 : }
40 :
41 79226050 : void Map::set_synchronized_instance_descriptors(DescriptorArray value,
42 : WriteBarrierMode mode) {
43 79226050 : RELEASE_WRITE_FIELD(*this, kDescriptorsOffset, value);
44 237678165 : CONDITIONAL_WRITE_BARRIER(*this, kDescriptorsOffset, value, mode);
45 79226061 : }
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 439047457 : SYNCHRONIZED_ACCESSORS_CHECKED(Map, layout_descriptor, LayoutDescriptor,
52 : kLayoutDescriptorOffset,
53 : FLAG_unbox_double_fields)
54 278788974 : WEAK_ACCESSORS(Map, raw_transitions, kTransitionsOrPrototypeInfoOffset)
55 :
56 : // |bit_field| fields.
57 168327 : BIT_FIELD_ACCESSORS(Map, bit_field, has_non_instance_prototype,
58 : Map::HasNonInstancePrototypeBit)
59 27680596 : BIT_FIELD_ACCESSORS(Map, bit_field, is_callable, Map::IsCallableBit)
60 336 : BIT_FIELD_ACCESSORS(Map, bit_field, has_named_interceptor,
61 : Map::HasNamedInterceptorBit)
62 252 : BIT_FIELD_ACCESSORS(Map, bit_field, has_indexed_interceptor,
63 : Map::HasIndexedInterceptorBit)
64 175869632 : BIT_FIELD_ACCESSORS(Map, bit_field, is_undetectable, Map::IsUndetectableBit)
65 71244566 : BIT_FIELD_ACCESSORS(Map, bit_field, is_access_check_needed,
66 : Map::IsAccessCheckNeededBit)
67 12804813 : BIT_FIELD_ACCESSORS(Map, bit_field, is_constructor, Map::IsConstructorBit)
68 1554 : BIT_FIELD_ACCESSORS(Map, bit_field, has_prototype_slot,
69 : Map::HasPrototypeSlotBit)
70 :
71 : // |bit_field2| fields.
72 136329 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_extensible, Map::IsExtensibleBit)
73 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_prototype_map, Map::IsPrototypeMapBit)
74 : BIT_FIELD_ACCESSORS(Map, bit_field2, is_in_retained_map_list,
75 : Map::IsInRetainedMapListBit)
76 :
77 : // |bit_field3| fields.
78 50795392 : BIT_FIELD_ACCESSORS(Map, bit_field3, owns_descriptors, Map::OwnsDescriptorsBit)
79 164181178 : BIT_FIELD_ACCESSORS(Map, bit_field3, has_hidden_prototype,
80 : Map::HasHiddenPrototypeBit)
81 70422248 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
82 720960 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_migration_target,
83 : Map::IsMigrationTargetBit)
84 370174 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_immutable_proto,
85 : Map::IsImmutablePrototypeBit)
86 68896006 : BIT_FIELD_ACCESSORS(Map, bit_field3, new_target_is_base,
87 : Map::NewTargetIsBaseBit)
88 3586170 : BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_symbols,
89 : Map::MayHaveInterestingSymbolsBit)
90 2167130 : BIT_FIELD_ACCESSORS(Map, bit_field3, construction_counter,
91 : Map::ConstructionCounterBits)
92 :
93 1530911 : InterceptorInfo Map::GetNamedInterceptor() {
94 : DCHECK(has_named_interceptor());
95 1530911 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
96 3061822 : return InterceptorInfo::cast(info->GetNamedPropertyHandler());
97 : }
98 :
99 621270 : InterceptorInfo Map::GetIndexedInterceptor() {
100 : DCHECK(has_indexed_interceptor());
101 621270 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
102 1242540 : return InterceptorInfo::cast(info->GetIndexedPropertyHandler());
103 : }
104 :
105 : bool Map::IsMostGeneralFieldType(Representation representation,
106 : FieldType field_type) {
107 671 : return !representation.IsHeapObject() || field_type->IsAny();
108 : }
109 :
110 : bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) {
111 16334154 : return instance_type == JS_ARRAY_TYPE || instance_type == JS_VALUE_TYPE ||
112 : instance_type == JS_ARGUMENTS_TYPE;
113 : }
114 :
115 : bool Map::CanHaveFastTransitionableElementsKind() const {
116 : return CanHaveFastTransitionableElementsKind(instance_type());
117 : }
118 :
119 : // static
120 16262067 : void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
121 : Isolate* isolate, InstanceType instance_type, PropertyConstness* constness,
122 : Representation* representation, Handle<FieldType>* field_type) {
123 16262067 : if (CanHaveFastTransitionableElementsKind(instance_type)) {
124 : // We don't support propagation of field generalization through elements
125 : // kind transitions because they are inserted into the transition tree
126 : // before field transitions. In order to avoid complexity of handling
127 : // such a case we ensure that all maps with transitionable elements kinds
128 : // have the most general field type.
129 128241 : if (representation->IsHeapObject()) {
130 : // The field type is either already Any or should become Any if it was
131 : // something else.
132 120135 : *field_type = FieldType::Any(isolate);
133 : }
134 : }
135 16262067 : }
136 :
137 101721198 : bool Map::IsUnboxedDoubleField(FieldIndex index) const {
138 : if (!FLAG_unbox_double_fields) return false;
139 203442397 : if (index.is_hidden_field() || !index.is_inobject()) return false;
140 38090096 : return !layout_descriptor()->IsTagged(index.property_index());
141 : }
142 :
143 16261575 : bool Map::TooManyFastProperties(StoreOrigin store_origin) const {
144 16261575 : if (UnusedPropertyFields() != 0) return false;
145 2947524 : if (is_prototype_map()) return false;
146 2497467 : if (store_origin == StoreOrigin::kNamed) {
147 2448057 : int limit = Max(kMaxFastProperties, GetInObjectProperties());
148 2448057 : FieldCounts counts = GetFieldCounts();
149 : // Only count mutable fields so that objects with large numbers of
150 : // constant functions do not go to dictionary mode. That would be bad
151 : // because such objects have often been used as modules.
152 2448057 : int external = counts.mutable_count() - GetInObjectProperties();
153 4896110 : return external > limit || counts.GetTotal() > kMaxNumberOfDescriptors;
154 : } else {
155 49410 : int limit = Max(kFastPropertiesSoftLimit, GetInObjectProperties());
156 49410 : int external = NumberOfFields() - GetInObjectProperties();
157 49410 : return external > limit;
158 : }
159 : }
160 :
161 79138120 : PropertyDetails Map::GetLastDescriptorDetails() const {
162 79138120 : return instance_descriptors()->GetDetails(LastAdded());
163 : }
164 :
165 161599701 : int Map::LastAdded() const {
166 : int number_of_own_descriptors = NumberOfOwnDescriptors();
167 : DCHECK_GT(number_of_own_descriptors, 0);
168 161599701 : return number_of_own_descriptors - 1;
169 : }
170 :
171 123427067 : int Map::NumberOfOwnDescriptors() const {
172 123427067 : return NumberOfOwnDescriptorsBits::decode(bit_field3());
173 : }
174 :
175 79236386 : void Map::SetNumberOfOwnDescriptors(int number) {
176 : DCHECK_LE(number, instance_descriptors()->number_of_descriptors());
177 79236386 : CHECK_LE(static_cast<unsigned>(number),
178 : static_cast<unsigned>(kMaxNumberOfDescriptors));
179 79236386 : set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number));
180 79236384 : }
181 :
182 : int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); }
183 :
184 95606 : void Map::SetEnumLength(int length) {
185 95606 : if (length != kInvalidEnumCacheSentinel) {
186 : DCHECK_LE(length, NumberOfOwnDescriptors());
187 61372 : CHECK_LE(static_cast<unsigned>(length),
188 : static_cast<unsigned>(kMaxNumberOfDescriptors));
189 : }
190 95606 : set_bit_field3(EnumLengthBits::update(bit_field3(), length));
191 95606 : }
192 :
193 37820767 : FixedArrayBase Map::GetInitialElements() const {
194 : FixedArrayBase result;
195 37820767 : if (has_fast_elements() || has_fast_string_wrapper_elements()) {
196 75626545 : result = GetReadOnlyRoots().empty_fixed_array();
197 7502 : } else if (has_fast_sloppy_arguments_elements()) {
198 0 : result = GetReadOnlyRoots().empty_sloppy_arguments_elements();
199 7502 : } else if (has_fixed_typed_array_elements()) {
200 : result =
201 8362 : GetReadOnlyRoots().EmptyFixedTypedArrayForTypedArray(elements_kind());
202 3321 : } else if (has_dictionary_elements()) {
203 6642 : result = GetReadOnlyRoots().empty_slow_element_dictionary();
204 : } else {
205 0 : UNREACHABLE();
206 : }
207 : DCHECK(!ObjectInYoungGeneration(result));
208 37820782 : return result;
209 : }
210 :
211 864989661 : VisitorId Map::visitor_id() const {
212 : return static_cast<VisitorId>(
213 1800209340 : RELAXED_READ_BYTE_FIELD(*this, kVisitorIdOffset));
214 : }
215 :
216 50875415 : void Map::set_visitor_id(VisitorId id) {
217 50875415 : CHECK_LT(static_cast<unsigned>(id), 256);
218 101747918 : RELAXED_WRITE_BYTE_FIELD(*this, kVisitorIdOffset, static_cast<byte>(id));
219 50875415 : }
220 :
221 1070117 : int Map::instance_size_in_words() const {
222 6261323148 : return RELAXED_READ_BYTE_FIELD(*this, kInstanceSizeInWordsOffset);
223 : }
224 :
225 2912 : void Map::set_instance_size_in_words(int value) {
226 28778223 : RELAXED_WRITE_BYTE_FIELD(*this, kInstanceSizeInWordsOffset,
227 : static_cast<byte>(value));
228 2912 : }
229 :
230 38782099 : int Map::instance_size() const {
231 2740635146 : return instance_size_in_words() << kTaggedSizeLog2;
232 : }
233 :
234 28778223 : void Map::set_instance_size(int value) {
235 28778223 : CHECK(IsAligned(value, kTaggedSize));
236 28778223 : value >>= kTaggedSizeLog2;
237 28781135 : CHECK_LT(static_cast<unsigned>(value), 256);
238 2912 : set_instance_size_in_words(value);
239 28778223 : }
240 :
241 11421 : int Map::inobject_properties_start_or_constructor_function_index() const {
242 1028118417 : return RELAXED_READ_BYTE_FIELD(
243 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset);
244 : }
245 :
246 28517870 : void Map::set_inobject_properties_start_or_constructor_function_index(
247 : int value) {
248 28522294 : CHECK_LT(static_cast<unsigned>(value), 256);
249 57031316 : RELAXED_WRITE_BYTE_FIELD(
250 : *this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
251 : static_cast<byte>(value));
252 28517870 : }
253 :
254 11421 : int Map::GetInObjectPropertiesStartInWords() const {
255 : DCHECK(IsJSObjectMap());
256 11421 : return inobject_properties_start_or_constructor_function_index();
257 : }
258 :
259 28507336 : void Map::SetInObjectPropertiesStartInWords(int value) {
260 28507336 : CHECK(IsJSObjectMap());
261 28507336 : set_inobject_properties_start_or_constructor_function_index(value);
262 28507346 : }
263 :
264 327187937 : int Map::GetInObjectProperties() const {
265 : DCHECK(IsJSObjectMap());
266 327187937 : return instance_size_in_words() - GetInObjectPropertiesStartInWords();
267 : }
268 :
269 : int Map::GetConstructorFunctionIndex() const {
270 : DCHECK(IsPrimitiveMap());
271 : return inobject_properties_start_or_constructor_function_index();
272 : }
273 :
274 1512 : void Map::SetConstructorFunctionIndex(int value) {
275 1512 : CHECK(IsPrimitiveMap());
276 1512 : set_inobject_properties_start_or_constructor_function_index(value);
277 1512 : }
278 :
279 11421 : int Map::GetInObjectPropertyOffset(int index) const {
280 149133048 : return (GetInObjectPropertiesStartInWords() + index) * kTaggedSize;
281 : }
282 :
283 : Handle<Map> Map::AddMissingTransitionsForTesting(
284 : Isolate* isolate, Handle<Map> split_map,
285 : Handle<DescriptorArray> descriptors,
286 : Handle<LayoutDescriptor> full_layout_descriptor) {
287 : return AddMissingTransitions(isolate, split_map, descriptors,
288 65 : full_layout_descriptor);
289 : }
290 :
291 11162844132 : InstanceType Map::instance_type() const {
292 : return static_cast<InstanceType>(
293 21385426433 : READ_UINT16_FIELD(*this, kInstanceTypeOffset));
294 : }
295 :
296 2912 : void Map::set_instance_type(InstanceType value) {
297 28370564 : WRITE_UINT16_FIELD(*this, kInstanceTypeOffset, value);
298 2912 : }
299 :
300 102590872 : int Map::UnusedPropertyFields() const {
301 : int value = used_or_unused_instance_size_in_words();
302 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
303 : int unused;
304 102590872 : if (value >= JSObject::kFieldsAdded) {
305 55151821 : unused = instance_size_in_words() - value;
306 : } else {
307 : // For out of object properties "used_or_unused_instance_size_in_words"
308 : // byte encodes the slack in the property array.
309 : unused = value;
310 : }
311 102590872 : return unused;
312 : }
313 :
314 351 : int Map::UnusedInObjectProperties() const {
315 : // Like Map::UnusedPropertyFields(), but returns 0 for out of object
316 : // properties.
317 : int value = used_or_unused_instance_size_in_words();
318 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
319 351 : if (value >= JSObject::kFieldsAdded) {
320 306 : return instance_size_in_words() - value;
321 : }
322 : return 0;
323 : }
324 :
325 : int Map::used_or_unused_instance_size_in_words() const {
326 385951020 : return RELAXED_READ_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset);
327 : }
328 :
329 68030216 : void Map::set_used_or_unused_instance_size_in_words(int value) {
330 68044497 : CHECK_LE(static_cast<unsigned>(value), 255);
331 136046151 : RELAXED_WRITE_BYTE_FIELD(*this, kUsedOrUnusedInstanceSizeInWordsOffset,
332 : static_cast<byte>(value));
333 68030216 : }
334 :
335 51886463 : int Map::UsedInstanceSize() const {
336 : int words = used_or_unused_instance_size_in_words();
337 51886463 : if (words < JSObject::kFieldsAdded) {
338 : // All in-object properties are used and the words is tracking the slack
339 : // in the property array.
340 5555476 : return instance_size();
341 : }
342 46330987 : return words * kTaggedSize;
343 : }
344 :
345 29313143 : void Map::SetInObjectUnusedPropertyFields(int value) {
346 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
347 29313143 : if (!IsJSObjectMap()) {
348 9018 : CHECK_EQ(0, value);
349 9018 : set_used_or_unused_instance_size_in_words(0);
350 : DCHECK_EQ(0, UnusedPropertyFields());
351 29322165 : return;
352 : }
353 29304125 : CHECK_LE(0, value);
354 : DCHECK_LE(value, GetInObjectProperties());
355 29304125 : int used_inobject_properties = GetInObjectProperties() - value;
356 : set_used_or_unused_instance_size_in_words(
357 29304129 : GetInObjectPropertyOffset(used_inobject_properties) / kTaggedSize);
358 : DCHECK_EQ(value, UnusedPropertyFields());
359 : }
360 :
361 219256 : void Map::SetOutOfObjectUnusedPropertyFields(int value) {
362 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
363 219256 : CHECK_LT(static_cast<unsigned>(value), JSObject::kFieldsAdded);
364 : // For out of object properties "used_instance_size_in_words" byte encodes
365 : // the slack in the property array.
366 219256 : set_used_or_unused_instance_size_in_words(value);
367 : DCHECK_EQ(value, UnusedPropertyFields());
368 219256 : }
369 :
370 22535417 : void Map::CopyUnusedPropertyFields(Map map) {
371 : set_used_or_unused_instance_size_in_words(
372 22535417 : map->used_or_unused_instance_size_in_words());
373 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
374 22535415 : }
375 :
376 306 : void Map::CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map map) {
377 : int value = map->used_or_unused_instance_size_in_words();
378 306 : if (value >= JSValue::kFieldsAdded) {
379 : // Unused in-object fields. Adjust the offset from the object’s start
380 : // so it matches the distance to the object’s end.
381 261 : value += instance_size_in_words() - map->instance_size_in_words();
382 : }
383 306 : set_used_or_unused_instance_size_in_words(value);
384 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
385 306 : }
386 :
387 15962101 : void Map::AccountAddedPropertyField() {
388 : // Update used instance size and unused property fields number.
389 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
390 : #ifdef DEBUG
391 : int new_unused = UnusedPropertyFields() - 1;
392 : if (new_unused < 0) new_unused += JSObject::kFieldsAdded;
393 : #endif
394 : int value = used_or_unused_instance_size_in_words();
395 15962101 : if (value >= JSObject::kFieldsAdded) {
396 8221031 : if (value == instance_size_in_words()) {
397 609211 : AccountAddedOutOfObjectPropertyField(0);
398 : } else {
399 : // The property is added in-object, so simply increment the counter.
400 7611820 : set_used_or_unused_instance_size_in_words(value + 1);
401 : }
402 : } else {
403 7741070 : AccountAddedOutOfObjectPropertyField(value);
404 : }
405 : DCHECK_EQ(new_unused, UnusedPropertyFields());
406 15962101 : }
407 :
408 8350281 : void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
409 8350281 : unused_in_property_array--;
410 8350281 : if (unused_in_property_array < 0) {
411 2928341 : unused_in_property_array += JSObject::kFieldsAdded;
412 : }
413 8350281 : CHECK_LT(static_cast<unsigned>(unused_in_property_array),
414 : JSObject::kFieldsAdded);
415 8350281 : set_used_or_unused_instance_size_in_words(unused_in_property_array);
416 : DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
417 8350281 : }
418 :
419 351052314 : byte Map::bit_field() const { return READ_BYTE_FIELD(*this, kBitFieldOffset); }
420 :
421 3024 : void Map::set_bit_field(byte value) {
422 51985486 : WRITE_BYTE_FIELD(*this, kBitFieldOffset, value);
423 3024 : }
424 :
425 3091 : byte Map::bit_field2() const {
426 736233620 : return READ_BYTE_FIELD(*this, kBitField2Offset);
427 : }
428 :
429 6003 : void Map::set_bit_field2(byte value) {
430 84748245 : WRITE_BYTE_FIELD(*this, kBitField2Offset, value);
431 6003 : }
432 :
433 440292 : bool Map::is_abandoned_prototype_map() const {
434 440292 : return is_prototype_map() && !owns_descriptors();
435 : }
436 :
437 28196174 : bool Map::should_be_fast_prototype_map() const {
438 56392367 : if (!prototype_info()->IsPrototypeInfo()) return false;
439 24741933 : return PrototypeInfo::cast(prototype_info())->should_be_fast_map();
440 : }
441 :
442 28699550 : void Map::set_elements_kind(ElementsKind elements_kind) {
443 28702585 : CHECK_LT(static_cast<int>(elements_kind), kElementsKindCount);
444 28699550 : set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
445 28699550 : }
446 :
447 465883 : ElementsKind Map::elements_kind() const {
448 465883 : return Map::ElementsKindBits::decode(bit_field2());
449 : }
450 :
451 : bool Map::has_fast_smi_elements() const {
452 : return IsSmiElementsKind(elements_kind());
453 : }
454 :
455 : bool Map::has_fast_object_elements() const {
456 : return IsObjectElementsKind(elements_kind());
457 : }
458 :
459 : bool Map::has_fast_smi_or_object_elements() const {
460 : return IsSmiOrObjectElementsKind(elements_kind());
461 : }
462 :
463 : bool Map::has_fast_double_elements() const {
464 : return IsDoubleElementsKind(elements_kind());
465 : }
466 :
467 : bool Map::has_fast_elements() const {
468 : return IsFastElementsKind(elements_kind());
469 : }
470 :
471 : bool Map::has_sloppy_arguments_elements() const {
472 : return IsSloppyArgumentsElementsKind(elements_kind());
473 : }
474 :
475 : bool Map::has_fast_sloppy_arguments_elements() const {
476 : return elements_kind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
477 : }
478 :
479 : bool Map::has_fast_string_wrapper_elements() const {
480 : return elements_kind() == FAST_STRING_WRAPPER_ELEMENTS;
481 : }
482 :
483 : bool Map::has_fixed_typed_array_elements() const {
484 : return IsFixedTypedArrayElementsKind(elements_kind());
485 : }
486 :
487 : bool Map::has_dictionary_elements() const {
488 : return IsDictionaryElementsKind(elements_kind());
489 : }
490 :
491 759580 : void Map::set_is_dictionary_map(bool value) {
492 : uint32_t new_bit_field3 = IsDictionaryMapBit::update(bit_field3(), value);
493 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, value);
494 759580 : set_bit_field3(new_bit_field3);
495 759580 : }
496 :
497 412652630 : bool Map::is_dictionary_map() const {
498 412652630 : return IsDictionaryMapBit::decode(bit_field3());
499 : }
500 :
501 16901823 : void Map::mark_unstable() {
502 16901823 : set_bit_field3(IsUnstableBit::update(bit_field3(), true));
503 16901824 : }
504 :
505 89732296 : bool Map::is_stable() const { return !IsUnstableBit::decode(bit_field3()); }
506 :
507 24793945 : bool Map::CanBeDeprecated() const {
508 24793945 : int descriptor = LastAdded();
509 86264676 : for (int i = 0; i <= descriptor; i++) {
510 69328224 : PropertyDetails details = instance_descriptors()->GetDetails(i);
511 69328008 : if (details.representation().IsNone()) return true;
512 69328696 : if (details.representation().IsSmi()) return true;
513 66570949 : if (details.representation().IsDouble()) return true;
514 66570215 : if (details.representation().IsHeapObject()) return true;
515 74923126 : if (details.kind() == kData && details.location() == kDescriptor) {
516 : return true;
517 : }
518 : }
519 : return false;
520 : }
521 :
522 32638526 : void Map::NotifyLeafMapLayoutChange(Isolate* isolate) {
523 32638526 : if (is_stable()) {
524 16901543 : mark_unstable();
525 : dependent_code()->DeoptimizeDependentCodeGroup(
526 16901544 : isolate, DependentCode::kPrototypeCheckGroup);
527 : }
528 32638525 : }
529 :
530 10808952 : bool Map::CanTransition() const {
531 : // Only JSObject and subtypes have map transitions and back pointers.
532 10808952 : return InstanceTypeChecker::IsJSObject(instance_type());
533 : }
534 :
535 : #define DEF_TESTER(Type, ...) \
536 : bool Map::Is##Type##Map() const { \
537 : return InstanceTypeChecker::Is##Type(instance_type()); \
538 : }
539 28562 : INSTANCE_TYPE_CHECKERS(DEF_TESTER)
540 : #undef DEF_TESTER
541 :
542 258695 : bool Map::IsBooleanMap() const {
543 517390 : return *this == GetReadOnlyRoots().boolean_map();
544 : }
545 :
546 558 : bool Map::IsNullOrUndefinedMap() const {
547 2223 : return *this == GetReadOnlyRoots().null_map() ||
548 1665 : *this == GetReadOnlyRoots().undefined_map();
549 : }
550 :
551 5444934 : bool Map::IsPrimitiveMap() const {
552 5444934 : return instance_type() <= LAST_PRIMITIVE_TYPE;
553 : }
554 :
555 630984107 : Object Map::prototype() const { return READ_FIELD(*this, kPrototypeOffset); }
556 :
557 57419013 : void Map::set_prototype(Object value, WriteBarrierMode mode) {
558 : DCHECK(value->IsNull() || value->IsJSReceiver());
559 2912 : WRITE_FIELD(*this, kPrototypeOffset, value);
560 104597226 : CONDITIONAL_WRITE_BARRIER(*this, kPrototypeOffset, value, mode);
561 57419017 : }
562 :
563 : LayoutDescriptor Map::layout_descriptor_gc_safe() const {
564 : DCHECK(FLAG_unbox_double_fields);
565 : // The loaded value can be dereferenced on background thread to load the
566 : // bitmap. We need acquire load in order to ensure that the bitmap
567 : // initializing stores are also visible to the background thread.
568 187552 : Object layout_desc = ACQUIRE_READ_FIELD(*this, kLayoutDescriptorOffset);
569 : return LayoutDescriptor::cast_gc_safe(layout_desc);
570 : }
571 :
572 129546409 : bool Map::HasFastPointerLayout() const {
573 : DCHECK(FLAG_unbox_double_fields);
574 : // The loaded value is used for SMI check only and is not dereferenced,
575 : // so relaxed load is safe.
576 129546409 : Object layout_desc = RELAXED_READ_FIELD(*this, kLayoutDescriptorOffset);
577 129548602 : return LayoutDescriptor::IsFastPointerLayout(layout_desc);
578 : }
579 :
580 28496929 : void Map::UpdateDescriptors(Isolate* isolate, DescriptorArray descriptors,
581 : LayoutDescriptor layout_desc,
582 : int number_of_own_descriptors) {
583 28496929 : SetInstanceDescriptors(isolate, descriptors, number_of_own_descriptors);
584 : if (FLAG_unbox_double_fields) {
585 56993857 : if (layout_descriptor()->IsSlowLayout()) {
586 2806 : set_layout_descriptor(layout_desc);
587 : }
588 : #ifdef VERIFY_HEAP
589 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
590 : if (FLAG_verify_heap) {
591 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
592 : CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
593 : }
594 : #else
595 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
596 : DCHECK(visitor_id() == Map::GetVisitorId(*this));
597 : #endif
598 : }
599 28496929 : }
600 :
601 22318323 : void Map::InitializeDescriptors(Isolate* isolate, DescriptorArray descriptors,
602 : LayoutDescriptor layout_desc) {
603 : SetInstanceDescriptors(isolate, descriptors,
604 22318323 : descriptors->number_of_descriptors());
605 :
606 : if (FLAG_unbox_double_fields) {
607 22318324 : set_layout_descriptor(layout_desc);
608 : #ifdef VERIFY_HEAP
609 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
610 : if (FLAG_verify_heap) {
611 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
612 : }
613 : #else
614 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
615 : #endif
616 22318324 : set_visitor_id(Map::GetVisitorId(*this));
617 : }
618 22318322 : }
619 :
620 218454419 : void Map::set_bit_field3(uint32_t bits) {
621 : if (kInt32Size != kTaggedSize) {
622 218454419 : RELAXED_WRITE_UINT32_FIELD(*this, kBitField3Offset + kInt32Size, 0);
623 : }
624 218454419 : RELAXED_WRITE_UINT32_FIELD(*this, kBitField3Offset, bits);
625 218454419 : }
626 :
627 280 : uint32_t Map::bit_field3() const {
628 1803845048 : return RELAXED_READ_UINT32_FIELD(*this, kBitField3Offset);
629 : }
630 :
631 : LayoutDescriptor Map::GetLayoutDescriptor() const {
632 : return FLAG_unbox_double_fields ? layout_descriptor()
633 14045820 : : LayoutDescriptor::FastPointerLayout();
634 : }
635 :
636 10328 : void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) {
637 10328 : DescriptorArray descriptors = instance_descriptors();
638 : int number_of_own_descriptors = NumberOfOwnDescriptors();
639 : DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
640 : {
641 : // The following two operations need to happen before the marking write
642 : // barrier.
643 10328 : descriptors->Append(desc);
644 10328 : SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
645 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
646 10328 : number_of_own_descriptors + 1);
647 : }
648 : // Properly mark the map if the {desc} is an "interesting symbol".
649 10328 : if (desc->GetKey()->IsInterestingSymbol()) {
650 111 : set_may_have_interesting_symbols(true);
651 : }
652 : PropertyDetails details = desc->GetDetails();
653 10328 : if (details.location() == kField) {
654 : DCHECK_GT(UnusedPropertyFields(), 0);
655 3219 : AccountAddedPropertyField();
656 : }
657 :
658 : // This function does not support appending double field descriptors and
659 : // it should never try to (otherwise, layout descriptor must be updated too).
660 : #ifdef DEBUG
661 : DCHECK(details.location() != kField || !details.representation().IsDouble());
662 : #endif
663 10328 : }
664 :
665 120899259 : Object Map::GetBackPointer() const {
666 120899259 : Object object = constructor_or_backpointer();
667 120899276 : if (object->IsMap()) {
668 75737342 : return object;
669 : }
670 90323870 : return GetReadOnlyRoots().undefined_value();
671 : }
672 :
673 8137382 : Map Map::ElementsTransitionMap() {
674 : DisallowHeapAllocation no_gc;
675 : // TODO(delphick): While it's safe to pass nullptr for Isolate* here as
676 : // SearchSpecial doesn't need it, this is really ugly. Perhaps factor out a
677 : // base class for methods not requiring an Isolate?
678 : return TransitionsAccessor(nullptr, *this, &no_gc)
679 16274772 : .SearchSpecial(GetReadOnlyRoots().elements_transition_symbol());
680 : }
681 :
682 : Object Map::prototype_info() const {
683 : DCHECK(is_prototype_map());
684 77180162 : return READ_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset);
685 : }
686 :
687 6675022 : void Map::set_prototype_info(Object value, WriteBarrierMode mode) {
688 6675022 : CHECK(is_prototype_map());
689 6675022 : WRITE_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset, value);
690 20025066 : CONDITIONAL_WRITE_BARRIER(*this, Map::kTransitionsOrPrototypeInfoOffset,
691 : value, mode);
692 6675023 : }
693 :
694 7258354 : void Map::SetBackPointer(Object value, WriteBarrierMode mode) {
695 7258354 : CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE);
696 7258356 : CHECK(value->IsMap());
697 14516714 : CHECK(GetBackPointer()->IsUndefined());
698 21775068 : CHECK_IMPLIES(value->IsMap(), Map::cast(value)->GetConstructor() ==
699 : constructor_or_backpointer());
700 7258357 : set_constructor_or_backpointer(value, mode);
701 7258357 : }
702 :
703 139039811 : ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
704 166394480 : ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
705 1379464100 : ACCESSORS(Map, constructor_or_backpointer, Object,
706 : kConstructorOrBackPointerOffset)
707 :
708 1339686 : bool Map::IsPrototypeValidityCellValid() const {
709 1339686 : Object validity_cell = prototype_validity_cell();
710 : Object value = validity_cell->IsSmi() ? Smi::cast(validity_cell)
711 1339687 : : Cell::cast(validity_cell)->value();
712 1339688 : return value == Smi::FromInt(Map::kPrototypeChainValid);
713 : }
714 :
715 81784113 : Object Map::GetConstructor() const {
716 81784113 : Object maybe_constructor = constructor_or_backpointer();
717 : // Follow any back pointers.
718 1040303905 : while (maybe_constructor->IsMap()) {
719 : maybe_constructor =
720 876735669 : Map::cast(maybe_constructor)->constructor_or_backpointer();
721 : }
722 81784121 : return maybe_constructor;
723 : }
724 :
725 2152181 : FunctionTemplateInfo Map::GetFunctionTemplateInfo() const {
726 2152181 : Object constructor = GetConstructor();
727 2152181 : if (constructor->IsJSFunction()) {
728 : DCHECK(JSFunction::cast(constructor)->shared()->IsApiFunction());
729 2152181 : return JSFunction::cast(constructor)->shared()->get_api_func_data();
730 : }
731 : DCHECK(constructor->IsFunctionTemplateInfo());
732 : return FunctionTemplateInfo::cast(constructor);
733 : }
734 :
735 9084637 : void Map::SetConstructor(Object constructor, WriteBarrierMode mode) {
736 : // Never overwrite a back pointer with a constructor.
737 18169274 : CHECK(!constructor_or_backpointer()->IsMap());
738 9084637 : set_constructor_or_backpointer(constructor, mode);
739 9084637 : }
740 :
741 415587 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map) {
742 : return CopyInitialMap(isolate, map, map->instance_size(),
743 : map->GetInObjectProperties(),
744 1246761 : map->UnusedPropertyFields());
745 : }
746 :
747 : bool Map::IsInobjectSlackTrackingInProgress() const {
748 20755265 : return construction_counter() != Map::kNoSlackTracking;
749 : }
750 :
751 240572 : void Map::InobjectSlackTrackingStep(Isolate* isolate) {
752 : // Slack tracking should only be performed on an initial map.
753 : DCHECK(GetBackPointer()->IsUndefined());
754 481144 : if (!IsInobjectSlackTrackingInProgress()) return;
755 : int counter = construction_counter();
756 240572 : set_construction_counter(counter - 1);
757 240572 : if (counter == kSlackTrackingCounterEnd) {
758 2023 : CompleteInobjectSlackTracking(isolate);
759 : }
760 : }
761 :
762 2350382 : int Map::SlackForArraySize(int old_size, int size_limit) {
763 2350382 : const int max_slack = size_limit - old_size;
764 2350382 : CHECK_LE(0, max_slack);
765 2350382 : if (old_size < 4) {
766 : DCHECK_LE(1, max_slack);
767 : return 1;
768 : }
769 2489234 : return Min(max_slack, old_size / 4);
770 : }
771 :
772 : int Map::InstanceSizeFromSlack(int slack) const {
773 267961 : return instance_size() - slack * kTaggedSize;
774 : }
775 :
776 1184722 : OBJECT_CONSTRUCTORS_IMPL(NormalizedMapCache, WeakFixedArray)
777 592361 : CAST_ACCESSOR(NormalizedMapCache)
778 : NEVER_READ_ONLY_SPACE_IMPL(NormalizedMapCache)
779 :
780 752667 : int NormalizedMapCache::GetIndex(Handle<Map> map) {
781 752667 : return map->Hash() % NormalizedMapCache::kEntries;
782 : }
783 :
784 : bool HeapObject::IsNormalizedMapCache() const {
785 : if (!IsWeakFixedArray()) return false;
786 : if (WeakFixedArray::cast(*this)->length() != NormalizedMapCache::kEntries) {
787 : return false;
788 : }
789 : return true;
790 : }
791 :
792 : } // namespace internal
793 : } // namespace v8
794 :
795 : #include "src/objects/object-macros-undef.h"
796 :
797 : #endif // V8_OBJECTS_MAP_INL_H_
|