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-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.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 3427425400 : OBJECT_CONSTRUCTORS_IMPL(Map, HeapObject)
31 1717965485 : CAST_ACCESSOR(Map)
32 :
33 722469533 : DescriptorArray Map::instance_descriptors() const {
34 1444939240 : return DescriptorArray::cast(READ_FIELD(*this, kDescriptorsOffset));
35 : }
36 :
37 29231776 : DescriptorArray Map::synchronized_instance_descriptors() const {
38 58493332 : return DescriptorArray::cast(ACQUIRE_READ_FIELD(*this, kDescriptorsOffset));
39 : }
40 :
41 80195629 : void Map::set_synchronized_instance_descriptors(DescriptorArray value,
42 : WriteBarrierMode mode) {
43 80195629 : RELEASE_WRITE_FIELD(*this, kDescriptorsOffset, value);
44 240586923 : CONDITIONAL_WRITE_BARRIER(*this, kDescriptorsOffset, value, mode);
45 80195612 : }
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 411655200 : SYNCHRONIZED_ACCESSORS_CHECKED(Map, layout_descriptor, LayoutDescriptor,
52 : kLayoutDescriptorOffset,
53 : FLAG_unbox_double_fields)
54 286239192 : WEAK_ACCESSORS(Map, raw_transitions, kTransitionsOrPrototypeInfoOffset)
55 :
56 : // |bit_field| fields.
57 180420 : BIT_FIELD_ACCESSORS(Map, bit_field, has_non_instance_prototype,
58 : Map::HasNonInstancePrototypeBit)
59 27657374 : 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 175468896 : BIT_FIELD_ACCESSORS(Map, bit_field, is_undetectable, Map::IsUndetectableBit)
65 71858026 : BIT_FIELD_ACCESSORS(Map, bit_field, is_access_check_needed,
66 : Map::IsAccessCheckNeededBit)
67 13398037 : 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 151712 : 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 54120384 : BIT_FIELD_ACCESSORS(Map, bit_field3, owns_descriptors, Map::OwnsDescriptorsBit)
79 174130542 : BIT_FIELD_ACCESSORS(Map, bit_field3, has_hidden_prototype,
80 : Map::HasHiddenPrototypeBit)
81 70836578 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
82 721542 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_migration_target,
83 : Map::IsMigrationTargetBit)
84 370902 : BIT_FIELD_ACCESSORS(Map, bit_field3, is_immutable_proto,
85 : Map::IsImmutablePrototypeBit)
86 73299036 : BIT_FIELD_ACCESSORS(Map, bit_field3, new_target_is_base,
87 : Map::NewTargetIsBaseBit)
88 4176984 : BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_symbols,
89 : Map::MayHaveInterestingSymbolsBit)
90 2175064 : BIT_FIELD_ACCESSORS(Map, bit_field3, construction_counter,
91 : Map::ConstructionCounterBits)
92 :
93 1538689 : InterceptorInfo Map::GetNamedInterceptor() {
94 : DCHECK(has_named_interceptor());
95 1538689 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
96 3077378 : return InterceptorInfo::cast(info->GetNamedPropertyHandler());
97 : }
98 :
99 621280 : InterceptorInfo Map::GetIndexedInterceptor() {
100 : DCHECK(has_indexed_interceptor());
101 621280 : FunctionTemplateInfo info = GetFunctionTemplateInfo();
102 1242560 : return InterceptorInfo::cast(info->GetIndexedPropertyHandler());
103 : }
104 :
105 : bool Map::IsInplaceGeneralizableField(PropertyConstness constness,
106 : Representation representation,
107 : FieldType field_type) {
108 : if (FLAG_track_constant_fields && FLAG_modify_map_inplace &&
109 : (constness == PropertyConstness::kConst)) {
110 : // VariableMode::kConst -> PropertyConstness::kMutable field generalization
111 : // may happen in-place.
112 : return true;
113 : }
114 1294 : if (representation.IsHeapObject() && !field_type->IsAny()) {
115 : return true;
116 : }
117 : return false;
118 : }
119 :
120 : bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) {
121 7650642 : return instance_type == JS_ARRAY_TYPE || instance_type == JS_VALUE_TYPE ||
122 : instance_type == JS_ARGUMENTS_TYPE;
123 : }
124 :
125 : bool Map::CanHaveFastTransitionableElementsKind() const {
126 : return CanHaveFastTransitionableElementsKind(instance_type());
127 : }
128 :
129 : // static
130 7650154 : void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
131 : Isolate* isolate, InstanceType instance_type, PropertyConstness* constness,
132 : Representation* representation, Handle<FieldType>* field_type) {
133 7650154 : if (CanHaveFastTransitionableElementsKind(instance_type)) {
134 : // We don't support propagation of field generalization through elements
135 : // kind transitions because they are inserted into the transition tree
136 : // before field transitions. In order to avoid complexity of handling
137 : // such a case we ensure that all maps with transitionable elements kinds
138 : // do not have fields that can be generalized in-place (without creation
139 : // of a new map).
140 : if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
141 : // The constness is either already PropertyConstness::kMutable or should
142 : // become PropertyConstness::kMutable if it was VariableMode::kConst.
143 : *constness = PropertyConstness::kMutable;
144 : }
145 22352 : if (representation->IsHeapObject()) {
146 : // The field type is either already Any or should become Any if it was
147 : // something else.
148 16036 : *field_type = FieldType::Any(isolate);
149 : }
150 : }
151 7650154 : }
152 :
153 54918283 : bool Map::IsUnboxedDoubleField(FieldIndex index) const {
154 : if (!FLAG_unbox_double_fields) return false;
155 109836574 : if (index.is_hidden_field() || !index.is_inobject()) return false;
156 13501477 : return !layout_descriptor()->IsTagged(index.property_index());
157 : }
158 :
159 17564353 : bool Map::TooManyFastProperties(StoreOrigin store_origin) const {
160 17564353 : if (UnusedPropertyFields() != 0) return false;
161 3363322 : if (is_prototype_map()) return false;
162 2651061 : if (store_origin == StoreOrigin::kNamed) {
163 2602154 : int limit = Max(kMaxFastProperties, GetInObjectProperties());
164 2602154 : FieldCounts counts = GetFieldCounts();
165 : // Only count mutable fields so that objects with large numbers of
166 : // constant functions do not go to dictionary mode. That would be bad
167 : // because such objects have often been used as modules.
168 2602154 : int external = counts.mutable_count() - GetInObjectProperties();
169 5198968 : return external > limit || counts.GetTotal() > kMaxNumberOfDescriptors;
170 : } else {
171 48907 : int limit = Max(kFastPropertiesSoftLimit, GetInObjectProperties());
172 48907 : int external = NumberOfFields() - GetInObjectProperties();
173 48907 : return external > limit;
174 : }
175 : }
176 :
177 78520049 : PropertyDetails Map::GetLastDescriptorDetails() const {
178 78520049 : return instance_descriptors()->GetDetails(LastAdded());
179 : }
180 :
181 159783951 : int Map::LastAdded() const {
182 : int number_of_own_descriptors = NumberOfOwnDescriptors();
183 : DCHECK_GT(number_of_own_descriptors, 0);
184 159783951 : return number_of_own_descriptors - 1;
185 : }
186 :
187 127247444 : int Map::NumberOfOwnDescriptors() const {
188 127247444 : return NumberOfOwnDescriptorsBits::decode(bit_field3());
189 : }
190 :
191 80205928 : void Map::SetNumberOfOwnDescriptors(int number) {
192 : DCHECK_LE(number, instance_descriptors()->number_of_descriptors());
193 80205928 : CHECK_LE(static_cast<unsigned>(number),
194 : static_cast<unsigned>(kMaxNumberOfDescriptors));
195 80205928 : set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number));
196 80205931 : }
197 :
198 : int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); }
199 :
200 104752 : void Map::SetEnumLength(int length) {
201 104752 : if (length != kInvalidEnumCacheSentinel) {
202 : DCHECK_LE(length, NumberOfOwnDescriptors());
203 61920 : CHECK_LE(static_cast<unsigned>(length),
204 : static_cast<unsigned>(kMaxNumberOfDescriptors));
205 : }
206 104752 : set_bit_field3(EnumLengthBits::update(bit_field3(), length));
207 104752 : }
208 :
209 41584061 : FixedArrayBase Map::GetInitialElements() const {
210 : FixedArrayBase result;
211 41584061 : if (has_fast_elements() || has_fast_string_wrapper_elements()) {
212 83153124 : result = GetReadOnlyRoots().empty_fixed_array();
213 7503 : } else if (has_fast_sloppy_arguments_elements()) {
214 0 : result = GetReadOnlyRoots().empty_sloppy_arguments_elements();
215 7503 : } else if (has_fixed_typed_array_elements()) {
216 8364 : result = GetReadOnlyRoots().EmptyFixedTypedArrayForMap(*this);
217 3321 : } else if (has_dictionary_elements()) {
218 6642 : result = GetReadOnlyRoots().empty_slow_element_dictionary();
219 : } else {
220 0 : UNREACHABLE();
221 : }
222 : DCHECK(!Heap::InNewSpace(result));
223 41584069 : return result;
224 : }
225 :
226 969241684 : VisitorId Map::visitor_id() const {
227 : return static_cast<VisitorId>(
228 2013109286 : RELAXED_READ_BYTE_FIELD(this, kVisitorIdOffset));
229 : }
230 :
231 54733813 : void Map::set_visitor_id(VisitorId id) {
232 54733813 : CHECK_LT(static_cast<unsigned>(id), 256);
233 109467626 : RELAXED_WRITE_BYTE_FIELD(this, kVisitorIdOffset, static_cast<byte>(id));
234 54733813 : }
235 :
236 : int Map::instance_size_in_words() const {
237 6605275973 : return RELAXED_READ_BYTE_FIELD(this, kInstanceSizeInWordsOffset);
238 : }
239 :
240 : void Map::set_instance_size_in_words(int value) {
241 30936611 : RELAXED_WRITE_BYTE_FIELD(this, kInstanceSizeInWordsOffset,
242 : static_cast<byte>(value));
243 : }
244 :
245 48376000 : int Map::instance_size() const {
246 2943817361 : return instance_size_in_words() << kTaggedSizeLog2;
247 : }
248 :
249 30936611 : void Map::set_instance_size(int value) {
250 30936611 : CHECK(IsAligned(value, kTaggedSize));
251 30936611 : value >>= kTaggedSizeLog2;
252 30936611 : CHECK_LT(static_cast<unsigned>(value), 256);
253 : set_instance_size_in_words(value);
254 30936611 : }
255 :
256 : int Map::inobject_properties_start_or_constructor_function_index() const {
257 881321654 : return RELAXED_READ_BYTE_FIELD(
258 : this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset);
259 : }
260 :
261 30674677 : void Map::set_inobject_properties_start_or_constructor_function_index(
262 : int value) {
263 30674677 : CHECK_LT(static_cast<unsigned>(value), 256);
264 61349354 : RELAXED_WRITE_BYTE_FIELD(
265 : this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
266 : static_cast<byte>(value));
267 30674677 : }
268 :
269 : int Map::GetInObjectPropertiesStartInWords() const {
270 : DCHECK(IsJSObjectMap());
271 : return inobject_properties_start_or_constructor_function_index();
272 : }
273 :
274 30664297 : void Map::SetInObjectPropertiesStartInWords(int value) {
275 30664297 : CHECK(IsJSObjectMap());
276 30664297 : set_inobject_properties_start_or_constructor_function_index(value);
277 30664321 : }
278 :
279 288285142 : int Map::GetInObjectProperties() const {
280 : DCHECK(IsJSObjectMap());
281 288285142 : return instance_size_in_words() - GetInObjectPropertiesStartInWords();
282 : }
283 :
284 : int Map::GetConstructorFunctionIndex() const {
285 : DCHECK(IsPrimitiveMap());
286 : return inobject_properties_start_or_constructor_function_index();
287 : }
288 :
289 1512 : void Map::SetConstructorFunctionIndex(int value) {
290 1512 : CHECK(IsPrimitiveMap());
291 1512 : set_inobject_properties_start_or_constructor_function_index(value);
292 1512 : }
293 :
294 : int Map::GetInObjectPropertyOffset(int index) const {
295 114484598 : return (GetInObjectPropertiesStartInWords() + index) * kTaggedSize;
296 : }
297 :
298 : Handle<Map> Map::AddMissingTransitionsForTesting(
299 : Isolate* isolate, Handle<Map> split_map,
300 : Handle<DescriptorArray> descriptors,
301 : Handle<LayoutDescriptor> full_layout_descriptor) {
302 : return AddMissingTransitions(isolate, split_map, descriptors,
303 65 : full_layout_descriptor);
304 : }
305 :
306 11002791644 : InstanceType Map::instance_type() const {
307 : return static_cast<InstanceType>(
308 21335522896 : READ_UINT16_FIELD(this, kInstanceTypeOffset));
309 : }
310 :
311 : void Map::set_instance_type(InstanceType value) {
312 30579344 : WRITE_UINT16_FIELD(this, kInstanceTypeOffset, value);
313 : }
314 :
315 104883484 : int Map::UnusedPropertyFields() const {
316 : int value = used_or_unused_instance_size_in_words();
317 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
318 : int unused;
319 104883484 : if (value >= JSObject::kFieldsAdded) {
320 67153760 : unused = instance_size_in_words() - value;
321 : } else {
322 : // For out of object properties "used_or_unused_instance_size_in_words"
323 : // byte encodes the slack in the property array.
324 : unused = value;
325 : }
326 104883484 : return unused;
327 : }
328 :
329 306 : int Map::UnusedInObjectProperties() const {
330 : // Like Map::UnusedPropertyFields(), but returns 0 for out of object
331 : // properties.
332 : int value = used_or_unused_instance_size_in_words();
333 : DCHECK_IMPLIES(!IsJSObjectMap(), value == 0);
334 306 : if (value >= JSObject::kFieldsAdded) {
335 270 : return instance_size_in_words() - value;
336 : }
337 : return 0;
338 : }
339 :
340 : int Map::used_or_unused_instance_size_in_words() const {
341 385458214 : return RELAXED_READ_BYTE_FIELD(this, kUsedOrUnusedInstanceSizeInWordsOffset);
342 : }
343 :
344 63340720 : void Map::set_used_or_unused_instance_size_in_words(int value) {
345 63340720 : CHECK_LE(static_cast<unsigned>(value), 255);
346 126681440 : RELAXED_WRITE_BYTE_FIELD(this, kUsedOrUnusedInstanceSizeInWordsOffset,
347 : static_cast<byte>(value));
348 63340720 : }
349 :
350 56239049 : int Map::UsedInstanceSize() const {
351 : int words = used_or_unused_instance_size_in_words();
352 56239049 : if (words < JSObject::kFieldsAdded) {
353 : // All in-object properties are used and the words is tracking the slack
354 : // in the property array.
355 3433983 : return instance_size();
356 : }
357 52805066 : return words * kTaggedSize;
358 : }
359 :
360 31706201 : void Map::SetInObjectUnusedPropertyFields(int value) {
361 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
362 31706201 : if (!IsJSObjectMap()) {
363 8850 : CHECK_EQ(0, value);
364 8850 : set_used_or_unused_instance_size_in_words(0);
365 : DCHECK_EQ(0, UnusedPropertyFields());
366 31715061 : return;
367 : }
368 31697351 : CHECK_LE(0, value);
369 : DCHECK_LE(value, GetInObjectProperties());
370 31697351 : int used_inobject_properties = GetInObjectProperties() - value;
371 : set_used_or_unused_instance_size_in_words(
372 31697353 : GetInObjectPropertyOffset(used_inobject_properties) / kTaggedSize);
373 : DCHECK_EQ(value, UnusedPropertyFields());
374 : }
375 :
376 28255 : void Map::SetOutOfObjectUnusedPropertyFields(int value) {
377 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
378 28255 : CHECK_LT(static_cast<unsigned>(value), JSObject::kFieldsAdded);
379 : // For out of object properties "used_instance_size_in_words" byte encodes
380 : // the slack in the property array.
381 28255 : set_used_or_unused_instance_size_in_words(value);
382 : DCHECK_EQ(value, UnusedPropertyFields());
383 28255 : }
384 :
385 24241144 : void Map::CopyUnusedPropertyFields(Map map) {
386 : set_used_or_unused_instance_size_in_words(
387 24241144 : map->used_or_unused_instance_size_in_words());
388 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
389 24241138 : }
390 :
391 261 : void Map::CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map map) {
392 : int value = map->used_or_unused_instance_size_in_words();
393 261 : if (value >= JSValue::kFieldsAdded) {
394 : // Unused in-object fields. Adjust the offset from the object’s start
395 : // so it matches the distance to the object’s end.
396 225 : value += instance_size_in_words() - map->instance_size_in_words();
397 : }
398 261 : set_used_or_unused_instance_size_in_words(value);
399 : DCHECK_EQ(UnusedPropertyFields(), map->UnusedPropertyFields());
400 261 : }
401 :
402 7364863 : void Map::AccountAddedPropertyField() {
403 : // Update used instance size and unused property fields number.
404 : STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kTaggedSize);
405 : #ifdef DEBUG
406 : int new_unused = UnusedPropertyFields() - 1;
407 : if (new_unused < 0) new_unused += JSObject::kFieldsAdded;
408 : #endif
409 : int value = used_or_unused_instance_size_in_words();
410 7364863 : if (value >= JSObject::kFieldsAdded) {
411 3381116 : if (value == instance_size_in_words()) {
412 346465 : AccountAddedOutOfObjectPropertyField(0);
413 : } else {
414 : // The property is added in-object, so simply increment the counter.
415 3034651 : set_used_or_unused_instance_size_in_words(value + 1);
416 : }
417 : } else {
418 3983747 : AccountAddedOutOfObjectPropertyField(value);
419 : }
420 : DCHECK_EQ(new_unused, UnusedPropertyFields());
421 7364866 : }
422 :
423 4330212 : void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
424 4330212 : unused_in_property_array--;
425 4330212 : if (unused_in_property_array < 0) {
426 1642773 : unused_in_property_array += JSObject::kFieldsAdded;
427 : }
428 4330212 : CHECK_LT(static_cast<unsigned>(unused_in_property_array),
429 : JSObject::kFieldsAdded);
430 4330212 : set_used_or_unused_instance_size_in_words(unused_in_property_array);
431 : DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
432 4330212 : }
433 :
434 365162105 : byte Map::bit_field() const { return READ_BYTE_FIELD(this, kBitFieldOffset); }
435 :
436 : void Map::set_bit_field(byte value) {
437 55942055 : WRITE_BYTE_FIELD(this, kBitFieldOffset, value);
438 : }
439 :
440 769634732 : byte Map::bit_field2() const { return READ_BYTE_FIELD(this, kBitField2Offset); }
441 :
442 : void Map::set_bit_field2(byte value) {
443 91333669 : WRITE_BYTE_FIELD(this, kBitField2Offset, value);
444 : }
445 :
446 446121 : bool Map::is_abandoned_prototype_map() const {
447 446121 : return is_prototype_map() && !owns_descriptors();
448 : }
449 :
450 32317135 : bool Map::should_be_fast_prototype_map() const {
451 64634315 : if (!prototype_info()->IsPrototypeInfo()) return false;
452 28634031 : return PrototypeInfo::cast(prototype_info())->should_be_fast_map();
453 : }
454 :
455 30927122 : void Map::set_elements_kind(ElementsKind elements_kind) {
456 30927122 : CHECK_LT(static_cast<int>(elements_kind), kElementsKindCount);
457 30927122 : set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
458 30927122 : }
459 :
460 449347 : ElementsKind Map::elements_kind() const {
461 449347 : return Map::ElementsKindBits::decode(bit_field2());
462 : }
463 :
464 : bool Map::has_fast_smi_elements() const {
465 : return IsSmiElementsKind(elements_kind());
466 : }
467 :
468 : bool Map::has_fast_object_elements() const {
469 : return IsObjectElementsKind(elements_kind());
470 : }
471 :
472 : bool Map::has_fast_smi_or_object_elements() const {
473 : return IsSmiOrObjectElementsKind(elements_kind());
474 : }
475 :
476 : bool Map::has_fast_double_elements() const {
477 : return IsDoubleElementsKind(elements_kind());
478 : }
479 :
480 : bool Map::has_fast_elements() const {
481 : return IsFastElementsKind(elements_kind());
482 : }
483 :
484 : bool Map::has_sloppy_arguments_elements() const {
485 : return IsSloppyArgumentsElementsKind(elements_kind());
486 : }
487 :
488 : bool Map::has_fast_sloppy_arguments_elements() const {
489 : return elements_kind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
490 : }
491 :
492 : bool Map::has_fast_string_wrapper_elements() const {
493 : return elements_kind() == FAST_STRING_WRAPPER_ELEMENTS;
494 : }
495 :
496 : bool Map::has_fixed_typed_array_elements() const {
497 : return IsFixedTypedArrayElementsKind(elements_kind());
498 : }
499 :
500 : bool Map::has_dictionary_elements() const {
501 : return IsDictionaryElementsKind(elements_kind());
502 : }
503 :
504 766230 : void Map::set_is_dictionary_map(bool value) {
505 : uint32_t new_bit_field3 = IsDictionaryMapBit::update(bit_field3(), value);
506 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, value);
507 766230 : set_bit_field3(new_bit_field3);
508 766230 : }
509 :
510 437730224 : bool Map::is_dictionary_map() const {
511 437730224 : return IsDictionaryMapBit::decode(bit_field3());
512 : }
513 :
514 18004059 : void Map::mark_unstable() {
515 18004059 : set_bit_field3(IsUnstableBit::update(bit_field3(), true));
516 18004061 : }
517 :
518 76403472 : bool Map::is_stable() const { return !IsUnstableBit::decode(bit_field3()); }
519 :
520 24836780 : bool Map::CanBeDeprecated() const {
521 24836780 : int descriptor = LastAdded();
522 84322202 : for (int i = 0; i <= descriptor; i++) {
523 67418098 : PropertyDetails details = instance_descriptors()->GetDetails(i);
524 67417579 : if (details.representation().IsNone()) return true;
525 67418925 : if (details.representation().IsSmi()) return true;
526 64650955 : if (details.representation().IsDouble()) return true;
527 64650168 : if (details.representation().IsHeapObject()) return true;
528 74690371 : if (details.kind() == kData && details.location() == kDescriptor) {
529 : return true;
530 : }
531 : }
532 : return false;
533 : }
534 :
535 34369218 : void Map::NotifyLeafMapLayoutChange(Isolate* isolate) {
536 34369218 : if (is_stable()) {
537 18003779 : mark_unstable();
538 : dependent_code()->DeoptimizeDependentCodeGroup(
539 18003780 : isolate, DependentCode::kPrototypeCheckGroup);
540 : }
541 34369216 : }
542 :
543 11632700 : bool Map::CanTransition() const {
544 : // Only JSObject and subtypes have map transitions and back pointers.
545 11632700 : return InstanceTypeChecker::IsJSObject(instance_type());
546 : }
547 :
548 : #define DEF_TESTER(Type, ...) \
549 : bool Map::Is##Type##Map() const { \
550 : return InstanceTypeChecker::Is##Type(instance_type()); \
551 : }
552 : INSTANCE_TYPE_CHECKERS(DEF_TESTER)
553 : #undef DEF_TESTER
554 :
555 252561 : bool Map::IsBooleanMap() const {
556 505123 : return *this == GetReadOnlyRoots().boolean_map();
557 : }
558 :
559 513 : bool Map::IsNullOrUndefinedMap() const {
560 2043 : return *this == GetReadOnlyRoots().null_map() ||
561 1530 : *this == GetReadOnlyRoots().undefined_map();
562 : }
563 :
564 5420092 : bool Map::IsPrimitiveMap() const {
565 5420092 : return instance_type() <= LAST_PRIMITIVE_TYPE;
566 : }
567 :
568 642292694 : Object Map::prototype() const { return READ_FIELD(this, kPrototypeOffset); }
569 :
570 61884189 : void Map::set_prototype(Object value, WriteBarrierMode mode) {
571 : DCHECK(value->IsNull() || value->IsJSReceiver());
572 61884189 : WRITE_FIELD(*this, kPrototypeOffset, value);
573 115048312 : CONDITIONAL_WRITE_BARRIER(*this, kPrototypeOffset, value, mode);
574 61884196 : }
575 :
576 : LayoutDescriptor Map::layout_descriptor_gc_safe() const {
577 : DCHECK(FLAG_unbox_double_fields);
578 : // The loaded value can be dereferenced on background thread to load the
579 : // bitmap. We need acquire load in order to ensure that the bitmap
580 : // initializing stores are also visible to the background thread.
581 271217 : Object layout_desc = ACQUIRE_READ_FIELD(*this, kLayoutDescriptorOffset);
582 : return LayoutDescriptor::cast_gc_safe(layout_desc);
583 : }
584 :
585 73021095 : bool Map::HasFastPointerLayout() const {
586 : DCHECK(FLAG_unbox_double_fields);
587 : // The loaded value is used for SMI check only and is not dereferenced,
588 : // so relaxed load is safe.
589 73021095 : Object layout_desc = RELAXED_READ_FIELD(*this, kLayoutDescriptorOffset);
590 73007304 : return LayoutDescriptor::IsFastPointerLayout(layout_desc);
591 : }
592 :
593 25556093 : void Map::UpdateDescriptors(Isolate* isolate, DescriptorArray descriptors,
594 : LayoutDescriptor layout_desc,
595 : int number_of_own_descriptors) {
596 25556093 : SetInstanceDescriptors(isolate, descriptors, number_of_own_descriptors);
597 : if (FLAG_unbox_double_fields) {
598 51112156 : if (layout_descriptor()->IsSlowLayout()) {
599 2809 : set_layout_descriptor(layout_desc);
600 : }
601 : #ifdef VERIFY_HEAP
602 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
603 : if (FLAG_verify_heap) {
604 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
605 : CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
606 : }
607 : #else
608 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
609 : DCHECK(visitor_id() == Map::GetVisitorId(*this));
610 : #endif
611 : }
612 25556078 : }
613 :
614 24009195 : void Map::InitializeDescriptors(Isolate* isolate, DescriptorArray descriptors,
615 : LayoutDescriptor layout_desc) {
616 : SetInstanceDescriptors(isolate, descriptors,
617 24009195 : descriptors->number_of_descriptors());
618 :
619 : if (FLAG_unbox_double_fields) {
620 24009188 : set_layout_descriptor(layout_desc);
621 : #ifdef VERIFY_HEAP
622 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
623 : if (FLAG_verify_heap) {
624 : CHECK(layout_descriptor()->IsConsistentWithMap(*this));
625 : }
626 : #else
627 : SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(*this));
628 : #endif
629 24009197 : set_visitor_id(Map::GetVisitorId(*this));
630 : }
631 24009203 : }
632 :
633 229652424 : void Map::set_bit_field3(uint32_t bits) {
634 : if (kInt32Size != kTaggedSize) {
635 229652424 : RELAXED_WRITE_UINT32_FIELD(this, kBitField3Offset + kInt32Size, 0);
636 : }
637 229652424 : RELAXED_WRITE_UINT32_FIELD(this, kBitField3Offset, bits);
638 229652424 : }
639 :
640 : uint32_t Map::bit_field3() const {
641 1790731984 : return RELAXED_READ_UINT32_FIELD(this, kBitField3Offset);
642 : }
643 :
644 : LayoutDescriptor Map::GetLayoutDescriptor() const {
645 : return FLAG_unbox_double_fields ? layout_descriptor()
646 13609600 : : LayoutDescriptor::FastPointerLayout();
647 : }
648 :
649 10328 : void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) {
650 10328 : DescriptorArray descriptors = instance_descriptors();
651 : int number_of_own_descriptors = NumberOfOwnDescriptors();
652 : DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
653 : {
654 : // The following two operations need to happen before the marking write
655 : // barrier.
656 10328 : descriptors->Append(desc);
657 10328 : SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
658 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
659 10328 : number_of_own_descriptors + 1);
660 : }
661 : // Properly mark the map if the {desc} is an "interesting symbol".
662 10328 : if (desc->GetKey()->IsInterestingSymbol()) {
663 111 : set_may_have_interesting_symbols(true);
664 : }
665 : PropertyDetails details = desc->GetDetails();
666 10328 : if (details.location() == kField) {
667 : DCHECK_GT(UnusedPropertyFields(), 0);
668 3219 : AccountAddedPropertyField();
669 : }
670 :
671 : // This function does not support appending double field descriptors and
672 : // it should never try to (otherwise, layout descriptor must be updated too).
673 : #ifdef DEBUG
674 : DCHECK(details.location() != kField || !details.representation().IsDouble());
675 : #endif
676 10328 : }
677 :
678 121226550 : Object Map::GetBackPointer() const {
679 121226550 : Object object = constructor_or_backpointer();
680 121226678 : if (object->IsMap()) {
681 69326246 : return object;
682 : }
683 103800852 : return GetReadOnlyRoots().undefined_value();
684 : }
685 :
686 8273601 : Map Map::ElementsTransitionMap() {
687 : DisallowHeapAllocation no_gc;
688 : // TODO(delphick): While it's safe to pass nullptr for Isolate* here as
689 : // SearchSpecial doesn't need it, this is really ugly. Perhaps factor out a
690 : // base class for methods not requiring an Isolate?
691 : return TransitionsAccessor(nullptr, *this, &no_gc)
692 16547218 : .SearchSpecial(GetReadOnlyRoots().elements_transition_symbol());
693 : }
694 :
695 : Object Map::prototype_info() const {
696 : DCHECK(is_prototype_map());
697 90020009 : return READ_FIELD(this, Map::kTransitionsOrPrototypeInfoOffset);
698 : }
699 :
700 9187185 : void Map::set_prototype_info(Object value, WriteBarrierMode mode) {
701 9187185 : CHECK(is_prototype_map());
702 9187185 : WRITE_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset, value);
703 27561553 : CONDITIONAL_WRITE_BARRIER(*this, Map::kTransitionsOrPrototypeInfoOffset,
704 : value, mode);
705 9187188 : }
706 :
707 6488294 : void Map::SetBackPointer(Object value, WriteBarrierMode mode) {
708 6488294 : CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE);
709 6488314 : CHECK(value->IsMap());
710 12976630 : CHECK(GetBackPointer()->IsUndefined());
711 19464958 : CHECK_IMPLIES(value->IsMap(), Map::cast(value)->GetConstructor() ==
712 : constructor_or_backpointer());
713 6488325 : set_constructor_or_backpointer(value, mode);
714 6488319 : }
715 :
716 149031773 : ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
717 216961102 : ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset)
718 2403881069 : ACCESSORS(Map, constructor_or_backpointer, Object,
719 : kConstructorOrBackPointerOffset)
720 :
721 1301766 : bool Map::IsPrototypeValidityCellValid() const {
722 1301766 : Object validity_cell = prototype_validity_cell();
723 : Object value = validity_cell->IsSmi() ? Smi::cast(validity_cell)
724 2603448 : : Cell::cast(validity_cell)->value();
725 1301767 : return value == Smi::FromInt(Map::kPrototypeChainValid);
726 : }
727 :
728 86210304 : Object Map::GetConstructor() const {
729 86210304 : Object maybe_constructor = constructor_or_backpointer();
730 : // Follow any back pointers.
731 649120378 : while (maybe_constructor->IsMap()) {
732 : maybe_constructor =
733 476699672 : Map::cast(maybe_constructor)->constructor_or_backpointer();
734 : }
735 86210373 : return maybe_constructor;
736 : }
737 :
738 2159969 : FunctionTemplateInfo Map::GetFunctionTemplateInfo() const {
739 2159969 : Object constructor = GetConstructor();
740 2159969 : if (constructor->IsJSFunction()) {
741 : DCHECK(JSFunction::cast(constructor)->shared()->IsApiFunction());
742 2159969 : return JSFunction::cast(constructor)->shared()->get_api_func_data();
743 : }
744 : DCHECK(constructor->IsFunctionTemplateInfo());
745 : return FunctionTemplateInfo::cast(constructor);
746 : }
747 :
748 9999754 : void Map::SetConstructor(Object constructor, WriteBarrierMode mode) {
749 : // Never overwrite a back pointer with a constructor.
750 19999526 : CHECK(!constructor_or_backpointer()->IsMap());
751 9999772 : set_constructor_or_backpointer(constructor, mode);
752 9999770 : }
753 :
754 449596 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map) {
755 : return CopyInitialMap(isolate, map, map->instance_size(),
756 : map->GetInObjectProperties(),
757 1348795 : map->UnusedPropertyFields());
758 : }
759 :
760 : bool Map::IsInobjectSlackTrackingInProgress() const {
761 23087387 : return construction_counter() != Map::kNoSlackTracking;
762 : }
763 :
764 242385 : void Map::InobjectSlackTrackingStep(Isolate* isolate) {
765 : // Slack tracking should only be performed on an initial map.
766 : DCHECK(GetBackPointer()->IsUndefined());
767 484769 : if (!IsInobjectSlackTrackingInProgress()) return;
768 : int counter = construction_counter();
769 242385 : set_construction_counter(counter - 1);
770 242383 : if (counter == kSlackTrackingCounterEnd) {
771 2191 : CompleteInobjectSlackTracking(isolate);
772 : }
773 : }
774 :
775 2343798 : int Map::SlackForArraySize(int old_size, int size_limit) {
776 2343798 : const int max_slack = size_limit - old_size;
777 2343798 : CHECK_LE(0, max_slack);
778 2343798 : if (old_size < 4) {
779 : DCHECK_LE(1, max_slack);
780 : return 1;
781 : }
782 2470480 : return Min(max_slack, old_size / 4);
783 : }
784 :
785 : NEVER_READ_ONLY_SPACE_IMPL(NormalizedMapCache)
786 :
787 758848 : int NormalizedMapCache::GetIndex(Handle<Map> map) {
788 758848 : return map->Hash() % NormalizedMapCache::kEntries;
789 : }
790 :
791 : bool NormalizedMapCache::IsNormalizedMapCache(const HeapObject obj) {
792 : if (!obj->IsWeakFixedArray()) return false;
793 : if (WeakFixedArray::cast(obj)->length() != NormalizedMapCache::kEntries) {
794 : return false;
795 : }
796 : #ifdef VERIFY_HEAP
797 : if (FLAG_verify_heap) {
798 : NormalizedMapCache cache = NormalizedMapCache::cast(obj);
799 : cache->NormalizedMapCacheVerify(cache->GetIsolate());
800 : }
801 : #endif
802 : return true;
803 : }
804 :
805 : } // namespace internal
806 : } // namespace v8
807 :
808 : #include "src/objects/object-macros-undef.h"
809 :
810 : #endif // V8_OBJECTS_MAP_INL_H_
|