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