Line data Source code
1 : // Copyright 2019 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 : #include "src/objects/map.h"
6 :
7 : #include "src/bootstrapper.h"
8 : #include "src/counters-inl.h"
9 : #include "src/field-type.h"
10 : #include "src/frames.h"
11 : #include "src/handles-inl.h"
12 : #include "src/heap/heap-write-barrier-inl.h"
13 : #include "src/isolate.h"
14 : #include "src/layout-descriptor.h"
15 : #include "src/log.h"
16 : #include "src/map-updater.h"
17 : #include "src/maybe-handles.h"
18 : #include "src/objects/descriptor-array.h"
19 : #include "src/objects/js-objects.h"
20 : #include "src/objects/maybe-object.h"
21 : #include "src/objects/oddball.h"
22 : #include "src/ostreams.h"
23 : #include "src/property.h"
24 : #include "src/roots.h"
25 : #include "src/transitions-inl.h"
26 : #include "src/zone/zone-containers.h"
27 :
28 : namespace v8 {
29 : namespace internal {
30 :
31 3677193 : Map Map::GetPrototypeChainRootMap(Isolate* isolate) const {
32 : DisallowHeapAllocation no_alloc;
33 3677193 : if (IsJSReceiverMap()) {
34 3302500 : return *this;
35 : }
36 : int constructor_function_index = GetConstructorFunctionIndex();
37 374693 : if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
38 374693 : Context native_context = isolate->context()->native_context();
39 : JSFunction constructor_function =
40 374693 : JSFunction::cast(native_context->get(constructor_function_index));
41 374693 : return constructor_function->initial_map();
42 : }
43 : return ReadOnlyRoots(isolate).null_value()->map();
44 : }
45 :
46 : // static
47 30719 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
48 : Handle<Map> map, Handle<Context> native_context) {
49 30719 : if (map->IsPrimitiveMap()) {
50 : int const constructor_function_index = map->GetConstructorFunctionIndex();
51 8005 : if (constructor_function_index != kNoConstructorFunctionIndex) {
52 : return handle(
53 : JSFunction::cast(native_context->get(constructor_function_index)),
54 16010 : native_context->GetIsolate());
55 : }
56 : }
57 22714 : return MaybeHandle<JSFunction>();
58 : }
59 :
60 0 : void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
61 : PropertyKind kind,
62 : PropertyAttributes attributes) {
63 0 : OFStream os(file);
64 0 : os << "[reconfiguring]";
65 0 : Name name = instance_descriptors()->GetKey(modify_index);
66 0 : if (name->IsString()) {
67 0 : String::cast(name)->PrintOn(file);
68 : } else {
69 0 : os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
70 : }
71 0 : os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
72 0 : os << attributes << " [";
73 0 : JavaScriptFrame::PrintTop(isolate, file, false, true);
74 0 : os << "]\n";
75 0 : }
76 :
77 50875378 : VisitorId Map::GetVisitorId(Map map) {
78 : STATIC_ASSERT(kVisitorIdCount <= 256);
79 :
80 50875378 : const int instance_type = map->instance_type();
81 :
82 50875378 : if (instance_type < FIRST_NONSTRING_TYPE) {
83 1288 : switch (instance_type & kStringRepresentationMask) {
84 : case kSeqStringTag:
85 224 : if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
86 : return kVisitSeqOneByteString;
87 : } else {
88 112 : return kVisitSeqTwoByteString;
89 : }
90 :
91 : case kConsStringTag:
92 112 : if (IsShortcutCandidate(instance_type)) {
93 : return kVisitShortcutCandidate;
94 : } else {
95 0 : return kVisitConsString;
96 : }
97 :
98 : case kSlicedStringTag:
99 : return kVisitSlicedString;
100 :
101 : case kExternalStringTag:
102 728 : return kVisitDataObject;
103 :
104 : case kThinStringTag:
105 112 : return kVisitThinString;
106 : }
107 0 : UNREACHABLE();
108 : }
109 :
110 50874090 : switch (instance_type) {
111 : case BYTE_ARRAY_TYPE:
112 : return kVisitByteArray;
113 :
114 : case BYTECODE_ARRAY_TYPE:
115 56 : return kVisitBytecodeArray;
116 :
117 : case FREE_SPACE_TYPE:
118 56 : return kVisitFreeSpace;
119 :
120 : case EMBEDDER_DATA_ARRAY_TYPE:
121 56 : return kVisitEmbedderDataArray;
122 :
123 : case FIXED_ARRAY_TYPE:
124 : case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
125 : case HASH_TABLE_TYPE:
126 : case ORDERED_HASH_MAP_TYPE:
127 : case ORDERED_HASH_SET_TYPE:
128 : case ORDERED_NAME_DICTIONARY_TYPE:
129 : case NAME_DICTIONARY_TYPE:
130 : case GLOBAL_DICTIONARY_TYPE:
131 : case NUMBER_DICTIONARY_TYPE:
132 : case SIMPLE_NUMBER_DICTIONARY_TYPE:
133 : case STRING_TABLE_TYPE:
134 : case SCOPE_INFO_TYPE:
135 : case SCRIPT_CONTEXT_TABLE_TYPE:
136 952 : return kVisitFixedArray;
137 :
138 : case AWAIT_CONTEXT_TYPE:
139 : case BLOCK_CONTEXT_TYPE:
140 : case CATCH_CONTEXT_TYPE:
141 : case DEBUG_EVALUATE_CONTEXT_TYPE:
142 : case EVAL_CONTEXT_TYPE:
143 : case FUNCTION_CONTEXT_TYPE:
144 : case MODULE_CONTEXT_TYPE:
145 : case SCRIPT_CONTEXT_TYPE:
146 : case WITH_CONTEXT_TYPE:
147 504 : return kVisitContext;
148 :
149 : case NATIVE_CONTEXT_TYPE:
150 56 : return kVisitNativeContext;
151 :
152 : case EPHEMERON_HASH_TABLE_TYPE:
153 56 : return kVisitEphemeronHashTable;
154 :
155 : case WEAK_FIXED_ARRAY_TYPE:
156 : case WEAK_ARRAY_LIST_TYPE:
157 112 : return kVisitWeakArray;
158 :
159 : case FIXED_DOUBLE_ARRAY_TYPE:
160 56 : return kVisitFixedDoubleArray;
161 :
162 : case PROPERTY_ARRAY_TYPE:
163 56 : return kVisitPropertyArray;
164 :
165 : case FEEDBACK_CELL_TYPE:
166 224 : return kVisitFeedbackCell;
167 :
168 : case FEEDBACK_VECTOR_TYPE:
169 56 : return kVisitFeedbackVector;
170 :
171 : case ODDBALL_TYPE:
172 616 : return kVisitOddball;
173 :
174 : case MAP_TYPE:
175 56 : return kVisitMap;
176 :
177 : case CODE_TYPE:
178 56 : return kVisitCode;
179 :
180 : case CELL_TYPE:
181 56 : return kVisitCell;
182 :
183 : case PROPERTY_CELL_TYPE:
184 56 : return kVisitPropertyCell;
185 :
186 : case DESCRIPTOR_ARRAY_TYPE:
187 56 : return kVisitDescriptorArray;
188 :
189 : case TRANSITION_ARRAY_TYPE:
190 56 : return kVisitTransitionArray;
191 :
192 : case JS_WEAK_MAP_TYPE:
193 : case JS_WEAK_SET_TYPE:
194 23397 : return kVisitJSWeakCollection;
195 :
196 : case CALL_HANDLER_INFO_TYPE:
197 168 : return kVisitStruct;
198 :
199 : case SHARED_FUNCTION_INFO_TYPE:
200 56 : return kVisitSharedFunctionInfo;
201 :
202 : case JS_PROXY_TYPE:
203 555 : return kVisitStruct;
204 :
205 : case SYMBOL_TYPE:
206 56 : return kVisitSymbol;
207 :
208 : case JS_ARRAY_BUFFER_TYPE:
209 12987 : return kVisitJSArrayBuffer;
210 :
211 : case JS_DATA_VIEW_TYPE:
212 901 : return kVisitJSDataView;
213 :
214 : case JS_FUNCTION_TYPE:
215 1552269 : return kVisitJSFunction;
216 :
217 : case JS_TYPED_ARRAY_TYPE:
218 31889 : return kVisitJSTypedArray;
219 :
220 : case SMALL_ORDERED_HASH_MAP_TYPE:
221 56 : return kVisitSmallOrderedHashMap;
222 :
223 : case SMALL_ORDERED_HASH_SET_TYPE:
224 56 : return kVisitSmallOrderedHashSet;
225 :
226 : case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
227 56 : return kVisitSmallOrderedNameDictionary;
228 :
229 : case CODE_DATA_CONTAINER_TYPE:
230 56 : return kVisitCodeDataContainer;
231 :
232 : case WASM_INSTANCE_TYPE:
233 81011 : return kVisitWasmInstanceObject;
234 :
235 : case PREPARSE_DATA_TYPE:
236 56 : return kVisitPreparseData;
237 :
238 : case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
239 56 : return kVisitUncompiledDataWithoutPreparseData;
240 :
241 : case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE:
242 56 : return kVisitUncompiledDataWithPreparseData;
243 :
244 : case JS_OBJECT_TYPE:
245 : case JS_ERROR_TYPE:
246 : case JS_ARGUMENTS_TYPE:
247 : case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
248 : case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
249 : case JS_GENERATOR_OBJECT_TYPE:
250 : case JS_ASYNC_FUNCTION_OBJECT_TYPE:
251 : case JS_ASYNC_GENERATOR_OBJECT_TYPE:
252 : case JS_MODULE_NAMESPACE_TYPE:
253 : case JS_VALUE_TYPE:
254 : case JS_DATE_TYPE:
255 : case JS_ARRAY_ITERATOR_TYPE:
256 : case JS_ARRAY_TYPE:
257 : case JS_GLOBAL_PROXY_TYPE:
258 : case JS_GLOBAL_OBJECT_TYPE:
259 : case JS_MESSAGE_OBJECT_TYPE:
260 : case JS_SET_TYPE:
261 : case JS_MAP_TYPE:
262 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
263 : case JS_SET_VALUE_ITERATOR_TYPE:
264 : case JS_MAP_KEY_ITERATOR_TYPE:
265 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
266 : case JS_MAP_VALUE_ITERATOR_TYPE:
267 : case JS_STRING_ITERATOR_TYPE:
268 : case JS_PROMISE_TYPE:
269 : case JS_REGEXP_TYPE:
270 : case JS_REGEXP_STRING_ITERATOR_TYPE:
271 : case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
272 : case JS_FINALIZATION_GROUP_TYPE:
273 : #ifdef V8_INTL_SUPPORT
274 : case JS_INTL_V8_BREAK_ITERATOR_TYPE:
275 : case JS_INTL_COLLATOR_TYPE:
276 : case JS_INTL_DATE_TIME_FORMAT_TYPE:
277 : case JS_INTL_LIST_FORMAT_TYPE:
278 : case JS_INTL_LOCALE_TYPE:
279 : case JS_INTL_NUMBER_FORMAT_TYPE:
280 : case JS_INTL_PLURAL_RULES_TYPE:
281 : case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
282 : case JS_INTL_SEGMENT_ITERATOR_TYPE:
283 : case JS_INTL_SEGMENTER_TYPE:
284 : #endif // V8_INTL_SUPPORT
285 : case WASM_EXCEPTION_TYPE:
286 : case WASM_GLOBAL_TYPE:
287 : case WASM_MEMORY_TYPE:
288 : case WASM_MODULE_TYPE:
289 : case WASM_TABLE_TYPE:
290 : case JS_BOUND_FUNCTION_TYPE: {
291 : const bool has_raw_data_fields =
292 41795282 : (FLAG_unbox_double_fields && !map->HasFastPointerLayout()) ||
293 : (COMPRESS_POINTERS_BOOL && JSObject::GetEmbedderFieldCount(map) > 0);
294 41795288 : return has_raw_data_fields ? kVisitJSObject : kVisitJSObjectFast;
295 : }
296 : case JS_API_OBJECT_TYPE:
297 : case JS_SPECIAL_API_OBJECT_TYPE:
298 7367577 : return kVisitJSApiObject;
299 :
300 : case JS_WEAK_REF_TYPE:
301 844 : return kVisitJSWeakRef;
302 :
303 : case WEAK_CELL_TYPE:
304 56 : return kVisitWeakCell;
305 :
306 : case FILLER_TYPE:
307 : case FOREIGN_TYPE:
308 : case HEAP_NUMBER_TYPE:
309 : case MUTABLE_HEAP_NUMBER_TYPE:
310 : case FEEDBACK_METADATA_TYPE:
311 341 : return kVisitDataObject;
312 :
313 : case BIGINT_TYPE:
314 56 : return kVisitBigInt;
315 :
316 : case FIXED_UINT8_ARRAY_TYPE:
317 : case FIXED_INT8_ARRAY_TYPE:
318 : case FIXED_UINT16_ARRAY_TYPE:
319 : case FIXED_INT16_ARRAY_TYPE:
320 : case FIXED_UINT32_ARRAY_TYPE:
321 : case FIXED_INT32_ARRAY_TYPE:
322 : case FIXED_FLOAT32_ARRAY_TYPE:
323 : case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
324 : case FIXED_BIGUINT64_ARRAY_TYPE:
325 : case FIXED_BIGINT64_ARRAY_TYPE:
326 560 : return kVisitFixedTypedArrayBase;
327 :
328 : case FIXED_FLOAT64_ARRAY_TYPE:
329 56 : return kVisitFixedFloat64Array;
330 :
331 : case ALLOCATION_SITE_TYPE:
332 112 : return kVisitAllocationSite;
333 :
334 : #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
335 : STRUCT_LIST(MAKE_STRUCT_CASE)
336 : #undef MAKE_STRUCT_CASE
337 1904 : if (instance_type == PROTOTYPE_INFO_TYPE) {
338 : return kVisitPrototypeInfo;
339 : }
340 1848 : return kVisitStruct;
341 :
342 : case LOAD_HANDLER_TYPE:
343 : case STORE_HANDLER_TYPE:
344 392 : return kVisitDataHandler;
345 :
346 : default:
347 0 : UNREACHABLE();
348 : }
349 : }
350 :
351 0 : void Map::PrintGeneralization(
352 : Isolate* isolate, FILE* file, const char* reason, int modify_index,
353 : int split, int descriptors, bool descriptor_to_field,
354 : Representation old_representation, Representation new_representation,
355 : MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
356 : MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
357 0 : OFStream os(file);
358 0 : os << "[generalizing]";
359 0 : Name name = instance_descriptors()->GetKey(modify_index);
360 0 : if (name->IsString()) {
361 0 : String::cast(name)->PrintOn(file);
362 : } else {
363 0 : os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
364 : }
365 0 : os << ":";
366 0 : if (descriptor_to_field) {
367 0 : os << "c";
368 : } else {
369 0 : os << old_representation.Mnemonic() << "{";
370 0 : if (old_field_type.is_null()) {
371 0 : os << Brief(*(old_value.ToHandleChecked()));
372 : } else {
373 0 : old_field_type.ToHandleChecked()->PrintTo(os);
374 : }
375 0 : os << "}";
376 : }
377 0 : os << "->" << new_representation.Mnemonic() << "{";
378 0 : if (new_field_type.is_null()) {
379 0 : os << Brief(*(new_value.ToHandleChecked()));
380 : } else {
381 0 : new_field_type.ToHandleChecked()->PrintTo(os);
382 : }
383 0 : os << "} (";
384 0 : if (strlen(reason) > 0) {
385 0 : os << reason;
386 : } else {
387 0 : os << "+" << (descriptors - split) << " maps";
388 : }
389 0 : os << ") [";
390 0 : JavaScriptFrame::PrintTop(isolate, file, false, true);
391 0 : os << "]\n";
392 0 : }
393 :
394 : // static
395 16224065 : MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) {
396 16224072 : if (type->IsClass()) {
397 12187746 : return MaybeObjectHandle::Weak(type->AsClass(), isolate);
398 : }
399 10130197 : return MaybeObjectHandle(type);
400 : }
401 :
402 : // static
403 41001738 : FieldType Map::UnwrapFieldType(MaybeObject wrapped_type) {
404 41001738 : if (wrapped_type->IsCleared()) {
405 82 : return FieldType::None();
406 : }
407 41001656 : HeapObject heap_object;
408 41001656 : if (wrapped_type->GetHeapObjectIfWeak(&heap_object)) {
409 2720840 : return FieldType::cast(heap_object);
410 : }
411 : return wrapped_type->cast<FieldType>();
412 : }
413 :
414 15903082 : MaybeHandle<Map> Map::CopyWithField(Isolate* isolate, Handle<Map> map,
415 : Handle<Name> name, Handle<FieldType> type,
416 : PropertyAttributes attributes,
417 : PropertyConstness constness,
418 : Representation representation,
419 : TransitionFlag flag) {
420 : DCHECK(DescriptorArray::kNotFound ==
421 : map->instance_descriptors()->Search(*name,
422 : map->NumberOfOwnDescriptors()));
423 :
424 : // Ensure the descriptor array does not get too big.
425 15903084 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
426 150 : return MaybeHandle<Map>();
427 : }
428 :
429 : // Compute the new index for new field.
430 15902936 : int index = map->NextFreePropertyIndex();
431 :
432 15902944 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
433 : constness = PropertyConstness::kMutable;
434 3625 : representation = Representation::Tagged();
435 3625 : type = FieldType::Any(isolate);
436 : } else {
437 : Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
438 15899318 : isolate, map->instance_type(), &constness, &representation, &type);
439 : }
440 :
441 15902942 : MaybeObjectHandle wrapped_type = WrapFieldType(isolate, type);
442 :
443 : DCHECK_IMPLIES(!FLAG_track_constant_fields,
444 : constness == PropertyConstness::kMutable);
445 : Descriptor d = Descriptor::DataField(name, index, attributes, constness,
446 15902941 : representation, wrapped_type);
447 15902939 : Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
448 15902943 : new_map->AccountAddedPropertyField();
449 15902943 : return new_map;
450 : }
451 :
452 35 : MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map,
453 : Handle<Name> name,
454 : Handle<Object> constant,
455 : PropertyAttributes attributes,
456 : TransitionFlag flag) {
457 : // Ensure the descriptor array does not get too big.
458 35 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
459 0 : return MaybeHandle<Map>();
460 : }
461 :
462 : if (FLAG_track_constant_fields) {
463 35 : Representation representation = constant->OptimalRepresentation();
464 35 : Handle<FieldType> type = constant->OptimalType(isolate, representation);
465 : return CopyWithField(isolate, map, name, type, attributes,
466 35 : PropertyConstness::kConst, representation, flag);
467 : } else {
468 : // Allocate new instance descriptors with (name, constant) added.
469 : Descriptor d =
470 : Descriptor::DataConstant(isolate, name, 0, constant, attributes);
471 : Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
472 : return new_map;
473 : }
474 : }
475 :
476 0 : bool Map::TransitionRemovesTaggedField(Map target) const {
477 0 : int inobject = NumberOfFields();
478 0 : int target_inobject = target->NumberOfFields();
479 0 : for (int i = target_inobject; i < inobject; i++) {
480 0 : FieldIndex index = FieldIndex::ForPropertyIndex(*this, i);
481 0 : if (!IsUnboxedDoubleField(index)) return true;
482 : }
483 : return false;
484 : }
485 :
486 0 : bool Map::TransitionChangesTaggedFieldToUntaggedField(Map target) const {
487 0 : int inobject = NumberOfFields();
488 0 : int target_inobject = target->NumberOfFields();
489 : int limit = Min(inobject, target_inobject);
490 0 : for (int i = 0; i < limit; i++) {
491 0 : FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
492 0 : if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
493 0 : return true;
494 : }
495 : }
496 : return false;
497 : }
498 :
499 0 : bool Map::TransitionRequiresSynchronizationWithGC(Map target) const {
500 0 : return TransitionRemovesTaggedField(target) ||
501 0 : TransitionChangesTaggedFieldToUntaggedField(target);
502 : }
503 :
504 83910 : bool Map::InstancesNeedRewriting(Map target) const {
505 83910 : int target_number_of_fields = target->NumberOfFields();
506 83910 : int target_inobject = target->GetInObjectProperties();
507 83910 : int target_unused = target->UnusedPropertyFields();
508 : int old_number_of_fields;
509 :
510 : return InstancesNeedRewriting(target, target_number_of_fields,
511 : target_inobject, target_unused,
512 83910 : &old_number_of_fields);
513 : }
514 :
515 14383037 : bool Map::InstancesNeedRewriting(Map target, int target_number_of_fields,
516 : int target_inobject, int target_unused,
517 : int* old_number_of_fields) const {
518 : // If fields were added (or removed), rewrite the instance.
519 14383037 : *old_number_of_fields = NumberOfFields();
520 : DCHECK(target_number_of_fields >= *old_number_of_fields);
521 14383036 : if (target_number_of_fields != *old_number_of_fields) return true;
522 :
523 : // If smi descriptors were replaced by double descriptors, rewrite.
524 5438333 : DescriptorArray old_desc = instance_descriptors();
525 5438334 : DescriptorArray new_desc = target->instance_descriptors();
526 : int limit = NumberOfOwnDescriptors();
527 11146857 : for (int i = 0; i < limit; i++) {
528 11422016 : if (new_desc->GetDetails(i).representation().IsDouble() !=
529 11422015 : old_desc->GetDetails(i).representation().IsDouble()) {
530 : return true;
531 : }
532 : }
533 :
534 : // If no fields were added, and no inobject properties were removed, setting
535 : // the map is sufficient.
536 5435848 : if (target_inobject == GetInObjectProperties()) return false;
537 : // In-object slack tracking may have reduced the object size of the new map.
538 : // In that case, succeed if all existing fields were inobject, and they still
539 : // fit within the new inobject size.
540 : DCHECK(target_inobject < GetInObjectProperties());
541 1 : if (target_number_of_fields <= target_inobject) {
542 : DCHECK(target_number_of_fields + target_unused == target_inobject);
543 : return false;
544 : }
545 : // Otherwise, properties will need to be moved to the backing store.
546 0 : return true;
547 : }
548 :
549 36540579 : int Map::NumberOfFields() const {
550 36540579 : DescriptorArray descriptors = instance_descriptors();
551 : int result = 0;
552 495715022 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
553 422633853 : if (descriptors->GetDetails(i).location() == kField) result++;
554 : }
555 36540584 : return result;
556 : }
557 :
558 2448057 : Map::FieldCounts Map::GetFieldCounts() const {
559 2448057 : DescriptorArray descriptors = instance_descriptors();
560 : int mutable_count = 0;
561 : int const_count = 0;
562 283353502 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
563 139228694 : PropertyDetails details = descriptors->GetDetails(i);
564 139228694 : if (details.location() == kField) {
565 138526566 : switch (details.constness()) {
566 : case PropertyConstness::kMutable:
567 24305 : mutable_count++;
568 24305 : break;
569 : case PropertyConstness::kConst:
570 138502261 : const_count++;
571 138502261 : break;
572 : }
573 : }
574 : }
575 2448057 : return FieldCounts(mutable_count, const_count);
576 : }
577 :
578 0 : bool Map::HasOutOfObjectProperties() const {
579 0 : return GetInObjectProperties() < NumberOfFields();
580 : }
581 :
582 17244 : Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
583 : ElementsKind elements_kind,
584 : int modify_index, PropertyKind kind,
585 : PropertyAttributes attributes,
586 : const char* reason) {
587 34488 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
588 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
589 : Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo(
590 17244 : isolate, old_descriptors, number_of_own_descriptors);
591 17244 : descriptors->GeneralizeAllFields();
592 :
593 : Handle<LayoutDescriptor> new_layout_descriptor(
594 : LayoutDescriptor::FastPointerLayout(), isolate);
595 : Handle<Map> new_map = CopyReplaceDescriptors(
596 : isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
597 17244 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
598 :
599 : // Unless the instance is being migrated, ensure that modify_index is a field.
600 17244 : if (modify_index >= 0) {
601 17230 : PropertyDetails details = descriptors->GetDetails(modify_index);
602 18555 : if (details.constness() != PropertyConstness::kMutable ||
603 18555 : details.location() != kField || details.attributes() != attributes) {
604 : int field_index = details.location() == kField
605 : ? details.field_index()
606 32083 : : new_map->NumberOfFields();
607 : Descriptor d = Descriptor::DataField(
608 : isolate, handle(descriptors->GetKey(modify_index), isolate),
609 32356 : field_index, attributes, Representation::Tagged());
610 16178 : descriptors->Replace(modify_index, &d);
611 16178 : if (details.location() != kField) {
612 15905 : new_map->AccountAddedPropertyField();
613 : }
614 : } else {
615 : DCHECK(details.attributes() == attributes);
616 : }
617 :
618 17230 : if (FLAG_trace_generalization) {
619 0 : MaybeHandle<FieldType> field_type = FieldType::None(isolate);
620 0 : if (details.location() == kField) {
621 : field_type = handle(
622 0 : map->instance_descriptors()->GetFieldType(modify_index), isolate);
623 : }
624 : map->PrintGeneralization(
625 : isolate, stdout, reason, modify_index,
626 : new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(),
627 : details.location() == kDescriptor, details.representation(),
628 : Representation::Tagged(), field_type, MaybeHandle<Object>(),
629 0 : FieldType::Any(isolate), MaybeHandle<Object>());
630 : }
631 : }
632 34488 : new_map->set_elements_kind(elements_kind);
633 17244 : return new_map;
634 : }
635 :
636 36575 : void Map::DeprecateTransitionTree(Isolate* isolate) {
637 36527 : if (is_deprecated()) return;
638 : DisallowHeapAllocation no_gc;
639 : TransitionsAccessor transitions(isolate, *this, &no_gc);
640 36527 : int num_transitions = transitions.NumberOfTransitions();
641 62581 : for (int i = 0; i < num_transitions; ++i) {
642 26054 : transitions.GetTarget(i)->DeprecateTransitionTree(isolate);
643 : }
644 : DCHECK(!constructor_or_backpointer()->IsFunctionTemplateInfo());
645 36527 : set_is_deprecated(true);
646 36527 : if (FLAG_trace_maps) {
647 96 : LOG(isolate, MapEvent("Deprecate", *this, Map()));
648 : }
649 : dependent_code()->DeoptimizeDependentCodeGroup(
650 36527 : isolate, DependentCode::kTransitionGroup);
651 36527 : NotifyLeafMapLayoutChange(isolate);
652 : }
653 :
654 : // Installs |new_descriptors| over the current instance_descriptors to ensure
655 : // proper sharing of descriptor arrays.
656 12047 : void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors,
657 : LayoutDescriptor new_layout_descriptor) {
658 : // Don't overwrite the empty descriptor array or initial map's descriptors.
659 19254 : if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
660 4972 : return;
661 : }
662 :
663 7075 : DescriptorArray to_replace = instance_descriptors();
664 : // Replace descriptors by new_descriptors in all maps that share it. The old
665 : // descriptors will not be trimmed in the mark-compactor, we need to mark
666 : // all its elements.
667 7075 : Map current = *this;
668 : MarkingBarrierForDescriptorArray(isolate->heap(), current, to_replace,
669 7075 : to_replace->number_of_descriptors());
670 48384 : while (current->instance_descriptors() == to_replace) {
671 34533 : Object next = current->GetBackPointer();
672 34533 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
673 34234 : current->SetEnumLength(kInvalidEnumCacheSentinel);
674 : current->UpdateDescriptors(isolate, new_descriptors, new_layout_descriptor,
675 34234 : current->NumberOfOwnDescriptors());
676 34234 : current = Map::cast(next);
677 : }
678 7075 : set_owns_descriptors(false);
679 : }
680 :
681 1000178 : Map Map::FindRootMap(Isolate* isolate) const {
682 1000178 : Map result = *this;
683 : while (true) {
684 1781908 : Object back = result->GetBackPointer();
685 1781909 : if (back->IsUndefined(isolate)) {
686 : // Initial map always owns descriptors and doesn't have unused entries
687 : // in the descriptor array.
688 : DCHECK(result->owns_descriptors());
689 : DCHECK_EQ(result->NumberOfOwnDescriptors(),
690 : result->instance_descriptors()->number_of_descriptors());
691 1000180 : return result;
692 : }
693 781730 : result = Map::cast(back);
694 781730 : }
695 : }
696 :
697 503660 : Map Map::FindFieldOwner(Isolate* isolate, int descriptor) const {
698 : DisallowHeapAllocation no_allocation;
699 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
700 503660 : Map result = *this;
701 : while (true) {
702 1552350 : Object back = result->GetBackPointer();
703 1552350 : if (back->IsUndefined(isolate)) break;
704 : const Map parent = Map::cast(back);
705 1469484 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
706 1048690 : result = parent;
707 : }
708 1048690 : return result;
709 : }
710 :
711 504243 : void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
712 : PropertyConstness new_constness,
713 : Representation new_representation,
714 : const MaybeObjectHandle& new_wrapped_type) {
715 : DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeak());
716 : // We store raw pointers in the queue, so no allocations are allowed.
717 : DisallowHeapAllocation no_allocation;
718 252120 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
719 252123 : if (details.location() != kField) return;
720 : DCHECK_EQ(kData, details.kind());
721 :
722 252123 : Zone zone(isolate->allocator(), ZONE_NAME);
723 252119 : ZoneQueue<Map> backlog(&zone);
724 : backlog.push(*this);
725 :
726 1731908 : while (!backlog.empty()) {
727 1479785 : Map current = backlog.front();
728 : backlog.pop();
729 :
730 : TransitionsAccessor transitions(isolate, current, &no_allocation);
731 1479787 : int num_transitions = transitions.NumberOfTransitions();
732 2707449 : for (int i = 0; i < num_transitions; ++i) {
733 1227665 : Map target = transitions.GetTarget(i);
734 : backlog.push(target);
735 : }
736 1479784 : DescriptorArray descriptors = current->instance_descriptors();
737 1479786 : PropertyDetails details = descriptors->GetDetails(descriptor);
738 :
739 : // Currently constness change implies map change.
740 : DCHECK_IMPLIES(new_constness != details.constness(),
741 : FLAG_modify_map_inplace);
742 :
743 : // It is allowed to change representation here only from None to something.
744 : DCHECK(details.representation().Equals(new_representation) ||
745 : details.representation().IsNone());
746 :
747 : // Skip if already updated the shared descriptor.
748 4439355 : if ((FLAG_modify_map_inplace && new_constness != details.constness()) ||
749 5753423 : descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) {
750 : DCHECK_IMPLIES(!FLAG_track_constant_fields,
751 : new_constness == PropertyConstness::kMutable);
752 : Descriptor d = Descriptor::DataField(
753 : name, descriptors->GetFieldIndex(descriptor), details.attributes(),
754 252299 : new_constness, new_representation, new_wrapped_type);
755 252297 : descriptors->Replace(descriptor, &d);
756 : }
757 252123 : }
758 : }
759 :
760 0 : bool FieldTypeIsCleared(Representation rep, FieldType type) {
761 1690142 : return type->IsNone() && rep.IsHeapObject();
762 : }
763 :
764 : // static
765 599845 : Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
766 : Handle<FieldType> type1,
767 : Representation rep2,
768 : Handle<FieldType> type2,
769 : Isolate* isolate) {
770 : // Cleared field types need special treatment. They represent lost knowledge,
771 : // so we must be conservative, so their generalization with any other type
772 : // is "Any".
773 1199666 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
774 5454 : return FieldType::Any(isolate);
775 : }
776 594401 : if (type1->NowIs(type2)) return type2;
777 53834 : if (type2->NowIs(type1)) return type1;
778 20209 : return FieldType::Any(isolate);
779 : }
780 :
781 : // static
782 711237 : void Map::GeneralizeField(Isolate* isolate, Handle<Map> map, int modify_index,
783 : PropertyConstness new_constness,
784 : Representation new_representation,
785 : Handle<FieldType> new_field_type) {
786 : // Check if we actually need to generalize the field type at all.
787 1422474 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
788 711240 : PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
789 : PropertyConstness old_constness = old_details.constness();
790 : Representation old_representation = old_details.representation();
791 : Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
792 1422482 : isolate);
793 :
794 : // Return if the current map is general enough to hold requested constness and
795 : // representation/field type.
796 940422 : if (((FLAG_modify_map_inplace &&
797 : IsGeneralizableTo(new_constness, old_constness)) ||
798 656138 : (!FLAG_modify_map_inplace && (old_constness == new_constness))) &&
799 482066 : old_representation.Equals(new_representation) &&
800 1193293 : !FieldTypeIsCleared(new_representation, *new_field_type) &&
801 : // Checking old_field_type for being cleared is not necessary because
802 : // the NowIs check below would fail anyway in that case.
803 1675352 : new_field_type->NowIs(old_field_type)) {
804 : DCHECK(GeneralizeFieldType(old_representation, old_field_type,
805 : new_representation, new_field_type, isolate)
806 : ->NowIs(old_field_type));
807 459120 : return;
808 : }
809 :
810 : // Determine the field owner.
811 504240 : Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate);
812 : Handle<DescriptorArray> descriptors(field_owner->instance_descriptors(),
813 504240 : isolate);
814 : DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
815 :
816 : new_field_type =
817 : Map::GeneralizeFieldType(old_representation, old_field_type,
818 252119 : new_representation, new_field_type, isolate);
819 : if (FLAG_modify_map_inplace) {
820 : new_constness = GeneralizeConstness(old_constness, new_constness);
821 : }
822 :
823 252122 : PropertyDetails details = descriptors->GetDetails(modify_index);
824 504243 : Handle<Name> name(descriptors->GetKey(modify_index), isolate);
825 :
826 252120 : MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
827 : field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
828 252123 : new_representation, wrapped_type);
829 504242 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
830 252121 : isolate, DependentCode::kFieldOwnerGroup);
831 :
832 252121 : if (FLAG_trace_generalization) {
833 : map->PrintGeneralization(
834 : isolate, stdout, "field type generalization", modify_index,
835 : map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
836 : details.representation(), details.representation(), old_field_type,
837 0 : MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
838 : }
839 : }
840 :
841 : // TODO(ishell): remove.
842 : // static
843 635 : Handle<Map> Map::ReconfigureProperty(Isolate* isolate, Handle<Map> map,
844 : int modify_index, PropertyKind new_kind,
845 : PropertyAttributes new_attributes,
846 : Representation new_representation,
847 : Handle<FieldType> new_field_type) {
848 : DCHECK_EQ(kData, new_kind); // Only kData case is supported.
849 635 : MapUpdater mu(isolate, map);
850 : return mu.ReconfigureToDataField(modify_index, new_attributes,
851 : PropertyConstness::kConst,
852 635 : new_representation, new_field_type);
853 : }
854 :
855 : // TODO(ishell): remove.
856 : // static
857 147 : Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
858 : ElementsKind new_elements_kind) {
859 295076 : MapUpdater mu(isolate, map);
860 295076 : return mu.ReconfigureElementsKind(new_elements_kind);
861 : }
862 :
863 : namespace {
864 :
865 : Map SearchMigrationTarget(Isolate* isolate, Map old_map) {
866 : DisallowHeapAllocation no_allocation;
867 : DisallowDeoptimization no_deoptimization(isolate);
868 :
869 : Map target = old_map;
870 : do {
871 : target = TransitionsAccessor(isolate, target, &no_allocation)
872 : .GetMigrationTarget();
873 : } while (!target.is_null() && target->is_deprecated());
874 : if (target.is_null()) return Map();
875 :
876 : // TODO(ishell): if this validation ever become a bottleneck consider adding a
877 : // bit to the Map telling whether it contains fields whose field types may be
878 : // cleared.
879 : // TODO(ishell): revisit handling of cleared field types in
880 : // TryReplayPropertyTransitions() and consider checking the target map's field
881 : // types instead of old_map's types.
882 : // Go to slow map updating if the old_map has fast properties with cleared
883 : // field types.
884 : int old_nof = old_map->NumberOfOwnDescriptors();
885 : DescriptorArray old_descriptors = old_map->instance_descriptors();
886 : for (int i = 0; i < old_nof; i++) {
887 : PropertyDetails old_details = old_descriptors->GetDetails(i);
888 : if (old_details.location() == kField && old_details.kind() == kData) {
889 : FieldType old_type = old_descriptors->GetFieldType(i);
890 : if (FieldTypeIsCleared(old_details.representation(), old_type)) {
891 : return Map();
892 : }
893 : }
894 : }
895 :
896 : SLOW_DCHECK(Map::TryUpdateSlow(isolate, old_map) == target);
897 : return target;
898 : }
899 : } // namespace
900 :
901 : // TODO(ishell): Move TryUpdate() and friends to MapUpdater
902 : // static
903 193579 : MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
904 : DisallowHeapAllocation no_allocation;
905 : DisallowDeoptimization no_deoptimization(isolate);
906 :
907 193579 : if (!old_map->is_deprecated()) return old_map;
908 :
909 : if (FLAG_fast_map_update) {
910 : Map target_map = SearchMigrationTarget(isolate, *old_map);
911 : if (!target_map.is_null()) {
912 : return handle(target_map, isolate);
913 : }
914 : }
915 :
916 617 : Map new_map = TryUpdateSlow(isolate, *old_map);
917 617 : if (new_map.is_null()) return MaybeHandle<Map>();
918 : if (FLAG_fast_map_update) {
919 : TransitionsAccessor(isolate, *old_map, &no_allocation)
920 : .SetMigrationTarget(new_map);
921 : }
922 601 : return handle(new_map, isolate);
923 : }
924 :
925 : namespace {
926 :
927 : struct IntegrityLevelTransitionInfo {
928 : explicit IntegrityLevelTransitionInfo(Map map)
929 841 : : integrity_level_source_map(map) {}
930 :
931 : bool has_integrity_level_transition = false;
932 : PropertyAttributes integrity_level = NONE;
933 : Map integrity_level_source_map;
934 : Symbol integrity_level_symbol;
935 : };
936 :
937 224 : IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions(
938 : Map map, Isolate* isolate, DisallowHeapAllocation* no_allocation) {
939 : IntegrityLevelTransitionInfo info(map);
940 :
941 : DCHECK(!map->is_extensible());
942 224 : Map source_map = map;
943 : // Skip integrity level transitions.
944 448 : while (!source_map->is_extensible()) {
945 448 : source_map = Map::cast(source_map->GetBackPointer());
946 : }
947 :
948 : // If there are some non-integrity-level transitions after the first
949 : // non-extensible transitions, e.g., if there were private symbols transitions
950 : // after the first integrity level transition, then we just bail out.
951 224 : if (map->NumberOfOwnDescriptors() != source_map->NumberOfOwnDescriptors()) {
952 : return info;
953 : }
954 :
955 : // Figure out the most restrictive integrity level transition (it should
956 : // be the last one in the transition tree).
957 : ReadOnlyRoots roots(isolate);
958 : TransitionsAccessor transitions(isolate, Map::cast(map->GetBackPointer()),
959 224 : no_allocation);
960 448 : if (transitions.SearchSpecial(roots.frozen_symbol()) == map) {
961 70 : info.integrity_level = FROZEN;
962 70 : info.integrity_level_symbol = roots.frozen_symbol();
963 308 : } else if (transitions.SearchSpecial(roots.sealed_symbol()) == map) {
964 84 : info.integrity_level = SEALED;
965 84 : info.integrity_level_symbol = roots.sealed_symbol();
966 : } else {
967 140 : CHECK_EQ(transitions.SearchSpecial(roots.nonextensible_symbol()), map);
968 70 : info.integrity_level = NONE;
969 70 : info.integrity_level_symbol = roots.nonextensible_symbol();
970 : }
971 :
972 224 : info.has_integrity_level_transition = true;
973 224 : info.integrity_level_source_map = source_map;
974 :
975 : return info;
976 : }
977 :
978 : } // namespace
979 :
980 617 : Map Map::TryUpdateSlow(Isolate* isolate, Map old_map) {
981 : DisallowHeapAllocation no_allocation;
982 : DisallowDeoptimization no_deoptimization(isolate);
983 :
984 : // Check the state of the root map.
985 617 : Map root_map = old_map->FindRootMap(isolate);
986 617 : if (root_map->is_deprecated()) {
987 0 : JSFunction constructor = JSFunction::cast(root_map->GetConstructor());
988 : DCHECK(constructor->has_initial_map());
989 : DCHECK(constructor->initial_map()->is_dictionary_map());
990 0 : if (constructor->initial_map()->elements_kind() !=
991 : old_map->elements_kind()) {
992 0 : return Map();
993 : }
994 0 : return constructor->initial_map();
995 : }
996 617 : if (!old_map->EquivalentToForTransition(root_map)) return Map();
997 :
998 : ElementsKind from_kind = root_map->elements_kind();
999 : ElementsKind to_kind = old_map->elements_kind();
1000 :
1001 : IntegrityLevelTransitionInfo info(old_map);
1002 617 : if (root_map->is_extensible() != old_map->is_extensible()) {
1003 : DCHECK(!old_map->is_extensible());
1004 : DCHECK(root_map->is_extensible());
1005 224 : info = DetectIntegrityLevelTransitions(old_map, isolate, &no_allocation);
1006 : // Bail out if there were some private symbol transitions mixed up
1007 : // with the integrity level transitions.
1008 224 : if (!info.has_integrity_level_transition) return Map();
1009 : // Make sure replay the original elements kind transitions, before
1010 : // the integrity level transition sets the elements to dictionary mode.
1011 : DCHECK(to_kind == DICTIONARY_ELEMENTS ||
1012 : IsFixedTypedArrayElementsKind(to_kind));
1013 : to_kind = info.integrity_level_source_map->elements_kind();
1014 : }
1015 617 : if (from_kind != to_kind) {
1016 : // Try to follow existing elements kind transitions.
1017 14 : root_map = root_map->LookupElementsTransitionMap(isolate, to_kind);
1018 14 : if (root_map.is_null()) return Map();
1019 : // From here on, use the map with correct elements kind as root map.
1020 : }
1021 :
1022 : // Replay the transitions as they were before the integrity level transition.
1023 : Map result = root_map->TryReplayPropertyTransitions(
1024 617 : isolate, info.integrity_level_source_map);
1025 617 : if (result.is_null()) return Map();
1026 :
1027 601 : if (info.has_integrity_level_transition) {
1028 : // Now replay the integrity level transition.
1029 : result = TransitionsAccessor(isolate, result, &no_allocation)
1030 224 : .SearchSpecial(info.integrity_level_symbol);
1031 : }
1032 :
1033 : DCHECK_EQ(old_map->elements_kind(), result->elements_kind());
1034 : DCHECK_EQ(old_map->instance_type(), result->instance_type());
1035 601 : return result;
1036 : }
1037 :
1038 90635 : Map Map::TryReplayPropertyTransitions(Isolate* isolate, Map old_map) {
1039 : DisallowHeapAllocation no_allocation;
1040 : DisallowDeoptimization no_deoptimization(isolate);
1041 :
1042 : int root_nof = NumberOfOwnDescriptors();
1043 :
1044 : int old_nof = old_map->NumberOfOwnDescriptors();
1045 90635 : DescriptorArray old_descriptors = old_map->instance_descriptors();
1046 :
1047 90635 : Map new_map = *this;
1048 94831 : for (int i = root_nof; i < old_nof; ++i) {
1049 10320 : PropertyDetails old_details = old_descriptors->GetDetails(i);
1050 : Map transition =
1051 : TransitionsAccessor(isolate, new_map, &no_allocation)
1052 : .SearchTransition(old_descriptors->GetKey(i), old_details.kind(),
1053 20640 : old_details.attributes());
1054 10320 : if (transition.is_null()) return Map();
1055 4238 : new_map = transition;
1056 4238 : DescriptorArray new_descriptors = new_map->instance_descriptors();
1057 :
1058 4238 : PropertyDetails new_details = new_descriptors->GetDetails(i);
1059 : DCHECK_EQ(old_details.kind(), new_details.kind());
1060 : DCHECK_EQ(old_details.attributes(), new_details.attributes());
1061 4238 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
1062 0 : return Map();
1063 : }
1064 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
1065 12714 : if (!old_details.representation().fits_into(new_details.representation())) {
1066 33 : return Map();
1067 : }
1068 4205 : if (new_details.location() == kField) {
1069 4205 : if (new_details.kind() == kData) {
1070 4205 : FieldType new_type = new_descriptors->GetFieldType(i);
1071 : // Cleared field types need special treatment. They represent lost
1072 : // knowledge, so we must first generalize the new_type to "Any".
1073 4205 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
1074 0 : return Map();
1075 : }
1076 : DCHECK_EQ(kData, old_details.kind());
1077 4205 : if (old_details.location() == kField) {
1078 4205 : FieldType old_type = old_descriptors->GetFieldType(i);
1079 8410 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
1080 4205 : !old_type->NowIs(new_type)) {
1081 9 : return Map();
1082 : }
1083 : } else {
1084 : DCHECK_EQ(kDescriptor, old_details.location());
1085 : DCHECK(!FLAG_track_constant_fields);
1086 0 : Object old_value = old_descriptors->GetStrongValue(i);
1087 0 : if (!new_type->NowContains(old_value)) {
1088 0 : return Map();
1089 : }
1090 : }
1091 :
1092 : } else {
1093 : DCHECK_EQ(kAccessor, new_details.kind());
1094 : #ifdef DEBUG
1095 : FieldType new_type = new_descriptors->GetFieldType(i);
1096 : DCHECK(new_type->IsAny());
1097 : #endif
1098 0 : UNREACHABLE();
1099 : }
1100 : } else {
1101 : DCHECK_EQ(kDescriptor, new_details.location());
1102 0 : if (old_details.location() == kField ||
1103 : old_descriptors->GetStrongValue(i) !=
1104 : new_descriptors->GetStrongValue(i)) {
1105 0 : return Map();
1106 : }
1107 : }
1108 : }
1109 84511 : if (new_map->NumberOfOwnDescriptors() != old_nof) return Map();
1110 84511 : return new_map;
1111 : }
1112 :
1113 : // static
1114 23690752 : Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
1115 23690757 : if (!map->is_deprecated()) return map;
1116 : if (FLAG_fast_map_update) {
1117 : Map target_map = SearchMigrationTarget(isolate, *map);
1118 : if (!target_map.is_null()) {
1119 : return handle(target_map, isolate);
1120 : }
1121 : }
1122 3168 : MapUpdater mu(isolate, map);
1123 3168 : return mu.Update();
1124 : }
1125 :
1126 2283840 : void Map::EnsureDescriptorSlack(Isolate* isolate, Handle<Map> map, int slack) {
1127 : // Only supports adding slack to owned descriptors.
1128 : DCHECK(map->owns_descriptors());
1129 :
1130 4567682 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
1131 : int old_size = map->NumberOfOwnDescriptors();
1132 2288064 : if (slack <= descriptors->number_of_slack_descriptors()) return;
1133 :
1134 : Handle<DescriptorArray> new_descriptors =
1135 2283841 : DescriptorArray::CopyUpTo(isolate, descriptors, old_size, slack);
1136 :
1137 : DisallowHeapAllocation no_allocation;
1138 : // The descriptors are still the same, so keep the layout descriptor.
1139 4567682 : LayoutDescriptor layout_descriptor = map->GetLayoutDescriptor();
1140 :
1141 2283841 : if (old_size == 0) {
1142 : map->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
1143 4223 : map->NumberOfOwnDescriptors());
1144 4223 : return;
1145 : }
1146 :
1147 : // If the source descriptors had an enum cache we copy it. This ensures
1148 : // that the maps to which we push the new descriptor array back can rely
1149 : // on a cache always being available once it is set. If the map has more
1150 : // enumerated descriptors than available in the original cache, the cache
1151 : // will be lazily replaced by the extended cache when needed.
1152 2279618 : new_descriptors->CopyEnumCacheFrom(*descriptors);
1153 :
1154 : // Replace descriptors by new_descriptors in all maps that share it. The old
1155 : // descriptors will not be trimmed in the mark-compactor, we need to mark
1156 : // all its elements.
1157 : MarkingBarrierForDescriptorArray(isolate->heap(), *map, *descriptors,
1158 6838854 : descriptors->number_of_descriptors());
1159 :
1160 2279618 : Map current = *map;
1161 59188446 : while (current->instance_descriptors() == *descriptors) {
1162 26175481 : Object next = current->GetBackPointer();
1163 26175481 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
1164 : current->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
1165 26174798 : current->NumberOfOwnDescriptors());
1166 26174796 : current = Map::cast(next);
1167 : }
1168 : map->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
1169 2279618 : map->NumberOfOwnDescriptors());
1170 : }
1171 :
1172 : // static
1173 120898 : Handle<Map> Map::GetObjectCreateMap(Isolate* isolate,
1174 : Handle<HeapObject> prototype) {
1175 362694 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
1176 241796 : isolate);
1177 120898 : if (map->prototype() == *prototype) return map;
1178 241742 : if (prototype->IsNull(isolate)) {
1179 365 : return isolate->slow_object_with_null_prototype_map();
1180 : }
1181 241012 : if (prototype->IsJSObject()) {
1182 119777 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
1183 119777 : if (!js_prototype->map()->is_prototype_map()) {
1184 117219 : JSObject::OptimizeAsPrototype(js_prototype);
1185 : }
1186 : Handle<PrototypeInfo> info =
1187 119777 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
1188 : // TODO(verwaest): Use inobject slack tracking for this map.
1189 119777 : if (info->HasObjectCreateMap()) {
1190 200 : map = handle(info->ObjectCreateMap(), isolate);
1191 : } else {
1192 119677 : map = Map::CopyInitialMap(isolate, map);
1193 119677 : Map::SetPrototype(isolate, map, prototype);
1194 119677 : PrototypeInfo::SetObjectCreateMap(info, map);
1195 : }
1196 119777 : return map;
1197 : }
1198 :
1199 729 : return Map::TransitionToPrototype(isolate, map, prototype);
1200 : }
1201 :
1202 : // static
1203 0 : MaybeHandle<Map> Map::TryGetObjectCreateMap(Isolate* isolate,
1204 : Handle<HeapObject> prototype) {
1205 0 : Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
1206 0 : isolate);
1207 0 : if (map->prototype() == *prototype) return map;
1208 0 : if (prototype->IsNull(isolate)) {
1209 0 : return isolate->slow_object_with_null_prototype_map();
1210 : }
1211 0 : if (!prototype->IsJSObject()) return MaybeHandle<Map>();
1212 0 : Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
1213 0 : if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
1214 : Handle<PrototypeInfo> info =
1215 0 : Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
1216 0 : if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
1217 0 : return handle(info->ObjectCreateMap(), isolate);
1218 : }
1219 :
1220 83892 : static bool ContainsMap(MapHandles const& maps, Map map) {
1221 : DCHECK(!map.is_null());
1222 245024 : for (Handle<Map> current : maps) {
1223 184388 : if (!current.is_null() && *current == map) return true;
1224 : }
1225 : return false;
1226 : }
1227 :
1228 52665 : Map Map::FindElementsKindTransitionedMap(Isolate* isolate,
1229 : MapHandles const& candidates) {
1230 : DisallowHeapAllocation no_allocation;
1231 : DisallowDeoptimization no_deoptimization(isolate);
1232 :
1233 52665 : if (is_prototype_map()) return Map();
1234 :
1235 : ElementsKind kind = elements_kind();
1236 : bool packed = IsFastPackedElementsKind(kind);
1237 :
1238 : Map transition;
1239 52092 : if (IsTransitionableFastElementsKind(kind)) {
1240 : // Check the state of the root map.
1241 27134 : Map root_map = FindRootMap(isolate);
1242 27134 : if (!EquivalentToForElementsKindTransition(root_map)) return Map();
1243 27134 : root_map = root_map->LookupElementsTransitionMap(isolate, kind);
1244 : DCHECK(!root_map.is_null());
1245 : // Starting from the next existing elements kind transition try to
1246 : // replay the property transitions that does not involve instance rewriting
1247 : // (ElementsTransitionAndStoreStub does not support that).
1248 234304 : for (root_map = root_map->ElementsTransitionMap();
1249 209166 : !root_map.is_null() && root_map->has_fast_elements();
1250 : root_map = root_map->ElementsTransitionMap()) {
1251 90018 : Map current = root_map->TryReplayPropertyTransitions(isolate, *this);
1252 90018 : if (current.is_null()) continue;
1253 83910 : if (InstancesNeedRewriting(current)) continue;
1254 :
1255 167784 : if (ContainsMap(candidates, current) &&
1256 1430 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
1257 : transition = current;
1258 28018 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
1259 : }
1260 : }
1261 : }
1262 52092 : return transition;
1263 : }
1264 :
1265 3290100 : static Map FindClosestElementsTransition(Isolate* isolate, Map map,
1266 : ElementsKind to_kind) {
1267 : // Ensure we are requested to search elements kind transition "near the root".
1268 : DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
1269 : map->NumberOfOwnDescriptors());
1270 3290100 : Map current_map = map;
1271 :
1272 : ElementsKind kind = map->elements_kind();
1273 10968356 : while (kind != to_kind) {
1274 7847039 : Map next_map = current_map->ElementsTransitionMap();
1275 7847047 : if (next_map.is_null()) return current_map;
1276 : kind = next_map->elements_kind();
1277 7678256 : current_map = next_map;
1278 : }
1279 :
1280 : DCHECK_EQ(to_kind, current_map->elements_kind());
1281 3121317 : return current_map;
1282 : }
1283 :
1284 27148 : Map Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) {
1285 27148 : Map to_map = FindClosestElementsTransition(isolate, *this, to_kind);
1286 27148 : if (to_map->elements_kind() == to_kind) return to_map;
1287 0 : return Map();
1288 : }
1289 :
1290 146239 : bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const {
1291 292478 : if (isolate->initial_array_prototype()->map() == *this) {
1292 : return true;
1293 : }
1294 :
1295 291236 : if (isolate->initial_object_prototype()->map() == *this) {
1296 : return true;
1297 : }
1298 :
1299 145408 : return false;
1300 : }
1301 :
1302 1206155 : Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map,
1303 : ElementsKind to_kind) {
1304 : ElementsKind from_kind = map->elements_kind();
1305 1206155 : if (from_kind == to_kind) return map;
1306 :
1307 467707 : Context native_context = isolate->context()->native_context();
1308 467708 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
1309 1479 : if (*map == native_context->fast_aliased_arguments_map()) {
1310 : DCHECK_EQ(SLOW_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
1311 676 : return handle(native_context->slow_aliased_arguments_map(), isolate);
1312 : }
1313 466969 : } else if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
1314 0 : if (*map == native_context->slow_aliased_arguments_map()) {
1315 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
1316 0 : return handle(native_context->fast_aliased_arguments_map(), isolate);
1317 : }
1318 466969 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
1319 : // Reuse map transitions for JSArrays.
1320 : DisallowHeapAllocation no_gc;
1321 354719 : if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
1322 : Object maybe_transitioned_map =
1323 171578 : native_context->get(Context::ArrayMapIndex(to_kind));
1324 171580 : if (maybe_transitioned_map->IsMap()) {
1325 171578 : return handle(Map::cast(maybe_transitioned_map), isolate);
1326 : }
1327 : }
1328 : }
1329 :
1330 : DCHECK(!map->IsUndefined(isolate));
1331 : // Check if we can go back in the elements kind transition chain.
1332 875578 : if (IsHoleyElementsKind(from_kind) &&
1333 0 : to_kind == GetPackedElementsKind(from_kind) &&
1334 590906 : map->GetBackPointer()->IsMap() &&
1335 295453 : Map::cast(map->GetBackPointer())->elements_kind() == to_kind) {
1336 0 : return handle(Map::cast(map->GetBackPointer()), isolate);
1337 : }
1338 :
1339 : bool allow_store_transition = IsTransitionElementsKind(from_kind);
1340 : // Only store fast element maps in ascending generality.
1341 295453 : if (IsFastElementsKind(to_kind)) {
1342 : allow_store_transition =
1343 17858 : allow_store_transition && IsTransitionableFastElementsKind(from_kind) &&
1344 5781 : IsMoreGeneralElementsKindTransition(from_kind, to_kind);
1345 : }
1346 :
1347 295453 : if (!allow_store_transition) {
1348 524 : return Map::CopyAsElementsKind(isolate, map, to_kind, OMIT_TRANSITION);
1349 : }
1350 :
1351 : return Map::ReconfigureElementsKind(isolate, map, to_kind);
1352 : }
1353 :
1354 168791 : static Handle<Map> AddMissingElementsTransitions(Isolate* isolate,
1355 : Handle<Map> map,
1356 : ElementsKind to_kind) {
1357 : DCHECK(IsTransitionElementsKind(map->elements_kind()));
1358 :
1359 : Handle<Map> current_map = map;
1360 :
1361 : ElementsKind kind = map->elements_kind();
1362 : TransitionFlag flag;
1363 168791 : if (map->is_prototype_map()) {
1364 : flag = OMIT_TRANSITION;
1365 : } else {
1366 : flag = INSERT_TRANSITION;
1367 167556 : if (IsFastElementsKind(kind)) {
1368 344282 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
1369 5928 : kind = GetNextTransitionElementsKind(kind);
1370 5928 : current_map = Map::CopyAsElementsKind(isolate, current_map, kind, flag);
1371 : }
1372 : }
1373 : }
1374 :
1375 : // In case we are exiting the fast elements kind system, just add the map in
1376 : // the end.
1377 168791 : if (kind != to_kind) {
1378 166277 : current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag);
1379 : }
1380 :
1381 : DCHECK(current_map->elements_kind() == to_kind);
1382 168791 : return current_map;
1383 : }
1384 :
1385 : // static
1386 3262950 : Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map,
1387 : ElementsKind kind) {
1388 : Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind),
1389 6525902 : isolate);
1390 :
1391 3262963 : if (closest_map->elements_kind() == kind) {
1392 3094172 : return closest_map;
1393 : }
1394 :
1395 168791 : return AddMissingElementsTransitions(isolate, closest_map, kind);
1396 : }
1397 :
1398 167863 : int Map::NumberOfEnumerableProperties() const {
1399 : int result = 0;
1400 167863 : DescriptorArray descs = instance_descriptors();
1401 : int limit = NumberOfOwnDescriptors();
1402 801578 : for (int i = 0; i < limit; i++) {
1403 2231721 : if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
1404 964291 : !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
1405 328775 : result++;
1406 : }
1407 : }
1408 167863 : return result;
1409 : }
1410 :
1411 62853165 : int Map::NextFreePropertyIndex() const {
1412 : int free_index = 0;
1413 : int number_of_own_descriptors = NumberOfOwnDescriptors();
1414 62853165 : DescriptorArray descs = instance_descriptors();
1415 718494277 : for (int i = 0; i < number_of_own_descriptors; i++) {
1416 655641037 : PropertyDetails details = descs->GetDetails(i);
1417 655641079 : if (details.location() == kField) {
1418 601840562 : int candidate = details.field_index() + details.field_width_in_words();
1419 601840562 : if (candidate > free_index) free_index = candidate;
1420 : }
1421 : }
1422 62853240 : return free_index;
1423 : }
1424 :
1425 81151 : bool Map::OnlyHasSimpleProperties() const {
1426 : // Wrapped string elements aren't explicitly stored in the elements backing
1427 : // store, but are loaded indirectly from the underlying string.
1428 78938 : return !IsStringWrapperElementsKind(elements_kind()) &&
1429 200891 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
1430 141021 : !is_dictionary_map();
1431 : }
1432 :
1433 59537 : bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) {
1434 59537 : if (IsDictionaryElementsKind(elements_kind())) {
1435 : return false;
1436 : }
1437 :
1438 245451 : for (PrototypeIterator iter(isolate, *this); !iter.IsAtEnd();
1439 129781 : iter.Advance()) {
1440 : // Be conservative, don't walk into proxies.
1441 272507 : if (iter.GetCurrent()->IsJSProxy()) return true;
1442 : // String wrappers have non-configurable, non-writable elements.
1443 268192 : if (iter.GetCurrent()->IsStringWrapper()) return true;
1444 134078 : JSObject current = iter.GetCurrent<JSObject>();
1445 :
1446 402234 : if (current->HasDictionaryElements() &&
1447 142690 : current->element_dictionary()->requires_slow_elements()) {
1448 : return true;
1449 : }
1450 :
1451 129781 : if (current->HasSlowArgumentsElements()) {
1452 0 : FixedArray parameter_map = FixedArray::cast(current->elements());
1453 : Object arguments = parameter_map->get(1);
1454 0 : if (NumberDictionary::cast(arguments)->requires_slow_elements()) {
1455 : return true;
1456 : }
1457 : }
1458 : }
1459 :
1460 53520 : return false;
1461 : }
1462 :
1463 23164126 : Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size,
1464 : int inobject_properties) {
1465 : Handle<Map> result = isolate->factory()->NewMap(
1466 : map->instance_type(), instance_size, TERMINAL_FAST_ELEMENTS_KIND,
1467 23164125 : inobject_properties);
1468 : Handle<Object> prototype(map->prototype(), isolate);
1469 23164131 : Map::SetPrototype(isolate, result, prototype);
1470 46328279 : result->set_constructor_or_backpointer(map->GetConstructor());
1471 : result->set_bit_field(map->bit_field());
1472 : result->set_bit_field2(map->bit_field2());
1473 : int new_bit_field3 = map->bit_field3();
1474 : new_bit_field3 = OwnsDescriptorsBit::update(new_bit_field3, true);
1475 : new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
1476 : new_bit_field3 =
1477 : EnumLengthBits::update(new_bit_field3, kInvalidEnumCacheSentinel);
1478 23164142 : new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
1479 23164140 : if (!map->is_dictionary_map()) {
1480 22187597 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
1481 : }
1482 46328277 : result->set_bit_field3(new_bit_field3);
1483 23164136 : return result;
1484 : }
1485 :
1486 674098 : Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
1487 : PropertyNormalizationMode mode, const char* reason) {
1488 : DCHECK(!fast_map->is_dictionary_map());
1489 :
1490 2021029 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
1491 673676 : isolate);
1492 : bool use_cache =
1493 1858399 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
1494 : Handle<NormalizedMapCache> cache;
1495 673677 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
1496 :
1497 : Handle<Map> new_map;
1498 1858177 : if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
1499 : #ifdef VERIFY_HEAP
1500 : if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate);
1501 : #endif
1502 : #ifdef ENABLE_SLOW_DCHECKS
1503 : if (FLAG_enable_slow_asserts) {
1504 : // The cached map should match newly created normalized map bit-by-bit,
1505 : // except for the code cache, which can contain some ICs which can be
1506 : // applied to the shared map, dependent code and weak cell cache.
1507 : Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode);
1508 :
1509 : if (new_map->is_prototype_map()) {
1510 : // For prototype maps, the PrototypeInfo is not copied.
1511 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
1512 : reinterpret_cast<void*>(new_map->address()),
1513 : kTransitionsOrPrototypeInfoOffset));
1514 : DCHECK_EQ(fresh->raw_transitions(),
1515 : MaybeObject::FromObject(Smi::kZero));
1516 : STATIC_ASSERT(kDescriptorsOffset ==
1517 : kTransitionsOrPrototypeInfoOffset + kTaggedSize);
1518 : DCHECK_EQ(
1519 : 0,
1520 : memcmp(
1521 : HeapObject::RawField(*fresh, kDescriptorsOffset).ToVoidPtr(),
1522 : HeapObject::RawField(*new_map, kDescriptorsOffset).ToVoidPtr(),
1523 : kDependentCodeOffset - kDescriptorsOffset));
1524 : } else {
1525 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address()),
1526 : reinterpret_cast<void*>(new_map->address()),
1527 : Map::kDependentCodeOffset));
1528 : }
1529 : STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
1530 : Map::kDependentCodeOffset + kTaggedSize);
1531 : int offset = Map::kPrototypeValidityCellOffset + kTaggedSize;
1532 : DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset),
1533 : reinterpret_cast<void*>(new_map->address() + offset),
1534 : Map::kSize - offset));
1535 : }
1536 : #endif
1537 : } else {
1538 241844 : new_map = Map::CopyNormalized(isolate, fast_map, mode);
1539 241844 : if (use_cache) {
1540 160417 : cache->Set(fast_map, new_map);
1541 160417 : isolate->counters()->maps_normalized()->Increment();
1542 : }
1543 241844 : if (FLAG_trace_maps) {
1544 844 : LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
1545 : }
1546 : }
1547 673677 : fast_map->NotifyLeafMapLayoutChange(isolate);
1548 673677 : return new_map;
1549 : }
1550 :
1551 241955 : Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map,
1552 : PropertyNormalizationMode mode) {
1553 : int new_instance_size = map->instance_size();
1554 241955 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
1555 67727 : new_instance_size -= map->GetInObjectProperties() * kTaggedSize;
1556 : }
1557 :
1558 : Handle<Map> result = RawCopy(
1559 : isolate, map, new_instance_size,
1560 416183 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : map->GetInObjectProperties());
1561 : // Clear the unused_property_fields explicitly as this field should not
1562 : // be accessed for normalized maps.
1563 241955 : result->SetInObjectUnusedPropertyFields(0);
1564 241955 : result->set_is_dictionary_map(true);
1565 241955 : result->set_is_migration_target(false);
1566 241955 : result->set_may_have_interesting_symbols(true);
1567 241955 : result->set_construction_counter(kNoSlackTracking);
1568 :
1569 : #ifdef VERIFY_HEAP
1570 : if (FLAG_verify_heap) result->DictionaryMapVerify(isolate);
1571 : #endif
1572 :
1573 241955 : return result;
1574 : }
1575 :
1576 : // Return an immutable prototype exotic object version of the input map.
1577 : // Never even try to cache it in the transition tree, as it is intended
1578 : // for the global object and its prototype chain, and excluding it saves
1579 : // memory on the map transition tree.
1580 :
1581 : // static
1582 6 : Handle<Map> Map::TransitionToImmutableProto(Isolate* isolate, Handle<Map> map) {
1583 6 : Handle<Map> new_map = Map::Copy(isolate, map, "ImmutablePrototype");
1584 6 : new_map->set_is_immutable_proto(true);
1585 6 : return new_map;
1586 : }
1587 :
1588 : namespace {
1589 : void EnsureInitialMap(Isolate* isolate, Handle<Map> map) {
1590 : #ifdef DEBUG
1591 : // Strict function maps have Function as a constructor but the
1592 : // Function's initial map is a sloppy function map. Same holds for
1593 : // GeneratorFunction / AsyncFunction and its initial map.
1594 : Object constructor = map->GetConstructor();
1595 : DCHECK(constructor->IsJSFunction());
1596 : DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
1597 : *map == *isolate->strict_function_map() ||
1598 : *map == *isolate->strict_function_with_name_map() ||
1599 : *map == *isolate->generator_function_map() ||
1600 : *map == *isolate->generator_function_with_name_map() ||
1601 : *map == *isolate->generator_function_with_home_object_map() ||
1602 : *map == *isolate->generator_function_with_name_and_home_object_map() ||
1603 : *map == *isolate->async_function_map() ||
1604 : *map == *isolate->async_function_with_name_map() ||
1605 : *map == *isolate->async_function_with_home_object_map() ||
1606 : *map == *isolate->async_function_with_name_and_home_object_map());
1607 : #endif
1608 : // Initial maps must always own their descriptors and it's descriptor array
1609 : // does not contain descriptors that do not belong to the map.
1610 : DCHECK(map->owns_descriptors());
1611 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
1612 : map->instance_descriptors()->number_of_descriptors());
1613 : }
1614 : } // namespace
1615 :
1616 : // static
1617 111 : Handle<Map> Map::CopyInitialMapNormalized(Isolate* isolate, Handle<Map> map,
1618 : PropertyNormalizationMode mode) {
1619 : EnsureInitialMap(isolate, map);
1620 111 : return CopyNormalized(isolate, map, mode);
1621 : }
1622 :
1623 : // static
1624 427271 : Handle<Map> Map::CopyInitialMap(Isolate* isolate, Handle<Map> map,
1625 : int instance_size, int inobject_properties,
1626 : int unused_property_fields) {
1627 : EnsureInitialMap(isolate, map);
1628 : Handle<Map> result =
1629 427271 : RawCopy(isolate, map, instance_size, inobject_properties);
1630 :
1631 : // Please note instance_type and instance_size are set when allocated.
1632 427271 : result->SetInObjectUnusedPropertyFields(unused_property_fields);
1633 :
1634 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
1635 427270 : if (number_of_own_descriptors > 0) {
1636 : // The copy will use the same descriptors array.
1637 : result->UpdateDescriptors(isolate, map->instance_descriptors(),
1638 : map->GetLayoutDescriptor(),
1639 12171 : number_of_own_descriptors);
1640 :
1641 : DCHECK_EQ(result->NumberOfFields(),
1642 : result->GetInObjectProperties() - result->UnusedPropertyFields());
1643 : }
1644 :
1645 427270 : return result;
1646 : }
1647 :
1648 22494903 : Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) {
1649 : Handle<Map> result =
1650 : RawCopy(isolate, map, map->instance_size(),
1651 67484490 : map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
1652 :
1653 : // Please note instance_type and instance_size are set when allocated.
1654 22494914 : if (map->IsJSObjectMap()) {
1655 22494692 : result->CopyUnusedPropertyFields(*map);
1656 : }
1657 22494914 : map->NotifyLeafMapLayoutChange(isolate);
1658 22494912 : return result;
1659 : }
1660 :
1661 6107042 : Handle<Map> Map::ShareDescriptor(Isolate* isolate, Handle<Map> map,
1662 : Handle<DescriptorArray> descriptors,
1663 : Descriptor* descriptor) {
1664 : // Sanity check. This path is only to be taken if the map owns its descriptor
1665 : // array, implying that its NumberOfOwnDescriptors equals the number of
1666 : // descriptors in the descriptor array.
1667 : DCHECK_EQ(map->NumberOfOwnDescriptors(),
1668 : map->instance_descriptors()->number_of_descriptors());
1669 :
1670 6107042 : Handle<Map> result = CopyDropDescriptors(isolate, map);
1671 : Handle<Name> name = descriptor->GetKey();
1672 :
1673 : // Properly mark the {result} if the {name} is an "interesting symbol".
1674 6107043 : if (name->IsInterestingSymbol()) {
1675 64 : result->set_may_have_interesting_symbols(true);
1676 : }
1677 :
1678 : // Ensure there's space for the new descriptor in the shared descriptor array.
1679 6107043 : if (descriptors->number_of_slack_descriptors() == 0) {
1680 2279641 : int old_size = descriptors->number_of_descriptors();
1681 2279641 : if (old_size == 0) {
1682 467 : descriptors = DescriptorArray::Allocate(isolate, 0, 1);
1683 : } else {
1684 2279174 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
1685 2279174 : EnsureDescriptorSlack(isolate, map, slack);
1686 4558348 : descriptors = handle(map->instance_descriptors(), isolate);
1687 : }
1688 : }
1689 :
1690 : Handle<LayoutDescriptor> layout_descriptor =
1691 : FLAG_unbox_double_fields
1692 : ? LayoutDescriptor::ShareAppend(isolate, map,
1693 : descriptor->GetDetails())
1694 6107043 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
1695 :
1696 : {
1697 : DisallowHeapAllocation no_gc;
1698 6107043 : descriptors->Append(descriptor);
1699 6107043 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1700 : }
1701 :
1702 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
1703 6107043 : ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION);
1704 :
1705 6107043 : return result;
1706 : }
1707 :
1708 13874860 : void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
1709 : Handle<Map> child, Handle<Name> name,
1710 : SimpleTransitionFlag flag) {
1711 : DCHECK_IMPLIES(name->IsInterestingSymbol(),
1712 : child->may_have_interesting_symbols());
1713 : DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
1714 : child->may_have_interesting_symbols());
1715 : // Do not track transitions during bootstrap except for element transitions.
1716 20487811 : if (isolate->bootstrapper()->IsActive() &&
1717 : !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
1718 6614218 : if (FLAG_trace_maps) {
1719 3436 : LOG(isolate,
1720 : MapEvent("Transition", *parent, *child,
1721 : child->is_prototype_map() ? "prototype" : "", *name));
1722 : }
1723 13872369 : return;
1724 : }
1725 14516309 : if (!parent->GetBackPointer()->IsUndefined(isolate)) {
1726 6326638 : parent->set_owns_descriptors(false);
1727 : } else {
1728 : // |parent| is initial map and it must keep the ownership, there must be no
1729 : // descriptors in the descriptors array that do not belong to the map.
1730 : DCHECK(parent->owns_descriptors());
1731 : DCHECK_EQ(parent->NumberOfOwnDescriptors(),
1732 : parent->instance_descriptors()->number_of_descriptors());
1733 : }
1734 7258152 : if (parent->is_prototype_map()) {
1735 : DCHECK(child->is_prototype_map());
1736 0 : if (FLAG_trace_maps) {
1737 0 : LOG(isolate, MapEvent("Transition", *parent, *child, "prototype", *name));
1738 : }
1739 : } else {
1740 7258152 : TransitionsAccessor(isolate, parent).Insert(name, child, flag);
1741 7258151 : if (FLAG_trace_maps) {
1742 4887 : LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
1743 : }
1744 : }
1745 : }
1746 :
1747 15725132 : Handle<Map> Map::CopyReplaceDescriptors(
1748 1282 : Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
1749 : Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
1750 : MaybeHandle<Name> maybe_name, const char* reason,
1751 : SimpleTransitionFlag simple_flag) {
1752 : DCHECK(descriptors->IsSortedNoDuplicates());
1753 :
1754 15725132 : Handle<Map> result = CopyDropDescriptors(isolate, map);
1755 :
1756 : // Properly mark the {result} if the {name} is an "interesting symbol".
1757 : Handle<Name> name;
1758 26014304 : if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
1759 769109 : result->set_may_have_interesting_symbols(true);
1760 : }
1761 :
1762 15725142 : if (!map->is_prototype_map()) {
1763 38993536 : if (flag == INSERT_TRANSITION &&
1764 28264732 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
1765 7633443 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1766 :
1767 : DCHECK(!maybe_name.is_null());
1768 7633446 : ConnectTransition(isolate, map, result, name, simple_flag);
1769 : } else {
1770 5364401 : descriptors->GeneralizeAllFields();
1771 : result->InitializeDescriptors(isolate, *descriptors,
1772 5364401 : LayoutDescriptor::FastPointerLayout());
1773 : }
1774 : } else {
1775 2727299 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1776 : }
1777 31453731 : if (FLAG_trace_maps &&
1778 : // Mirror conditions above that did not call ConnectTransition().
1779 3122 : (map->is_prototype_map() ||
1780 : !(flag == INSERT_TRANSITION &&
1781 2185 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
1782 2909 : LOG(isolate, MapEvent("ReplaceDescriptors", *map, *result, reason,
1783 : maybe_name.is_null() ? Name() : *name));
1784 : }
1785 15725132 : return result;
1786 : }
1787 :
1788 : // Creates transition tree starting from |split_map| and adding all descriptors
1789 : // starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
1790 : // The way how it is done is tricky because of GC and special descriptors
1791 : // marking logic.
1792 12112 : Handle<Map> Map::AddMissingTransitions(
1793 : Isolate* isolate, Handle<Map> split_map,
1794 : Handle<DescriptorArray> descriptors,
1795 : Handle<LayoutDescriptor> full_layout_descriptor) {
1796 : DCHECK(descriptors->IsSortedNoDuplicates());
1797 : int split_nof = split_map->NumberOfOwnDescriptors();
1798 12112 : int nof_descriptors = descriptors->number_of_descriptors();
1799 : DCHECK_LT(split_nof, nof_descriptors);
1800 :
1801 : // Start with creating last map which will own full descriptors array.
1802 : // This is necessary to guarantee that GC will mark the whole descriptor
1803 : // array if any of the allocations happening below fail.
1804 : // Number of unused properties is temporarily incorrect and the layout
1805 : // descriptor could unnecessarily be in slow mode but we will fix after
1806 : // all the other intermediate maps are created.
1807 : // Also the last map might have interesting symbols, we temporarily set
1808 : // the flag and clear it right before the descriptors are installed. This
1809 : // makes heap verification happy and ensures the flag ends up accurate.
1810 12112 : Handle<Map> last_map = CopyDropDescriptors(isolate, split_map);
1811 : last_map->InitializeDescriptors(isolate, *descriptors,
1812 12112 : *full_layout_descriptor);
1813 12112 : last_map->SetInObjectUnusedPropertyFields(0);
1814 12112 : last_map->set_may_have_interesting_symbols(true);
1815 :
1816 : // During creation of intermediate maps we violate descriptors sharing
1817 : // invariant since the last map is not yet connected to the transition tree
1818 : // we create here. But it is safe because GC never trims map's descriptors
1819 : // if there are no dead transitions from that map and this is exactly the
1820 : // case for all the intermediate maps we create here.
1821 : Handle<Map> map = split_map;
1822 40725 : for (int i = split_nof; i < nof_descriptors - 1; ++i) {
1823 28613 : Handle<Map> new_map = CopyDropDescriptors(isolate, map);
1824 : InstallDescriptors(isolate, map, new_map, i, descriptors,
1825 28613 : full_layout_descriptor);
1826 :
1827 28613 : map = new_map;
1828 : }
1829 12112 : map->NotifyLeafMapLayoutChange(isolate);
1830 12112 : last_map->set_may_have_interesting_symbols(false);
1831 : InstallDescriptors(isolate, map, last_map, nof_descriptors - 1, descriptors,
1832 12112 : full_layout_descriptor);
1833 12112 : return last_map;
1834 : }
1835 :
1836 : // Since this method is used to rewrite an existing transition tree, it can
1837 : // always insert transitions without checking.
1838 40725 : void Map::InstallDescriptors(Isolate* isolate, Handle<Map> parent,
1839 : Handle<Map> child, int new_descriptor,
1840 : Handle<DescriptorArray> descriptors,
1841 : Handle<LayoutDescriptor> full_layout_descriptor) {
1842 : DCHECK(descriptors->IsSortedNoDuplicates());
1843 :
1844 81450 : child->SetInstanceDescriptors(isolate, *descriptors, new_descriptor + 1);
1845 40725 : child->CopyUnusedPropertyFields(*parent);
1846 40725 : PropertyDetails details = descriptors->GetDetails(new_descriptor);
1847 40725 : if (details.location() == kField) {
1848 40033 : child->AccountAddedPropertyField();
1849 : }
1850 :
1851 : if (FLAG_unbox_double_fields) {
1852 : Handle<LayoutDescriptor> layout_descriptor =
1853 : LayoutDescriptor::AppendIfFastOrUseFull(isolate, parent, details,
1854 40725 : full_layout_descriptor);
1855 40725 : child->set_layout_descriptor(*layout_descriptor);
1856 : #ifdef VERIFY_HEAP
1857 : // TODO(ishell): remove these checks from VERIFY_HEAP mode.
1858 : if (FLAG_verify_heap) {
1859 : CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
1860 : }
1861 : #else
1862 : SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
1863 : #endif
1864 81450 : child->set_visitor_id(Map::GetVisitorId(*child));
1865 : }
1866 :
1867 81450 : Handle<Name> name = handle(descriptors->GetKey(new_descriptor), isolate);
1868 81396 : if (parent->may_have_interesting_symbols() || name->IsInterestingSymbol()) {
1869 291 : child->set_may_have_interesting_symbols(true);
1870 : }
1871 40725 : ConnectTransition(isolate, parent, child, name, SIMPLE_PROPERTY_TRANSITION);
1872 40725 : }
1873 :
1874 173839 : Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
1875 : ElementsKind kind, TransitionFlag flag) {
1876 : // Only certain objects are allowed to have non-terminal fast transitional
1877 : // elements kinds.
1878 : DCHECK(map->IsJSObjectMap());
1879 : DCHECK_IMPLIES(
1880 : !map->CanHaveFastTransitionableElementsKind(),
1881 : IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
1882 :
1883 : Map maybe_elements_transition_map;
1884 173839 : if (flag == INSERT_TRANSITION) {
1885 : // Ensure we are requested to add elements kind transition "near the root".
1886 : DCHECK_EQ(map->FindRootMap(isolate)->NumberOfOwnDescriptors(),
1887 : map->NumberOfOwnDescriptors());
1888 :
1889 172080 : maybe_elements_transition_map = map->ElementsTransitionMap();
1890 : DCHECK(maybe_elements_transition_map.is_null() ||
1891 : (maybe_elements_transition_map->elements_kind() ==
1892 : DICTIONARY_ELEMENTS &&
1893 : kind == DICTIONARY_ELEMENTS));
1894 : DCHECK(!IsFastElementsKind(kind) ||
1895 : IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
1896 : DCHECK(kind != map->elements_kind());
1897 : }
1898 :
1899 : bool insert_transition =
1900 172080 : flag == INSERT_TRANSITION &&
1901 436963 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
1902 1759 : maybe_elements_transition_map.is_null();
1903 :
1904 173839 : if (insert_transition) {
1905 91044 : Handle<Map> new_map = CopyForElementsTransition(isolate, map);
1906 182088 : new_map->set_elements_kind(kind);
1907 :
1908 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
1909 91044 : ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION);
1910 91044 : return new_map;
1911 : }
1912 :
1913 : // Create a new free-floating map only if we are not allowed to store it.
1914 82795 : Handle<Map> new_map = Copy(isolate, map, "CopyAsElementsKind");
1915 165590 : new_map->set_elements_kind(kind);
1916 82795 : return new_map;
1917 : }
1918 :
1919 671 : Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
1920 : Handle<SharedFunctionInfo> shared_info) {
1921 : DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
1922 : // Initial map for sloppy mode function is stored in the function
1923 : // constructor. Initial maps for strict mode are cached as special transitions
1924 : // using |strict_function_transition_symbol| as a key.
1925 671 : if (is_sloppy(shared_info->language_mode())) return initial_map;
1926 :
1927 459 : Handle<Map> function_map(Map::cast(isolate->native_context()->get(
1928 : shared_info->function_map_index())),
1929 306 : isolate);
1930 :
1931 : STATIC_ASSERT(LanguageModeSize == 2);
1932 : DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
1933 : Handle<Symbol> transition_symbol =
1934 : isolate->factory()->strict_function_transition_symbol();
1935 : Map maybe_transition = TransitionsAccessor(isolate, initial_map)
1936 153 : .SearchSpecial(*transition_symbol);
1937 153 : if (!maybe_transition.is_null()) {
1938 : return handle(maybe_transition, isolate);
1939 : }
1940 117 : initial_map->NotifyLeafMapLayoutChange(isolate);
1941 :
1942 : // Create new map taking descriptors from the |function_map| and all
1943 : // the other details from the |initial_map|.
1944 : Handle<Map> map =
1945 : Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(),
1946 : initial_map->GetInObjectProperties(),
1947 351 : initial_map->UnusedPropertyFields());
1948 234 : map->SetConstructor(initial_map->GetConstructor());
1949 117 : map->set_prototype(initial_map->prototype());
1950 117 : map->set_construction_counter(initial_map->construction_counter());
1951 :
1952 117 : if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) {
1953 : Map::ConnectTransition(isolate, initial_map, map, transition_symbol,
1954 117 : SPECIAL_TRANSITION);
1955 : }
1956 117 : return map;
1957 : }
1958 :
1959 91044 : Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, Handle<Map> map) {
1960 : DCHECK(!map->is_prototype_map());
1961 91044 : Handle<Map> new_map = CopyDropDescriptors(isolate, map);
1962 :
1963 91044 : if (map->owns_descriptors()) {
1964 : // In case the map owned its own descriptors, share the descriptors and
1965 : // transfer ownership to the new map.
1966 : // The properties did not change, so reuse descriptors.
1967 : new_map->InitializeDescriptors(isolate, map->instance_descriptors(),
1968 272958 : map->GetLayoutDescriptor());
1969 : } else {
1970 : // In case the map did not own its own descriptors, a split is forced by
1971 : // copying the map; creating a new descriptor array cell.
1972 116 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
1973 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
1974 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
1975 58 : isolate, descriptors, number_of_own_descriptors);
1976 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
1977 116 : isolate);
1978 : new_map->InitializeDescriptors(isolate, *new_descriptors,
1979 58 : *new_layout_descriptor);
1980 : }
1981 91044 : return new_map;
1982 : }
1983 :
1984 5418727 : Handle<Map> Map::Copy(Isolate* isolate, Handle<Map> map, const char* reason) {
1985 10837461 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
1986 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
1987 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
1988 5418732 : isolate, descriptors, number_of_own_descriptors);
1989 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
1990 10837461 : isolate);
1991 : return CopyReplaceDescriptors(
1992 : isolate, map, new_descriptors, new_layout_descriptor, OMIT_TRANSITION,
1993 5418730 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
1994 : }
1995 :
1996 146260 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
1997 : Handle<Map> copy =
1998 292520 : Copy(isolate, handle(isolate->object_function()->initial_map(), isolate),
1999 292519 : "MapCreate");
2000 :
2001 : // Check that we do not overflow the instance size when adding the extra
2002 : // inobject properties. If the instance size overflows, we allocate as many
2003 : // properties as we can as inobject properties.
2004 146260 : if (inobject_properties > JSObject::kMaxInObjectProperties) {
2005 : inobject_properties = JSObject::kMaxInObjectProperties;
2006 : }
2007 :
2008 : int new_instance_size =
2009 146260 : JSObject::kHeaderSize + kTaggedSize * inobject_properties;
2010 :
2011 : // Adjust the map with the extra inobject properties.
2012 146260 : copy->set_instance_size(new_instance_size);
2013 146260 : copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kTaggedSize);
2014 : DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
2015 146260 : copy->SetInObjectUnusedPropertyFields(inobject_properties);
2016 292520 : copy->set_visitor_id(Map::GetVisitorId(*copy));
2017 146260 : return copy;
2018 : }
2019 :
2020 135432 : Handle<Map> Map::CopyForPreventExtensions(Isolate* isolate, Handle<Map> map,
2021 : PropertyAttributes attrs_to_add,
2022 : Handle<Symbol> transition_marker,
2023 : const char* reason) {
2024 : int num_descriptors = map->NumberOfOwnDescriptors();
2025 : Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
2026 : isolate, handle(map->instance_descriptors(), isolate), num_descriptors,
2027 270865 : attrs_to_add);
2028 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
2029 270867 : isolate);
2030 : Handle<Map> new_map = CopyReplaceDescriptors(
2031 : isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
2032 135433 : transition_marker, reason, SPECIAL_TRANSITION);
2033 : new_map->set_is_extensible(false);
2034 135434 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
2035 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
2036 : ? SLOW_STRING_WRAPPER_ELEMENTS
2037 135385 : : DICTIONARY_ELEMENTS;
2038 270770 : new_map->set_elements_kind(new_kind);
2039 : }
2040 135434 : return new_map;
2041 : }
2042 :
2043 : namespace {
2044 :
2045 7194251 : bool CanHoldValue(DescriptorArray descriptors, int descriptor,
2046 : PropertyConstness constness, Object value) {
2047 7194251 : PropertyDetails details = descriptors->GetDetails(descriptor);
2048 7194253 : if (details.location() == kField) {
2049 7194253 : if (details.kind() == kData) {
2050 7136249 : return IsGeneralizableTo(constness, details.constness()) &&
2051 21252735 : value->FitsRepresentation(details.representation()) &&
2052 14116488 : descriptors->GetFieldType(descriptor)->NowContains(value);
2053 : } else {
2054 : DCHECK_EQ(kAccessor, details.kind());
2055 : return false;
2056 : }
2057 :
2058 : } else {
2059 : DCHECK_EQ(kDescriptor, details.location());
2060 : DCHECK_EQ(PropertyConstness::kConst, details.constness());
2061 0 : if (details.kind() == kData) {
2062 : DCHECK(!FLAG_track_constant_fields);
2063 : DCHECK(descriptors->GetStrongValue(descriptor) != value ||
2064 : value->FitsRepresentation(details.representation()));
2065 : return descriptors->GetStrongValue(descriptor) == value;
2066 : } else {
2067 : DCHECK_EQ(kAccessor, details.kind());
2068 : return false;
2069 : }
2070 : }
2071 : UNREACHABLE();
2072 : }
2073 :
2074 7194253 : Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map,
2075 : int descriptor,
2076 : PropertyConstness constness,
2077 : Handle<Object> value) {
2078 14388507 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
2079 14388508 : *value)) {
2080 6915247 : return map;
2081 : }
2082 :
2083 : PropertyAttributes attributes =
2084 558016 : map->instance_descriptors()->GetDetails(descriptor).attributes();
2085 279009 : Representation representation = value->OptimalRepresentation();
2086 279009 : Handle<FieldType> type = value->OptimalType(isolate, representation);
2087 :
2088 279006 : MapUpdater mu(isolate, map);
2089 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
2090 279006 : representation, type);
2091 : }
2092 :
2093 : } // namespace
2094 :
2095 : // static
2096 1879649 : Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map,
2097 : int descriptor,
2098 : PropertyConstness constness,
2099 : Handle<Object> value) {
2100 : // Dictionaries can store any property value.
2101 : DCHECK(!map->is_dictionary_map());
2102 : // Update to the newest map before storing the property.
2103 : return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor,
2104 1879649 : constness, value);
2105 : }
2106 :
2107 21218570 : Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
2108 : Handle<Name> name,
2109 : Handle<Object> value,
2110 : PropertyAttributes attributes,
2111 : PropertyConstness constness,
2112 : StoreOrigin store_origin) {
2113 : RuntimeCallTimerScope stats_scope(
2114 : isolate, *map,
2115 : map->is_prototype_map()
2116 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
2117 21218573 : : RuntimeCallCounterId::kMap_TransitionToDataProperty);
2118 :
2119 : DCHECK(name->IsUniqueName());
2120 : DCHECK(!map->is_dictionary_map());
2121 :
2122 : // Migrate to the newest map before storing the property.
2123 21218574 : map = Update(isolate, map);
2124 :
2125 : Map maybe_transition = TransitionsAccessor(isolate, map)
2126 21218579 : .SearchTransition(*name, kData, attributes);
2127 21218583 : if (!maybe_transition.is_null()) {
2128 : Handle<Map> transition(maybe_transition, isolate);
2129 5314606 : int descriptor = transition->LastAdded();
2130 :
2131 : DCHECK_EQ(attributes, transition->instance_descriptors()
2132 : ->GetDetails(descriptor)
2133 : .attributes());
2134 :
2135 : return UpdateDescriptorForValue(isolate, transition, descriptor, constness,
2136 5314606 : value);
2137 : }
2138 :
2139 : TransitionFlag flag = INSERT_TRANSITION;
2140 : MaybeHandle<Map> maybe_map;
2141 15903975 : if (!map->TooManyFastProperties(store_origin)) {
2142 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
2143 : maybe_map =
2144 : Map::CopyWithConstant(isolate, map, name, value, attributes, flag);
2145 : } else {
2146 15883791 : Representation representation = value->OptimalRepresentation();
2147 15883788 : Handle<FieldType> type = value->OptimalType(isolate, representation);
2148 : maybe_map = Map::CopyWithField(isolate, map, name, type, attributes,
2149 15883784 : constness, representation, flag);
2150 : }
2151 : }
2152 :
2153 : Handle<Map> result;
2154 15903973 : if (!maybe_map.ToHandle(&result)) {
2155 : const char* reason = "TooManyFastProperties";
2156 : #if V8_TRACE_MAPS
2157 : std::unique_ptr<ScopedVector<char>> buffer;
2158 : if (FLAG_trace_maps) {
2159 : ScopedVector<char> name_buffer(100);
2160 : name->NameShortPrint(name_buffer);
2161 : buffer.reset(new ScopedVector<char>(128));
2162 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
2163 : reason = buffer->start();
2164 : }
2165 : #endif
2166 40662 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
2167 20331 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
2168 40662 : maybe_constructor->IsJSFunction() &&
2169 20331 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
2170 : Handle<JSFunction> constructor =
2171 0 : Handle<JSFunction>::cast(maybe_constructor);
2172 : DCHECK_NE(*constructor,
2173 : constructor->context()->native_context()->object_function());
2174 0 : Handle<Map> initial_map(constructor->initial_map(), isolate);
2175 : result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES,
2176 0 : reason);
2177 0 : initial_map->DeprecateTransitionTree(isolate);
2178 : Handle<Object> prototype(result->prototype(), isolate);
2179 0 : JSFunction::SetInitialMap(constructor, result, prototype);
2180 :
2181 : // Deoptimize all code that embeds the previous initial map.
2182 0 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
2183 0 : isolate, DependentCode::kInitialMapChangedGroup);
2184 0 : if (!result->EquivalentToForNormalization(*map,
2185 0 : CLEAR_INOBJECT_PROPERTIES)) {
2186 : result =
2187 0 : Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
2188 : }
2189 : } else {
2190 20331 : result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
2191 : }
2192 : }
2193 :
2194 15903973 : return result;
2195 : }
2196 :
2197 17655 : Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
2198 : int descriptor, PropertyKind kind,
2199 : PropertyAttributes attributes) {
2200 : // Dictionaries have to be reconfigured in-place.
2201 : DCHECK(!map->is_dictionary_map());
2202 :
2203 35310 : if (!map->GetBackPointer()->IsMap()) {
2204 : // There is no benefit from reconstructing transition tree for maps without
2205 : // back pointers.
2206 : return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
2207 : descriptor, kind, attributes,
2208 1229 : "GenAll_AttributesMismatchProtoMap");
2209 : }
2210 :
2211 16426 : if (FLAG_trace_generalization) {
2212 0 : map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes);
2213 : }
2214 :
2215 16426 : MapUpdater mu(isolate, map);
2216 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
2217 : Handle<Map> new_map = mu.ReconfigureToDataField(
2218 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
2219 16426 : FieldType::None(isolate));
2220 16426 : return new_map;
2221 : }
2222 :
2223 589123 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
2224 : Handle<Name> name, int descriptor,
2225 : Handle<Object> getter,
2226 : Handle<Object> setter,
2227 : PropertyAttributes attributes) {
2228 : RuntimeCallTimerScope stats_scope(
2229 : isolate,
2230 : map->is_prototype_map()
2231 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
2232 589123 : : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
2233 :
2234 : // At least one of the accessors needs to be a new value.
2235 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
2236 : DCHECK(name->IsUniqueName());
2237 :
2238 : // Dictionary maps can always have additional data properties.
2239 589123 : if (map->is_dictionary_map()) return map;
2240 :
2241 : // Migrate to the newest map before transitioning to the new property.
2242 589123 : map = Update(isolate, map);
2243 :
2244 : PropertyNormalizationMode mode = map->is_prototype_map()
2245 : ? KEEP_INOBJECT_PROPERTIES
2246 589123 : : CLEAR_INOBJECT_PROPERTIES;
2247 :
2248 : Map maybe_transition = TransitionsAccessor(isolate, map)
2249 589123 : .SearchTransition(*name, kAccessor, attributes);
2250 589123 : if (!maybe_transition.is_null()) {
2251 : Handle<Map> transition(maybe_transition, isolate);
2252 12065 : DescriptorArray descriptors = transition->instance_descriptors();
2253 12065 : int descriptor = transition->LastAdded();
2254 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
2255 :
2256 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
2257 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
2258 :
2259 : Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate);
2260 24130 : if (!maybe_pair->IsAccessorPair()) {
2261 : return Map::Normalize(isolate, map, mode,
2262 0 : "TransitionToAccessorFromNonPair");
2263 : }
2264 :
2265 12065 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
2266 12065 : if (!pair->Equals(*getter, *setter)) {
2267 : return Map::Normalize(isolate, map, mode,
2268 11532 : "TransitionToDifferentAccessor");
2269 : }
2270 :
2271 533 : return transition;
2272 : }
2273 :
2274 : Handle<AccessorPair> pair;
2275 577058 : DescriptorArray old_descriptors = map->instance_descriptors();
2276 577058 : if (descriptor != DescriptorArray::kNotFound) {
2277 219453 : if (descriptor != map->LastAdded()) {
2278 117361 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast");
2279 : }
2280 102092 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
2281 102092 : if (old_details.kind() != kAccessor) {
2282 : return Map::Normalize(isolate, map, mode,
2283 100412 : "AccessorsOverwritingNonAccessors");
2284 : }
2285 :
2286 1680 : if (old_details.attributes() != attributes) {
2287 81 : return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes");
2288 : }
2289 :
2290 : Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor),
2291 : isolate);
2292 3198 : if (!maybe_pair->IsAccessorPair()) {
2293 24 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair");
2294 : }
2295 :
2296 1575 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
2297 1575 : if (current_pair->Equals(*getter, *setter)) return map;
2298 :
2299 : bool overwriting_accessor = false;
2300 4711 : if (!getter->IsNull(isolate) &&
2301 4607 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
2302 : current_pair->get(ACCESSOR_GETTER) != *getter) {
2303 : overwriting_accessor = true;
2304 : }
2305 4716 : if (!setter->IsNull(isolate) &&
2306 4317 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
2307 : current_pair->get(ACCESSOR_SETTER) != *setter) {
2308 : overwriting_accessor = true;
2309 : }
2310 1575 : if (overwriting_accessor) {
2311 : return Map::Normalize(isolate, map, mode,
2312 1392 : "AccessorsOverwritingAccessors");
2313 : }
2314 :
2315 183 : pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair));
2316 1072815 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
2317 715210 : map->TooManyFastProperties(StoreOrigin::kNamed)) {
2318 : return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
2319 0 : "TooManyAccessors");
2320 : } else {
2321 357605 : pair = isolate->factory()->NewAccessorPair();
2322 : }
2323 :
2324 357788 : pair->SetComponents(*getter, *setter);
2325 :
2326 : TransitionFlag flag = INSERT_TRANSITION;
2327 357788 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
2328 357788 : return Map::CopyInsertDescriptor(isolate, map, &d, flag);
2329 : }
2330 :
2331 16260583 : Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
2332 : Descriptor* descriptor,
2333 : TransitionFlag flag) {
2334 32521166 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2335 :
2336 : // Share descriptors only if map owns descriptors and it not an initial map.
2337 48733318 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
2338 54840563 : !map->GetBackPointer()->IsUndefined(isolate) &&
2339 22367626 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
2340 6107043 : return ShareDescriptor(isolate, map, descriptors, descriptor);
2341 : }
2342 :
2343 : int nof = map->NumberOfOwnDescriptors();
2344 : Handle<DescriptorArray> new_descriptors =
2345 10153542 : DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
2346 10153550 : new_descriptors->Append(descriptor);
2347 :
2348 : Handle<LayoutDescriptor> new_layout_descriptor =
2349 : FLAG_unbox_double_fields
2350 10153547 : ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
2351 10153547 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
2352 :
2353 : return CopyReplaceDescriptors(
2354 : isolate, map, new_descriptors, new_layout_descriptor, flag,
2355 10153550 : descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
2356 : }
2357 :
2358 357828 : Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
2359 : Descriptor* descriptor,
2360 : TransitionFlag flag) {
2361 715656 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
2362 :
2363 : // We replace the key if it is already present.
2364 : int index =
2365 715656 : old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map);
2366 357828 : if (index != DescriptorArray::kNotFound) {
2367 : return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor,
2368 183 : index, flag);
2369 : }
2370 357645 : return CopyAddDescriptor(isolate, map, descriptor, flag);
2371 : }
2372 :
2373 183 : Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
2374 : Handle<DescriptorArray> descriptors,
2375 : Descriptor* descriptor,
2376 : int insertion_index,
2377 : TransitionFlag flag) {
2378 : Handle<Name> key = descriptor->GetKey();
2379 : DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
2380 : // This function does not support replacing property fields as
2381 : // that would break property field counters.
2382 : DCHECK_NE(kField, descriptor->GetDetails().location());
2383 : DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
2384 :
2385 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
2386 183 : isolate, descriptors, map->NumberOfOwnDescriptors());
2387 :
2388 183 : new_descriptors->Replace(insertion_index, descriptor);
2389 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
2390 183 : isolate, map, new_descriptors, new_descriptors->number_of_descriptors());
2391 :
2392 : SimpleTransitionFlag simple_flag =
2393 183 : (insertion_index == descriptors->number_of_descriptors() - 1)
2394 : ? SIMPLE_PROPERTY_TRANSITION
2395 183 : : PROPERTY_TRANSITION;
2396 : return CopyReplaceDescriptors(isolate, map, new_descriptors,
2397 : new_layout_descriptor, flag, key,
2398 183 : "CopyReplaceDescriptor", simple_flag);
2399 : }
2400 :
2401 752667 : int Map::Hash() {
2402 : // For performance reasons we only hash the 3 most variable fields of a map:
2403 : // constructor, prototype and bit_field2. For predictability reasons we
2404 : // use objects' offsets in respective pages for hashing instead of raw
2405 : // addresses.
2406 :
2407 : // Shift away the tag.
2408 1505334 : int hash = ObjectAddressForHashing(GetConstructor().ptr()) >> 2;
2409 :
2410 : // XOR-ing the prototype and constructor directly yields too many zero bits
2411 : // when the two pointers are close (which is fairly common).
2412 : // To avoid this we shift the prototype bits relatively to the constructor.
2413 752667 : hash ^= ObjectAddressForHashing(prototype().ptr()) << (32 - kPageSizeBits);
2414 :
2415 1505334 : return hash ^ (hash >> 16) ^ bit_field2();
2416 : }
2417 :
2418 : namespace {
2419 :
2420 521896 : bool CheckEquivalent(const Map first, const Map second) {
2421 1531423 : return first->GetConstructor() == second->GetConstructor() &&
2422 478733 : first->prototype() == second->prototype() &&
2423 478733 : first->instance_type() == second->instance_type() &&
2424 478733 : first->bit_field() == second->bit_field() &&
2425 478733 : first->is_extensible() == second->is_extensible() &&
2426 1479353 : first->new_target_is_base() == second->new_target_is_base() &&
2427 1000620 : first->has_hidden_prototype() == second->has_hidden_prototype();
2428 : }
2429 :
2430 : } // namespace
2431 :
2432 447987 : bool Map::EquivalentToForTransition(const Map other) const {
2433 895976 : CHECK_EQ(GetConstructor(), other->GetConstructor());
2434 447989 : CHECK_EQ(instance_type(), other->instance_type());
2435 447989 : CHECK_EQ(has_hidden_prototype(), other->has_hidden_prototype());
2436 :
2437 447987 : if (bit_field() != other->bit_field()) return false;
2438 447978 : if (new_target_is_base() != other->new_target_is_base()) return false;
2439 447971 : if (prototype() != other->prototype()) return false;
2440 447971 : if (instance_type() == JS_FUNCTION_TYPE) {
2441 : // JSFunctions require more checks to ensure that sloppy function is
2442 : // not equivalent to strict function.
2443 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
2444 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
2445 4858 : nof);
2446 : }
2447 : return true;
2448 : }
2449 :
2450 0 : bool Map::EquivalentToForElementsKindTransition(const Map other) const {
2451 27134 : if (!EquivalentToForTransition(other)) return false;
2452 : #ifdef DEBUG
2453 : // Ensure that we don't try to generate elements kind transitions from maps
2454 : // with fields that may be generalized in-place. This must already be handled
2455 : // during addition of a new field.
2456 : DescriptorArray descriptors = instance_descriptors();
2457 : int nof = NumberOfOwnDescriptors();
2458 : for (int i = 0; i < nof; i++) {
2459 : PropertyDetails details = descriptors->GetDetails(i);
2460 : if (details.location() == kField) {
2461 : DCHECK(IsMostGeneralFieldType(details.representation(),
2462 : descriptors->GetFieldType(i)));
2463 : }
2464 : }
2465 : #endif
2466 0 : return true;
2467 : }
2468 :
2469 521896 : bool Map::EquivalentToForNormalization(const Map other,
2470 : PropertyNormalizationMode mode) const {
2471 : int properties =
2472 521896 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
2473 1479344 : return CheckEquivalent(*this, other) && bit_field2() == other->bit_field2() &&
2474 1432453 : GetInObjectProperties() == properties &&
2475 431833 : JSObject::GetEmbedderFieldCount(*this) ==
2476 953729 : JSObject::GetEmbedderFieldCount(other);
2477 : }
2478 :
2479 373237 : static void GetMinInobjectSlack(Map map, void* data) {
2480 373237 : int slack = map->UnusedPropertyFields();
2481 373237 : if (*reinterpret_cast<int*>(data) > slack) {
2482 36173 : *reinterpret_cast<int*>(data) = slack;
2483 : }
2484 373237 : }
2485 :
2486 134209 : int Map::ComputeMinObjectSlack(Isolate* isolate) {
2487 : DisallowHeapAllocation no_gc;
2488 : // Has to be an initial map.
2489 : DCHECK(GetBackPointer()->IsUndefined(isolate));
2490 :
2491 134209 : int slack = UnusedPropertyFields();
2492 : TransitionsAccessor transitions(isolate, *this, &no_gc);
2493 : transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
2494 134210 : return slack;
2495 : }
2496 :
2497 261869 : static void ShrinkInstanceSize(Map map, void* data) {
2498 261869 : int slack = *reinterpret_cast<int*>(data);
2499 : DCHECK_GE(slack, 0);
2500 : #ifdef DEBUG
2501 : int old_visitor_id = Map::GetVisitorId(map);
2502 : int new_unused = map->UnusedPropertyFields() - slack;
2503 : #endif
2504 261869 : map->set_instance_size(map->InstanceSizeFromSlack(slack));
2505 261868 : map->set_construction_counter(Map::kNoSlackTracking);
2506 : DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
2507 : DCHECK_EQ(new_unused, map->UnusedPropertyFields());
2508 261868 : }
2509 :
2510 97977 : static void StopSlackTracking(Map map, void* data) {
2511 97977 : map->set_construction_counter(Map::kNoSlackTracking);
2512 97977 : }
2513 :
2514 128117 : void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
2515 : DisallowHeapAllocation no_gc;
2516 : // Has to be an initial map.
2517 : DCHECK(GetBackPointer()->IsUndefined(isolate));
2518 :
2519 128117 : int slack = ComputeMinObjectSlack(isolate);
2520 : TransitionsAccessor transitions(isolate, *this, &no_gc);
2521 128118 : if (slack != 0) {
2522 : // Resize the initial map and all maps in its transition tree.
2523 : transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
2524 : } else {
2525 : transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
2526 : }
2527 128117 : }
2528 :
2529 79226051 : void Map::SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors,
2530 : int number_of_own_descriptors) {
2531 79226051 : set_synchronized_instance_descriptors(descriptors);
2532 79226064 : SetNumberOfOwnDescriptors(number_of_own_descriptors);
2533 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
2534 79226058 : number_of_own_descriptors);
2535 79226064 : }
2536 :
2537 : // static
2538 617537 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
2539 : Isolate* isolate) {
2540 617538 : Object maybe_proto_info = prototype->map()->prototype_info();
2541 617540 : if (maybe_proto_info->IsPrototypeInfo()) {
2542 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
2543 : }
2544 136971 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
2545 273942 : prototype->map()->set_prototype_info(*proto_info);
2546 136971 : return proto_info;
2547 : }
2548 :
2549 : // static
2550 2678581 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
2551 : Isolate* isolate) {
2552 2678585 : Object maybe_proto_info = prototype_map->prototype_info();
2553 2678589 : if (maybe_proto_info->IsPrototypeInfo()) {
2554 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
2555 : }
2556 357685 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
2557 715373 : prototype_map->set_prototype_info(*proto_info);
2558 357687 : return proto_info;
2559 : }
2560 :
2561 : // static
2562 453725 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
2563 : Isolate* isolate) {
2564 453725 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
2565 : // "False" is the implicit default value, so there's nothing to do.
2566 453726 : return;
2567 : }
2568 907451 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
2569 : }
2570 :
2571 : // static
2572 1598270 : Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
2573 : Isolate* isolate) {
2574 : Handle<Object> maybe_prototype;
2575 1598271 : if (map->IsJSGlobalObjectMap()) {
2576 : DCHECK(map->is_prototype_map());
2577 : // Global object is prototype of a global proxy and therefore we can
2578 : // use its validity cell for guarding global object's prototype change.
2579 42924 : maybe_prototype = isolate->global_object();
2580 : } else {
2581 : maybe_prototype =
2582 3110697 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
2583 : }
2584 3196543 : if (!maybe_prototype->IsJSObject()) {
2585 66604 : return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
2586 : }
2587 1531667 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
2588 : // Ensure the prototype is registered with its own prototypes so its cell
2589 : // will be invalidated when necessary.
2590 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
2591 1531666 : isolate);
2592 :
2593 1531670 : Object maybe_cell = prototype->map()->prototype_validity_cell();
2594 : // Return existing cell if it's still valid.
2595 1531671 : if (maybe_cell->IsCell()) {
2596 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
2597 1531597 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
2598 1118597 : return cell;
2599 : }
2600 : }
2601 : // Otherwise create a new cell.
2602 : Handle<Cell> cell = isolate->factory()->NewCell(
2603 413071 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
2604 826144 : prototype->map()->set_prototype_validity_cell(*cell);
2605 413072 : return cell;
2606 : }
2607 :
2608 : // static
2609 0 : bool Map::IsPrototypeChainInvalidated(Map map) {
2610 : DCHECK(map->is_prototype_map());
2611 0 : Object maybe_cell = map->prototype_validity_cell();
2612 0 : if (maybe_cell->IsCell()) {
2613 : Cell cell = Cell::cast(maybe_cell);
2614 : return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
2615 : }
2616 : return true;
2617 : }
2618 :
2619 : // static
2620 29048780 : void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
2621 : Handle<Object> prototype,
2622 : bool enable_prototype_setup_mode) {
2623 : RuntimeCallTimerScope stats_scope(isolate, *map,
2624 : RuntimeCallCounterId::kMap_SetPrototype);
2625 :
2626 : bool is_hidden = false;
2627 58097614 : if (prototype->IsJSObject()) {
2628 23586407 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
2629 23586407 : JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
2630 :
2631 23586424 : Object maybe_constructor = prototype_jsobj->map()->GetConstructor();
2632 23586418 : if (maybe_constructor->IsJSFunction()) {
2633 22814476 : JSFunction constructor = JSFunction::cast(maybe_constructor);
2634 45628952 : Object data = constructor->shared()->function_data();
2635 233766 : is_hidden = (data->IsFunctionTemplateInfo() &&
2636 68910979 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
2637 68209675 : prototype->IsJSGlobalObject();
2638 771943 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
2639 : is_hidden =
2640 54 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
2641 36 : prototype->IsJSGlobalObject();
2642 : }
2643 : }
2644 58097643 : map->set_has_hidden_prototype(is_hidden);
2645 :
2646 : WriteBarrierMode wb_mode =
2647 58097608 : prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
2648 29048799 : map->set_prototype(*prototype, wb_mode);
2649 29048800 : }
2650 :
2651 309061 : void Map::StartInobjectSlackTracking() {
2652 : DCHECK(!IsInobjectSlackTrackingInProgress());
2653 618122 : if (UnusedPropertyFields() == 0) return;
2654 226564 : set_construction_counter(Map::kSlackTrackingCounterStart);
2655 : }
2656 :
2657 185475 : Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
2658 : Handle<Object> prototype) {
2659 : Handle<Map> new_map =
2660 185475 : TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
2661 185475 : if (new_map.is_null()) {
2662 169268 : new_map = Copy(isolate, map, "TransitionToPrototype");
2663 : TransitionsAccessor(isolate, map)
2664 169268 : .PutPrototypeTransition(prototype, new_map);
2665 169268 : Map::SetPrototype(isolate, new_map, prototype);
2666 : }
2667 185475 : return new_map;
2668 : }
2669 :
2670 111 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
2671 : Handle<WeakFixedArray> array(
2672 111 : isolate->factory()->NewWeakFixedArray(kEntries, TENURED));
2673 111 : return Handle<NormalizedMapCache>::cast(array);
2674 : }
2675 :
2676 592250 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
2677 : PropertyNormalizationMode mode) {
2678 : DisallowHeapAllocation no_gc;
2679 592250 : MaybeObject value = WeakFixedArray::Get(GetIndex(fast_map));
2680 592250 : HeapObject heap_object;
2681 592250 : if (!value->GetHeapObjectIfWeak(&heap_object)) {
2682 70354 : return MaybeHandle<Map>();
2683 : }
2684 :
2685 521896 : Map normalized_map = Map::cast(heap_object);
2686 521896 : if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
2687 90063 : return MaybeHandle<Map>();
2688 : }
2689 431833 : return handle(normalized_map, GetIsolate());
2690 : }
2691 :
2692 160417 : void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) {
2693 : DisallowHeapAllocation no_gc;
2694 : DCHECK(normalized_map->is_dictionary_map());
2695 : WeakFixedArray::Set(GetIndex(fast_map),
2696 160417 : HeapObjectReference::Weak(*normalized_map));
2697 160417 : }
2698 :
2699 : } // namespace internal
2700 178779 : } // namespace v8
|