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