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 3857059 : Map Map::GetPrototypeChainRootMap(Isolate* isolate) const {
31 : DisallowHeapAllocation no_alloc;
32 3857059 : if (IsJSReceiverMap()) {
33 3468628 : return *this;
34 : }
35 : int constructor_function_index = GetConstructorFunctionIndex();
36 388431 : 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 31394 : MaybeHandle<JSFunction> Map::GetConstructorFunction(
47 : Handle<Map> map, Handle<Context> native_context) {
48 31394 : if (map->IsPrimitiveMap()) {
49 : int const constructor_function_index = map->GetConstructorFunctionIndex();
50 8144 : if (constructor_function_index != kNoConstructorFunctionIndex) {
51 : return handle(
52 : JSFunction::cast(native_context->get(constructor_function_index)),
53 8144 : native_context->GetIsolate());
54 : }
55 : }
56 23250 : return MaybeHandle<JSFunction>();
57 : }
58 :
59 48310834 : bool Map::IsMapOfGlobalProxy(Handle<NativeContext> native_context) const {
60 : DisallowHeapAllocation no_gc;
61 48310834 : if (IsJSGlobalProxyMap()) {
62 464413 : Object maybe_constructor = GetConstructor();
63 : // Detached global proxies have |null| as their constructor.
64 928823 : 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 55722649 : VisitorId Map::GetVisitorId(Map map) {
89 : STATIC_ASSERT(kVisitorIdCount <= 256);
90 :
91 55722649 : const int instance_type = map->instance_type();
92 :
93 55722649 : if (instance_type < FIRST_NONSTRING_TYPE) {
94 1120 : switch (instance_type & kStringRepresentationMask) {
95 : case kSeqStringTag:
96 280 : 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 55721529 : 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 24047 : 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 13122 : return kVisitJSArrayBuffer;
222 :
223 : case JS_DATA_VIEW_TYPE:
224 874 : return kVisitJSDataView;
225 :
226 : case JS_FUNCTION_TYPE:
227 1758111 : return kVisitJSFunction;
228 :
229 : case JS_TYPED_ARRAY_TYPE:
230 31488 : 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 82879 : 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 46180504 : (FLAG_unbox_double_fields && !map->HasFastPointerLayout()) ||
305 : (COMPRESS_POINTERS_BOOL && JSObject::GetEmbedderFieldCount(map) > 0);
306 46180504 : return has_raw_data_fields ? kVisitJSObject : kVisitJSObjectFast;
307 : }
308 : case JS_API_OBJECT_TYPE:
309 : case JS_SPECIAL_API_OBJECT_TYPE:
310 7621795 : 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 1904 : if (instance_type == PROTOTYPE_INFO_TYPE) {
350 : return kVisitPrototypeInfo;
351 : }
352 1848 : 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 17306531 : MaybeObjectHandle Map::WrapFieldType(Isolate* isolate, Handle<FieldType> type) {
408 17306531 : if (type->IsClass()) {
409 11638410 : return MaybeObjectHandle::Weak(type->AsClass(), isolate);
410 : }
411 11487329 : return MaybeObjectHandle(type);
412 : }
413 :
414 : // static
415 37154466 : FieldType Map::UnwrapFieldType(MaybeObject wrapped_type) {
416 37154466 : if (wrapped_type->IsCleared()) {
417 120 : return FieldType::None();
418 : }
419 37154346 : HeapObject heap_object;
420 37154346 : if (wrapped_type->GetHeapObjectIfWeak(&heap_object)) {
421 1384773 : return FieldType::cast(heap_object);
422 : }
423 : return wrapped_type->cast<FieldType>();
424 : }
425 :
426 16987664 : 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 16987664 : if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
438 150 : return MaybeHandle<Map>();
439 : }
440 :
441 : // Compute the new index for new field.
442 16987514 : int index = map->NextFreePropertyIndex();
443 :
444 16987538 : if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
445 3628 : constness = PropertyConstness::kMutable;
446 3628 : representation = Representation::Tagged();
447 3628 : type = FieldType::Any(isolate);
448 : } else {
449 16983910 : Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
450 16983910 : isolate, map->instance_type(), &constness, &representation, &type);
451 : }
452 :
453 16987546 : 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 16987526 : representation, wrapped_type);
459 16987532 : Handle<Map> new_map = Map::CopyAddDescriptor(isolate, map, &d, flag);
460 16987523 : new_map->AccountAddedPropertyField();
461 16987530 : 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 99035 : bool Map::InstancesNeedRewriting(Map target) const {
517 99035 : int target_number_of_fields = target->NumberOfFields();
518 99036 : int target_inobject = target->GetInObjectProperties();
519 99036 : 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 99036 : &old_number_of_fields);
525 : }
526 :
527 16370117 : 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 16370117 : *old_number_of_fields = NumberOfFields();
532 : DCHECK(target_number_of_fields >= *old_number_of_fields);
533 16370142 : if (target_number_of_fields != *old_number_of_fields) return true;
534 :
535 : // If smi descriptors were replaced by double descriptors, rewrite.
536 6450436 : DescriptorArray old_desc = instance_descriptors();
537 6450436 : DescriptorArray new_desc = target->instance_descriptors();
538 : int limit = NumberOfOwnDescriptors();
539 35337396 : for (int i = 0; i < limit; i++) {
540 28891942 : if (new_desc->GetDetails(i).representation().IsDouble() !=
541 28891943 : 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 6447943 : 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 40474721 : int Map::NumberOfFields() const {
562 40474721 : DescriptorArray descriptors = instance_descriptors();
563 : int result = 0;
564 512569481 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
565 472094706 : if (descriptors->GetDetails(i).location() == kField) result++;
566 : }
567 40474775 : return result;
568 : }
569 :
570 2558140 : Map::FieldCounts Map::GetFieldCounts() const {
571 2558140 : DescriptorArray descriptors = instance_descriptors();
572 : int mutable_count = 0;
573 : int const_count = 0;
574 283436928 : for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
575 140439396 : PropertyDetails details = descriptors->GetDetails(i);
576 140439394 : if (details.location() == kField) {
577 139469415 : switch (details.constness()) {
578 : case PropertyConstness::kMutable:
579 24289 : mutable_count++;
580 24289 : break;
581 : case PropertyConstness::kConst:
582 139445125 : const_count++;
583 139445125 : break;
584 : }
585 : }
586 : }
587 2558138 : 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 975408 : Map Map::FindRootMap(Isolate* isolate) const {
694 975408 : Map result = *this;
695 744786 : while (true) {
696 1720194 : Object back = result->GetBackPointer();
697 1720198 : 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 975412 : return result;
704 : }
705 744786 : result = Map::cast(back);
706 : }
707 : }
708 :
709 642583 : Map Map::FindFieldOwner(Isolate* isolate, int descriptor) const {
710 : DisallowHeapAllocation no_allocation;
711 : DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
712 642583 : Map result = *this;
713 1085884 : while (true) {
714 1728467 : Object back = result->GetBackPointer();
715 1728465 : if (back->IsUndefined(isolate)) break;
716 : const Map parent = Map::cast(back);
717 1572532 : if (parent->NumberOfOwnDescriptors() <= descriptor) break;
718 1085884 : result = parent;
719 : }
720 642581 : return result;
721 : }
722 :
723 266360 : 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 266360 : PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
731 266360 : if (details.location() != kField) return;
732 : DCHECK_EQ(kData, details.kind());
733 :
734 532726 : Zone zone(isolate->allocator(), ZONE_NAME);
735 266362 : ZoneQueue<Map> backlog(&zone);
736 : backlog.push(*this);
737 :
738 3287307 : while (!backlog.empty()) {
739 1510469 : Map current = backlog.front();
740 : backlog.pop();
741 :
742 : TransitionsAccessor transitions(isolate, current, &no_allocation);
743 1510468 : int num_transitions = transitions.NumberOfTransitions();
744 3998668 : for (int i = 0; i < num_transitions; ++i) {
745 1244101 : Map target = transitions.GetTarget(i);
746 : backlog.push(target);
747 : }
748 1510466 : DescriptorArray descriptors = current->instance_descriptors();
749 1510466 : 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 2959216 : if (new_constness != details.constness() ||
758 2774099 : !new_representation.Equals(details.representation()) ||
759 1263632 : 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 267350 : new_constness, new_representation, new_wrapped_type);
765 267352 : descriptors->Replace(descriptor, &d);
766 : }
767 : }
768 : }
769 :
770 0 : bool FieldTypeIsCleared(Representation rep, FieldType type) {
771 1677871 : return type->IsNone() && rep.IsHeapObject();
772 : }
773 :
774 : // static
775 603822 : 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 1207607 : if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
784 5097 : return FieldType::Any(isolate);
785 : }
786 598723 : if (type1->NowIs(type2)) return type2;
787 51481 : if (type2->NowIs(type1)) return type1;
788 17206 : return FieldType::Any(isolate);
789 : }
790 :
791 : // static
792 710170 : 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 710173 : 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 1420347 : isolate);
803 :
804 : // Return if the current map is general enough to hold requested constness and
805 : // representation/field type.
806 1604911 : if (IsGeneralizableTo(new_constness, old_constness) &&
807 464304 : old_representation.Equals(new_representation) &&
808 1174468 : !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 1638764 : 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 443809 : return;
816 : }
817 :
818 : // Determine the field owner.
819 532724 : 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 266362 : new_representation, new_field_type, isolate);
827 :
828 : new_constness = GeneralizeConstness(old_constness, new_constness);
829 :
830 266361 : PropertyDetails details = descriptors->GetDetails(modify_index);
831 : Handle<Name> name(descriptors->GetKey(modify_index), isolate);
832 :
833 266361 : MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
834 532725 : field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
835 266361 : new_representation, wrapped_type);
836 532728 : field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
837 266364 : isolate, DependentCode::kFieldOwnerGroup);
838 :
839 266364 : 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 194367 : MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
911 : DisallowHeapAllocation no_allocation;
912 : DisallowDeoptimization no_deoptimization(isolate);
913 :
914 194367 : 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 231 : Map new_map = TryUpdateSlow(isolate, *old_map);
924 231 : 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 224 : 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 231 : 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 231 : Map root_map = old_map->FindRootMap(isolate);
993 231 : 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 231 : 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 231 : 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 231 : 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 231 : isolate, info.integrity_level_source_map);
1033 231 : if (result.is_null()) return Map();
1034 :
1035 224 : 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 224 : return result;
1046 : }
1047 :
1048 105368 : 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 105368 : DescriptorArray old_descriptors = old_map->instance_descriptors();
1056 :
1057 105368 : Map new_map = *this;
1058 111328 : for (int i = root_nof; i < old_nof; ++i) {
1059 9089 : 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 9089 : old_details.attributes());
1064 9089 : if (transition.is_null()) return Map();
1065 : new_map = transition;
1066 3013 : DescriptorArray new_descriptors = new_map->instance_descriptors();
1067 :
1068 3013 : 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 3013 : if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
1072 0 : return Map();
1073 : }
1074 : DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
1075 3013 : if (!old_details.representation().fits_into(new_details.representation())) {
1076 33 : return Map();
1077 : }
1078 2980 : if (new_details.location() == kField) {
1079 2980 : if (new_details.kind() == kData) {
1080 2980 : 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 2980 : if (FieldTypeIsCleared(new_details.representation(), new_type)) {
1084 0 : return Map();
1085 : }
1086 : DCHECK_EQ(kData, old_details.kind());
1087 2980 : if (old_details.location() == kField) {
1088 2980 : FieldType old_type = old_descriptors->GetFieldType(i);
1089 5960 : if (FieldTypeIsCleared(old_details.representation(), old_type) ||
1090 2980 : !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 99259 : if (new_map->NumberOfOwnDescriptors() != old_nof) return Map();
1120 99259 : return new_map;
1121 : }
1122 :
1123 : // static
1124 25785698 : Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
1125 25785698 : 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 1102 : MapUpdater mu(isolate, map);
1133 1102 : return mu.Update();
1134 : }
1135 :
1136 2323771 : 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 2327994 : if (slack <= descriptors->number_of_slack_descriptors()) return;
1143 :
1144 : Handle<DescriptorArray> new_descriptors =
1145 2323771 : 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 2323781 : LayoutDescriptor layout_descriptor = map->GetLayoutDescriptor();
1150 :
1151 2323781 : 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 4639113 : 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 2319555 : MarkingBarrierForDescriptorArray(isolate->heap(), *map, *descriptors,
1168 : descriptors->number_of_descriptors());
1169 :
1170 2319555 : Map current = *map;
1171 55409123 : while (current->instance_descriptors() == *descriptors) {
1172 26545468 : Object next = current->GetBackPointer();
1173 26545468 : if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
1174 : current->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
1175 26544785 : current->NumberOfOwnDescriptors());
1176 26544784 : current = Map::cast(next);
1177 : }
1178 4639115 : map->UpdateDescriptors(isolate, *new_descriptors, layout_descriptor,
1179 2319554 : 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 117195 : 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 180747 : for (Handle<Map> current : maps) {
1233 189032 : if (!current.is_null() && *current == map) return true;
1234 : }
1235 : return false;
1236 : }
1237 :
1238 62264 : Map Map::FindElementsKindTransitionedMap(Isolate* isolate,
1239 : MapHandles const& candidates) {
1240 : DisallowHeapAllocation no_allocation;
1241 : DisallowDeoptimization no_deoptimization(isolate);
1242 :
1243 62264 : if (is_prototype_map()) return Map();
1244 :
1245 : ElementsKind kind = elements_kind();
1246 : bool packed = IsFastPackedElementsKind(kind);
1247 :
1248 : Map transition;
1249 61691 : if (IsTransitionableFastElementsKind(kind)) {
1250 : // Check the state of the root map.
1251 32195 : Map root_map = FindRootMap(isolate);
1252 32196 : if (!EquivalentToForElementsKindTransition(root_map)) return Map();
1253 32196 : 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 274667 : for (root_map = root_map->ElementsTransitionMap();
1259 244622 : !root_map.is_null() && root_map->has_fast_elements();
1260 : root_map = root_map->ElementsTransitionMap()) {
1261 105138 : Map current = root_map->TryReplayPropertyTransitions(isolate, *this);
1262 105137 : if (current.is_null()) continue;
1263 99035 : if (InstancesNeedRewriting(current)) continue;
1264 :
1265 198036 : if (ContainsMap(candidates, current) &&
1266 1543 : (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
1267 : transition = current;
1268 23471 : packed = packed && IsFastPackedElementsKind(current->elements_kind());
1269 : }
1270 : }
1271 : }
1272 61692 : return transition;
1273 : }
1274 :
1275 3197368 : 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 3197368 : Map current_map = map;
1281 :
1282 : ElementsKind kind = map->elements_kind();
1283 18796524 : while (kind != to_kind) {
1284 7967180 : Map next_map = current_map->ElementsTransitionMap();
1285 7967183 : if (next_map.is_null()) return current_map;
1286 : kind = next_map->elements_kind();
1287 7799578 : current_map = next_map;
1288 : }
1289 :
1290 : DCHECK_EQ(to_kind, current_map->elements_kind());
1291 3029766 : return current_map;
1292 : }
1293 :
1294 32202 : Map Map::LookupElementsTransitionMap(Isolate* isolate, ElementsKind to_kind) {
1295 32202 : Map to_map = FindClosestElementsTransition(isolate, *this, to_kind);
1296 32202 : if (to_map->elements_kind() == to_kind) return to_map;
1297 0 : return Map();
1298 : }
1299 :
1300 150718 : bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const {
1301 301437 : if (isolate->initial_array_prototype()->map() == *this) {
1302 : return true;
1303 : }
1304 :
1305 300179 : if (isolate->initial_object_prototype()->map() == *this) {
1306 : return true;
1307 : }
1308 :
1309 149880 : return false;
1310 : }
1311 :
1312 1207384 : Handle<Map> Map::TransitionElementsTo(Isolate* isolate, Handle<Map> map,
1313 : ElementsKind to_kind) {
1314 : ElementsKind from_kind = map->elements_kind();
1315 1207384 : if (from_kind == to_kind) return map;
1316 :
1317 467461 : Context native_context = isolate->context()->native_context();
1318 467461 : if (from_kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
1319 1481 : 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 466722 : } 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 466722 : } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
1329 : // Reuse map transitions for JSArrays.
1330 : DisallowHeapAllocation no_gc;
1331 354135 : if (native_context->GetInitialJSArrayMap(from_kind) == *map) {
1332 : Object maybe_transitioned_map =
1333 : native_context->get(Context::ArrayMapIndex(to_kind));
1334 173849 : 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 167605 : 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 167605 : if (map->is_prototype_map()) {
1374 : flag = OMIT_TRANSITION;
1375 : } else {
1376 : flag = INSERT_TRANSITION;
1377 166362 : if (IsFastElementsKind(kind)) {
1378 340255 : while (kind != to_kind && !IsTerminalElementsKind(kind)) {
1379 2996 : kind = GetNextTransitionElementsKind(kind);
1380 2996 : 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 167605 : if (kind != to_kind) {
1388 166320 : current_map = Map::CopyAsElementsKind(isolate, current_map, to_kind, flag);
1389 : }
1390 :
1391 : DCHECK(current_map->elements_kind() == to_kind);
1392 167605 : return current_map;
1393 : }
1394 :
1395 : // static
1396 3165167 : Handle<Map> Map::AsElementsKind(Isolate* isolate, Handle<Map> map,
1397 : ElementsKind kind) {
1398 : Handle<Map> closest_map(FindClosestElementsTransition(isolate, *map, kind),
1399 6330334 : isolate);
1400 :
1401 3165170 : if (closest_map->elements_kind() == kind) {
1402 2997565 : return closest_map;
1403 : }
1404 :
1405 167605 : return AddMissingElementsTransitions(isolate, closest_map, kind);
1406 : }
1407 :
1408 168035 : int Map::NumberOfEnumerableProperties() const {
1409 : int result = 0;
1410 168035 : DescriptorArray descs = instance_descriptors();
1411 : int limit = NumberOfOwnDescriptors();
1412 1446003 : for (int i = 0; i < limit; i++) {
1413 2248013 : if ((descs->GetDetails(i).attributes() & ONLY_ENUMERABLE) == 0 &&
1414 970045 : !descs->GetKey(i)->FilterKey(ENUMERABLE_STRINGS)) {
1415 329260 : result++;
1416 : }
1417 : }
1418 168035 : return result;
1419 : }
1420 :
1421 65174229 : int Map::NextFreePropertyIndex() const {
1422 : int free_index = 0;
1423 : int number_of_own_descriptors = NumberOfOwnDescriptors();
1424 65174229 : DescriptorArray descs = instance_descriptors();
1425 1392184861 : for (int i = 0; i < number_of_own_descriptors; i++) {
1426 663505315 : PropertyDetails details = descs->GetDetails(i);
1427 663505316 : if (details.location() == kField) {
1428 608532460 : int candidate = details.field_index() + details.field_width_in_words();
1429 608532460 : if (candidate > free_index) free_index = candidate;
1430 : }
1431 : }
1432 65174230 : return free_index;
1433 : }
1434 :
1435 81518 : 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 79305 : return !IsStringWrapperElementsKind(elements_kind()) &&
1439 201992 : !IsSpecialReceiverMap() && !has_hidden_prototype() &&
1440 81518 : !is_dictionary_map();
1441 : }
1442 :
1443 64021 : bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) {
1444 64021 : if (IsDictionaryElementsKind(elements_kind())) {
1445 : return false;
1446 : }
1447 :
1448 200829 : for (PrototypeIterator iter(isolate, *this); !iter.IsAtEnd();
1449 138990 : iter.Advance()) {
1450 : // Be conservative, don't walk into proxies.
1451 149177 : if (iter.GetCurrent()->IsJSProxy()) return true;
1452 : // String wrappers have non-configurable, non-writable elements.
1453 144085 : if (iter.GetCurrent()->IsStringWrapper()) return true;
1454 144067 : JSObject current = iter.GetCurrent<JSObject>();
1455 :
1456 432203 : if (current->HasDictionaryElements() &&
1457 154238 : current->element_dictionary()->requires_slow_elements()) {
1458 : return true;
1459 : }
1460 :
1461 138992 : 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 56742 : return false;
1471 : }
1472 :
1473 25454574 : 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 25454574 : inobject_properties);
1478 : Handle<HeapObject> prototype(map->prototype(), isolate);
1479 25454547 : Map::SetPrototype(isolate, result, prototype);
1480 50909162 : 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 25454578 : new_bit_field3 = IsDeprecatedBit::update(new_bit_field3, false);
1489 25454578 : if (!map->is_dictionary_map()) {
1490 24469156 : new_bit_field3 = IsUnstableBit::update(new_bit_field3, false);
1491 : }
1492 25454578 : result->set_bit_field3(new_bit_field3);
1493 : result->clear_padding();
1494 25454578 : return result;
1495 : }
1496 :
1497 679294 : 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 2037884 : Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
1502 679295 : isolate);
1503 : bool use_cache =
1504 1275666 : !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
1505 : Handle<NormalizedMapCache> cache;
1506 679295 : if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
1507 :
1508 : Handle<Map> new_map;
1509 1871815 : 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 247589 : new_map = Map::CopyNormalized(isolate, fast_map, mode);
1547 247591 : if (use_cache) {
1548 164554 : cache->Set(fast_map, new_map);
1549 164554 : isolate->counters()->maps_normalized()->Increment();
1550 : }
1551 247591 : if (FLAG_trace_maps) {
1552 844 : LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason));
1553 : }
1554 : }
1555 679297 : fast_map->NotifyLeafMapLayoutChange(isolate);
1556 679297 : return new_map;
1557 : }
1558 :
1559 247700 : Handle<Map> Map::CopyNormalized(Isolate* isolate, Handle<Map> map,
1560 : PropertyNormalizationMode mode) {
1561 : int new_instance_size = map->instance_size();
1562 247700 : if (mode == CLEAR_INOBJECT_PROPERTIES) {
1563 69898 : new_instance_size -= map->GetInObjectProperties() * kTaggedSize;
1564 : }
1565 :
1566 : Handle<Map> result = RawCopy(
1567 : isolate, map, new_instance_size,
1568 425502 : 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 247702 : result->SetInObjectUnusedPropertyFields(0);
1572 247702 : result->set_is_dictionary_map(true);
1573 247702 : result->set_is_migration_target(false);
1574 247702 : result->set_may_have_interesting_symbols(true);
1575 247702 : result->set_construction_counter(kNoSlackTracking);
1576 :
1577 : #ifdef VERIFY_HEAP
1578 : if (FLAG_verify_heap) result->DictionaryMapVerify(isolate);
1579 : #endif
1580 :
1581 247702 : 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 429361 : 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 429361 : RawCopy(isolate, map, instance_size, inobject_properties);
1638 :
1639 : // Please note instance_type and instance_size are set when allocated.
1640 429362 : result->SetInObjectUnusedPropertyFields(unused_property_fields);
1641 :
1642 : int number_of_own_descriptors = map->NumberOfOwnDescriptors();
1643 429361 : 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 429361 : return result;
1654 : }
1655 :
1656 24777487 : Handle<Map> Map::CopyDropDescriptors(Isolate* isolate, Handle<Map> map) {
1657 : Handle<Map> result =
1658 : RawCopy(isolate, map, map->instance_size(),
1659 49554980 : map->IsJSObjectMap() ? map->GetInObjectProperties() : 0);
1660 :
1661 : // Please note instance_type and instance_size are set when allocated.
1662 24777520 : if (map->IsJSObjectMap()) {
1663 24777306 : result->CopyUnusedPropertyFields(*map);
1664 : }
1665 24777483 : map->NotifyLeafMapLayoutChange(isolate);
1666 24777518 : return result;
1667 : }
1668 :
1669 6188925 : 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 6188925 : 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 6188925 : 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 6188925 : if (descriptors->number_of_slack_descriptors() == 0) {
1688 2319547 : int old_size = descriptors->number_of_descriptors();
1689 2319547 : if (old_size == 0) {
1690 442 : descriptors = DescriptorArray::Allocate(isolate, 0, 1);
1691 : } else {
1692 2319105 : int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
1693 2319104 : 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 6188931 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
1703 :
1704 : {
1705 : DisallowHeapAllocation no_gc;
1706 6188928 : descriptors->Append(descriptor);
1707 6188932 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1708 : }
1709 :
1710 : DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
1711 6188929 : ConnectTransition(isolate, map, result, name, SIMPLE_PROPERTY_TRANSITION);
1712 :
1713 6188931 : return result;
1714 : }
1715 :
1716 14534902 : 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 21727914 : if (isolate->bootstrapper()->IsActive() &&
1725 : !name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
1726 7191806 : 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 14686194 : if (!parent->GetBackPointer()->IsUndefined(isolate)) {
1734 6400784 : 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 7343098 : 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 7343092 : TransitionsAccessor(isolate, parent).Insert(name, child, flag);
1749 7343094 : if (FLAG_trace_maps) {
1750 4839 : LOG(isolate, MapEvent("Transition", *parent, *child, "", *name));
1751 : }
1752 : }
1753 : }
1754 :
1755 17930373 : 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 17930373 : Handle<Map> result = CopyDropDescriptors(isolate, map);
1763 :
1764 : // Properly mark the {result} if the {name} is an "interesting symbol".
1765 : Handle<Name> name;
1766 30146303 : if (maybe_name.ToHandle(&name) && name->IsInterestingSymbol()) {
1767 877740 : result->set_may_have_interesting_symbols(true);
1768 : }
1769 :
1770 17930433 : if (!map->is_prototype_map()) {
1771 41608741 : if (flag == INSERT_TRANSITION &&
1772 30323135 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
1773 8226781 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1774 :
1775 : DCHECK(!maybe_name.is_null());
1776 8226776 : ConnectTransition(isolate, map, result, name, simple_flag);
1777 : } else {
1778 5642796 : descriptors->GeneralizeAllFields();
1779 11285578 : result->InitializeDescriptors(isolate, *descriptors,
1780 5642789 : LayoutDescriptor::FastPointerLayout());
1781 : }
1782 : } else {
1783 4060845 : result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
1784 : }
1785 35864633 : 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 17930358 : 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 170950 : 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 170950 : 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 169183 : 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 169183 : flag == INSERT_TRANSITION &&
1909 597463 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
1910 1767 : maybe_elements_transition_map.is_null();
1911 :
1912 170950 : if (insert_transition) {
1913 88147 : Handle<Map> new_map = CopyForElementsTransition(isolate, map);
1914 176294 : new_map->set_elements_kind(kind);
1915 :
1916 : Handle<Name> name = isolate->factory()->elements_transition_symbol();
1917 88147 : ConnectTransition(isolate, map, new_map, name, SPECIAL_TRANSITION);
1918 88147 : 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 88147 : Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, Handle<Map> map) {
1968 : DCHECK(!map->is_prototype_map());
1969 88147 : Handle<Map> new_map = CopyDropDescriptors(isolate, map);
1970 :
1971 88147 : 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 176158 : new_map->InitializeDescriptors(isolate, map->instance_descriptors(),
1976 88079 : 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 68 : isolate, descriptors, number_of_own_descriptors);
1984 : Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
1985 : isolate);
1986 136 : new_map->InitializeDescriptors(isolate, *new_descriptors,
1987 68 : *new_layout_descriptor);
1988 : }
1989 88147 : return new_map;
1990 : }
1991 :
1992 5713145 : 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 5713147 : 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 5713155 : MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
2002 : }
2003 :
2004 150242 : Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
2005 : Handle<Map> copy =
2006 300485 : Copy(isolate, handle(isolate->object_function()->initial_map(), isolate),
2007 150241 : "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 150243 : if (inobject_properties > JSObject::kMaxInObjectProperties) {
2013 : inobject_properties = JSObject::kMaxInObjectProperties;
2014 : }
2015 :
2016 : int new_instance_size =
2017 150243 : JSObject::kHeaderSize + kTaggedSize * inobject_properties;
2018 :
2019 : // Adjust the map with the extra inobject properties.
2020 150243 : copy->set_instance_size(new_instance_size);
2021 150244 : copy->SetInObjectPropertiesStartInWords(JSObject::kHeaderSize / kTaggedSize);
2022 : DCHECK_EQ(copy->GetInObjectProperties(), inobject_properties);
2023 150244 : copy->SetInObjectUnusedPropertyFields(inobject_properties);
2024 300486 : copy->set_visitor_id(Map::GetVisitorId(*copy));
2025 150244 : return copy;
2026 : }
2027 :
2028 138126 : 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 138126 : 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 138129 : transition_marker, reason, SPECIAL_TRANSITION);
2041 : new_map->set_is_extensible(false);
2042 138128 : if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
2043 : ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
2044 : ? SLOW_STRING_WRAPPER_ELEMENTS
2045 138061 : : DICTIONARY_ELEMENTS;
2046 138061 : switch (map->elements_kind()) {
2047 : case PACKED_ELEMENTS:
2048 496 : if (attrs_to_add == SEALED) {
2049 : new_kind = PACKED_SEALED_ELEMENTS;
2050 398 : } else if (attrs_to_add == FROZEN) {
2051 : new_kind = PACKED_FROZEN_ELEMENTS;
2052 : }
2053 : break;
2054 : case PACKED_SEALED_ELEMENTS:
2055 9 : if (attrs_to_add == FROZEN) {
2056 : new_kind = PACKED_FROZEN_ELEMENTS;
2057 : }
2058 : break;
2059 : default:
2060 : break;
2061 : }
2062 276122 : new_map->set_elements_kind(new_kind);
2063 : }
2064 138128 : return new_map;
2065 : }
2066 :
2067 : namespace {
2068 :
2069 7282739 : bool CanHoldValue(DescriptorArray descriptors, int descriptor,
2070 : PropertyConstness constness, Object value) {
2071 7282739 : PropertyDetails details = descriptors->GetDetails(descriptor);
2072 7282733 : if (details.location() == kField) {
2073 7282733 : if (details.kind() == kData) {
2074 7220521 : return IsGeneralizableTo(constness, details.constness()) &&
2075 21507551 : value->FitsRepresentation(details.representation()) &&
2076 14287030 : descriptors->GetFieldType(descriptor)->NowContains(value);
2077 : } else {
2078 : DCHECK_EQ(kAccessor, details.kind());
2079 : return false;
2080 : }
2081 :
2082 : } else {
2083 : DCHECK_EQ(kDescriptor, details.location());
2084 : DCHECK_EQ(PropertyConstness::kConst, details.constness());
2085 0 : if (details.kind() == kData) {
2086 : DCHECK(!FLAG_track_constant_fields);
2087 : DCHECK(descriptors->GetStrongValue(descriptor) != value ||
2088 : value->FitsRepresentation(details.representation()));
2089 : return descriptors->GetStrongValue(descriptor) == value;
2090 : } else {
2091 : DCHECK_EQ(kAccessor, details.kind());
2092 : return false;
2093 : }
2094 : }
2095 : UNREACHABLE();
2096 : }
2097 :
2098 7282740 : Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map,
2099 : int descriptor,
2100 : PropertyConstness constness,
2101 : Handle<Object> value) {
2102 7282740 : if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
2103 : *value)) {
2104 6997825 : return map;
2105 : }
2106 :
2107 : PropertyAttributes attributes =
2108 569819 : map->instance_descriptors()->GetDetails(descriptor).attributes();
2109 284909 : Representation representation = value->OptimalRepresentation();
2110 284909 : Handle<FieldType> type = value->OptimalType(isolate, representation);
2111 :
2112 284907 : MapUpdater mu(isolate, map);
2113 : return mu.ReconfigureToDataField(descriptor, attributes, constness,
2114 284910 : representation, type);
2115 : }
2116 :
2117 : } // namespace
2118 :
2119 : // static
2120 1904411 : Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map,
2121 : int descriptor,
2122 : PropertyConstness constness,
2123 : Handle<Object> value) {
2124 : // Dictionaries can store any property value.
2125 : DCHECK(!map->is_dictionary_map());
2126 : // Update to the newest map before storing the property.
2127 : return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor,
2128 1904411 : constness, value);
2129 : }
2130 :
2131 22369259 : Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
2132 : Handle<Name> name,
2133 : Handle<Object> value,
2134 : PropertyAttributes attributes,
2135 : PropertyConstness constness,
2136 : StoreOrigin store_origin) {
2137 : RuntimeCallTimerScope stats_scope(
2138 : isolate, *map,
2139 : map->is_prototype_map()
2140 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
2141 22369259 : : RuntimeCallCounterId::kMap_TransitionToDataProperty);
2142 :
2143 : DCHECK(name->IsUniqueName());
2144 : DCHECK(!map->is_dictionary_map());
2145 :
2146 : // Migrate to the newest map before storing the property.
2147 22369251 : map = Update(isolate, map);
2148 :
2149 : Map maybe_transition = TransitionsAccessor(isolate, map)
2150 22369255 : .SearchTransition(*name, kData, attributes);
2151 22369259 : if (!maybe_transition.is_null()) {
2152 : Handle<Map> transition(maybe_transition, isolate);
2153 : int descriptor = transition->LastAdded();
2154 :
2155 : DCHECK_EQ(attributes, transition->instance_descriptors()
2156 : ->GetDetails(descriptor)
2157 : .attributes());
2158 :
2159 : return UpdateDescriptorForValue(isolate, transition, descriptor, constness,
2160 5378336 : value);
2161 : }
2162 :
2163 : TransitionFlag flag = INSERT_TRANSITION;
2164 : MaybeHandle<Map> maybe_map;
2165 16990923 : if (!map->TooManyFastProperties(store_origin)) {
2166 : if (!FLAG_track_constant_fields && value->IsJSFunction()) {
2167 : maybe_map =
2168 : Map::CopyWithConstant(isolate, map, name, value, attributes, flag);
2169 : } else {
2170 16970750 : Representation representation = value->OptimalRepresentation();
2171 16970757 : Handle<FieldType> type = value->OptimalType(isolate, representation);
2172 : maybe_map = Map::CopyWithField(isolate, map, name, type, attributes,
2173 16970742 : constness, representation, flag);
2174 : }
2175 : }
2176 :
2177 : Handle<Map> result;
2178 16990923 : if (!maybe_map.ToHandle(&result)) {
2179 : const char* reason = "TooManyFastProperties";
2180 : #if V8_TRACE_MAPS
2181 : std::unique_ptr<ScopedVector<char>> buffer;
2182 : if (FLAG_trace_maps) {
2183 : ScopedVector<char> name_buffer(100);
2184 : name->NameShortPrint(name_buffer);
2185 : buffer.reset(new ScopedVector<char>(128));
2186 : SNPrintF(*buffer, "TooManyFastProperties %s", name_buffer.start());
2187 : reason = buffer->start();
2188 : }
2189 : #endif
2190 40662 : Handle<Object> maybe_constructor(map->GetConstructor(), isolate);
2191 20331 : if (FLAG_feedback_normalization && map->new_target_is_base() &&
2192 20331 : maybe_constructor->IsJSFunction() &&
2193 : !JSFunction::cast(*maybe_constructor)->shared()->native()) {
2194 : Handle<JSFunction> constructor =
2195 : Handle<JSFunction>::cast(maybe_constructor);
2196 : DCHECK_NE(*constructor,
2197 : constructor->context()->native_context()->object_function());
2198 : Handle<Map> initial_map(constructor->initial_map(), isolate);
2199 : result = Map::Normalize(isolate, initial_map, CLEAR_INOBJECT_PROPERTIES,
2200 0 : reason);
2201 0 : initial_map->DeprecateTransitionTree(isolate);
2202 : Handle<HeapObject> prototype(result->prototype(), isolate);
2203 0 : JSFunction::SetInitialMap(constructor, result, prototype);
2204 :
2205 : // Deoptimize all code that embeds the previous initial map.
2206 0 : initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
2207 0 : isolate, DependentCode::kInitialMapChangedGroup);
2208 0 : if (!result->EquivalentToForNormalization(*map,
2209 : CLEAR_INOBJECT_PROPERTIES)) {
2210 : result =
2211 0 : Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
2212 : }
2213 : } else {
2214 20331 : result = Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, reason);
2215 : }
2216 : }
2217 :
2218 16990923 : return result;
2219 : }
2220 :
2221 2752 : Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
2222 : int descriptor, PropertyKind kind,
2223 : PropertyAttributes attributes) {
2224 : // Dictionaries have to be reconfigured in-place.
2225 : DCHECK(!map->is_dictionary_map());
2226 :
2227 5504 : if (!map->GetBackPointer()->IsMap()) {
2228 : // There is no benefit from reconstructing transition tree for maps without
2229 : // back pointers.
2230 : return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
2231 : descriptor, kind, attributes,
2232 1211 : "GenAll_AttributesMismatchProtoMap");
2233 : }
2234 :
2235 1541 : if (FLAG_trace_generalization) {
2236 0 : map->PrintReconfiguration(isolate, stdout, descriptor, kind, attributes);
2237 : }
2238 :
2239 1541 : MapUpdater mu(isolate, map);
2240 : DCHECK_EQ(kData, kind); // Only kData case is supported so far.
2241 : Handle<Map> new_map = mu.ReconfigureToDataField(
2242 : descriptor, attributes, kDefaultFieldConstness, Representation::None(),
2243 1541 : FieldType::None(isolate));
2244 1541 : return new_map;
2245 : }
2246 :
2247 1510479 : Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
2248 : Handle<Name> name, int descriptor,
2249 : Handle<Object> getter,
2250 : Handle<Object> setter,
2251 : PropertyAttributes attributes) {
2252 : RuntimeCallTimerScope stats_scope(
2253 : isolate,
2254 : map->is_prototype_map()
2255 : ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
2256 1510479 : : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
2257 :
2258 : // At least one of the accessors needs to be a new value.
2259 : DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
2260 : DCHECK(name->IsUniqueName());
2261 :
2262 : // Dictionary maps can always have additional data properties.
2263 1510478 : if (map->is_dictionary_map()) return map;
2264 :
2265 : // Migrate to the newest map before transitioning to the new property.
2266 1510478 : map = Update(isolate, map);
2267 :
2268 : PropertyNormalizationMode mode = map->is_prototype_map()
2269 : ? KEEP_INOBJECT_PROPERTIES
2270 1510478 : : CLEAR_INOBJECT_PROPERTIES;
2271 :
2272 : Map maybe_transition = TransitionsAccessor(isolate, map)
2273 1510481 : .SearchTransition(*name, kAccessor, attributes);
2274 1510481 : if (!maybe_transition.is_null()) {
2275 : Handle<Map> transition(maybe_transition, isolate);
2276 : DescriptorArray descriptors = transition->instance_descriptors();
2277 : int descriptor = transition->LastAdded();
2278 : DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
2279 :
2280 : DCHECK_EQ(kAccessor, descriptors->GetDetails(descriptor).kind());
2281 : DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
2282 :
2283 : Handle<Object> maybe_pair(descriptors->GetStrongValue(descriptor), isolate);
2284 12032 : if (!maybe_pair->IsAccessorPair()) {
2285 : return Map::Normalize(isolate, map, mode,
2286 0 : "TransitionToAccessorFromNonPair");
2287 : }
2288 :
2289 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
2290 12032 : if (!pair->Equals(*getter, *setter)) {
2291 : return Map::Normalize(isolate, map, mode,
2292 11500 : "TransitionToDifferentAccessor");
2293 : }
2294 :
2295 532 : return transition;
2296 : }
2297 :
2298 : Handle<AccessorPair> pair;
2299 1498449 : DescriptorArray old_descriptors = map->instance_descriptors();
2300 1498449 : if (descriptor != DescriptorArray::kNotFound) {
2301 219550 : if (descriptor != map->LastAdded()) {
2302 117425 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonLast");
2303 : }
2304 102125 : PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
2305 102125 : if (old_details.kind() != kAccessor) {
2306 : return Map::Normalize(isolate, map, mode,
2307 100436 : "AccessorsOverwritingNonAccessors");
2308 : }
2309 :
2310 1689 : if (old_details.attributes() != attributes) {
2311 81 : return Map::Normalize(isolate, map, mode, "AccessorsWithAttributes");
2312 : }
2313 :
2314 : Handle<Object> maybe_pair(old_descriptors->GetStrongValue(descriptor),
2315 : isolate);
2316 1608 : if (!maybe_pair->IsAccessorPair()) {
2317 24 : return Map::Normalize(isolate, map, mode, "AccessorsOverwritingNonPair");
2318 : }
2319 :
2320 : Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
2321 1584 : if (current_pair->Equals(*getter, *setter)) return map;
2322 :
2323 : bool overwriting_accessor = false;
2324 3154 : if (!getter->IsNull(isolate) &&
2325 3064 : !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
2326 : current_pair->get(ACCESSOR_GETTER) != *getter) {
2327 : overwriting_accessor = true;
2328 : }
2329 3159 : if (!setter->IsNull(isolate) &&
2330 2760 : !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
2331 : current_pair->get(ACCESSOR_SETTER) != *setter) {
2332 : overwriting_accessor = true;
2333 : }
2334 1584 : if (overwriting_accessor) {
2335 : return Map::Normalize(isolate, map, mode,
2336 1392 : "AccessorsOverwritingAccessors");
2337 : }
2338 :
2339 192 : pair = AccessorPair::Copy(isolate, Handle<AccessorPair>::cast(maybe_pair));
2340 3836696 : } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
2341 2557797 : map->TooManyFastProperties(StoreOrigin::kNamed)) {
2342 : return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
2343 0 : "TooManyAccessors");
2344 : } else {
2345 1278899 : pair = isolate->factory()->NewAccessorPair();
2346 : }
2347 :
2348 1279088 : pair->SetComponents(*getter, *setter);
2349 :
2350 : TransitionFlag flag = INSERT_TRANSITION;
2351 1279088 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
2352 1279086 : return Map::CopyInsertDescriptor(isolate, map, &d, flag);
2353 : }
2354 :
2355 18266460 : Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
2356 : Descriptor* descriptor,
2357 : TransitionFlag flag) {
2358 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
2359 :
2360 : // Share descriptors only if map owns descriptors and it not an initial map.
2361 54751952 : if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
2362 60941068 : !map->GetBackPointer()->IsUndefined(isolate) &&
2363 24455414 : TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
2364 6188928 : return ShareDescriptor(isolate, map, descriptors, descriptor);
2365 : }
2366 :
2367 : int nof = map->NumberOfOwnDescriptors();
2368 : Handle<DescriptorArray> new_descriptors =
2369 12077559 : DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
2370 12077558 : new_descriptors->Append(descriptor);
2371 :
2372 : Handle<LayoutDescriptor> new_layout_descriptor =
2373 : FLAG_unbox_double_fields
2374 12077569 : ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
2375 12077569 : : handle(LayoutDescriptor::FastPointerLayout(), isolate);
2376 :
2377 : return CopyReplaceDescriptors(
2378 : isolate, map, new_descriptors, new_layout_descriptor, flag,
2379 12077545 : descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
2380 : }
2381 :
2382 1279119 : Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
2383 : Descriptor* descriptor,
2384 : TransitionFlag flag) {
2385 : Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
2386 :
2387 : // We replace the key if it is already present.
2388 : int index =
2389 2558244 : old_descriptors->SearchWithCache(isolate, *descriptor->GetKey(), *map);
2390 1279122 : if (index != DescriptorArray::kNotFound) {
2391 : return CopyReplaceDescriptor(isolate, map, old_descriptors, descriptor,
2392 192 : index, flag);
2393 : }
2394 1278930 : return CopyAddDescriptor(isolate, map, descriptor, flag);
2395 : }
2396 :
2397 192 : Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
2398 : Handle<DescriptorArray> descriptors,
2399 : Descriptor* descriptor,
2400 : int insertion_index,
2401 : TransitionFlag flag) {
2402 : Handle<Name> key = descriptor->GetKey();
2403 : DCHECK_EQ(*key, descriptors->GetKey(insertion_index));
2404 : // This function does not support replacing property fields as
2405 : // that would break property field counters.
2406 : DCHECK_NE(kField, descriptor->GetDetails().location());
2407 : DCHECK_NE(kField, descriptors->GetDetails(insertion_index).location());
2408 :
2409 : Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
2410 192 : isolate, descriptors, map->NumberOfOwnDescriptors());
2411 :
2412 192 : new_descriptors->Replace(insertion_index, descriptor);
2413 : Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
2414 192 : isolate, map, new_descriptors, new_descriptors->number_of_descriptors());
2415 :
2416 : SimpleTransitionFlag simple_flag =
2417 192 : (insertion_index == descriptors->number_of_descriptors() - 1)
2418 : ? SIMPLE_PROPERTY_TRANSITION
2419 192 : : PROPERTY_TRANSITION;
2420 : return CopyReplaceDescriptors(isolate, map, new_descriptors,
2421 : new_layout_descriptor, flag, key,
2422 192 : "CopyReplaceDescriptor", simple_flag);
2423 : }
2424 :
2425 760814 : int Map::Hash() {
2426 : // For performance reasons we only hash the 3 most variable fields of a map:
2427 : // constructor, prototype and bit_field2. For predictability reasons we
2428 : // use objects' offsets in respective pages for hashing instead of raw
2429 : // addresses.
2430 :
2431 : // Shift away the tag.
2432 1521628 : int hash = ObjectAddressForHashing(GetConstructor().ptr()) >> 2;
2433 :
2434 : // XOR-ing the prototype and constructor directly yields too many zero bits
2435 : // when the two pointers are close (which is fairly common).
2436 : // To avoid this we shift the prototype bits relatively to the constructor.
2437 760814 : hash ^= ObjectAddressForHashing(prototype().ptr()) << (32 - kPageSizeBits);
2438 :
2439 1521628 : return hash ^ (hash >> 16) ^ bit_field2();
2440 : }
2441 :
2442 : namespace {
2443 :
2444 526542 : bool CheckEquivalent(const Map first, const Map second) {
2445 1547163 : return first->GetConstructor() == second->GetConstructor() &&
2446 479459 : first->prototype() == second->prototype() &&
2447 479459 : first->instance_type() == second->instance_type() &&
2448 479459 : first->bit_field() == second->bit_field() &&
2449 479459 : first->is_extensible() == second->is_extensible() &&
2450 1005992 : first->new_target_is_base() == second->new_target_is_base() &&
2451 526542 : first->has_hidden_prototype() == second->has_hidden_prototype();
2452 : }
2453 :
2454 : } // namespace
2455 :
2456 426993 : bool Map::EquivalentToForTransition(const Map other) const {
2457 853985 : CHECK_EQ(GetConstructor(), other->GetConstructor());
2458 426992 : CHECK_EQ(instance_type(), other->instance_type());
2459 426992 : CHECK_EQ(has_hidden_prototype(), other->has_hidden_prototype());
2460 :
2461 426992 : if (bit_field() != other->bit_field()) return false;
2462 426983 : if (new_target_is_base() != other->new_target_is_base()) return false;
2463 426975 : if (prototype() != other->prototype()) return false;
2464 426976 : if (instance_type() == JS_FUNCTION_TYPE) {
2465 : // JSFunctions require more checks to ensure that sloppy function is
2466 : // not equivalent to strict function.
2467 : int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
2468 9566 : return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
2469 4783 : nof);
2470 : }
2471 : return true;
2472 : }
2473 :
2474 0 : bool Map::EquivalentToForElementsKindTransition(const Map other) const {
2475 32196 : if (!EquivalentToForTransition(other)) return false;
2476 : #ifdef DEBUG
2477 : // Ensure that we don't try to generate elements kind transitions from maps
2478 : // with fields that may be generalized in-place. This must already be handled
2479 : // during addition of a new field.
2480 : DescriptorArray descriptors = instance_descriptors();
2481 : int nof = NumberOfOwnDescriptors();
2482 : for (int i = 0; i < nof; i++) {
2483 : PropertyDetails details = descriptors->GetDetails(i);
2484 : if (details.location() == kField) {
2485 : DCHECK(IsMostGeneralFieldType(details.representation(),
2486 : descriptors->GetFieldType(i)));
2487 : }
2488 : }
2489 : #endif
2490 0 : return true;
2491 : }
2492 :
2493 526542 : bool Map::EquivalentToForNormalization(const Map other,
2494 : PropertyNormalizationMode mode) const {
2495 : int properties =
2496 526542 : mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
2497 1485234 : return CheckEquivalent(*this, other) && bit_field2() == other->bit_field2() &&
2498 1437490 : GetInObjectProperties() == properties &&
2499 431706 : JSObject::GetEmbedderFieldCount(*this) ==
2500 958248 : JSObject::GetEmbedderFieldCount(other);
2501 : }
2502 :
2503 379843 : static void GetMinInobjectSlack(Map map, void* data) {
2504 379843 : int slack = map->UnusedPropertyFields();
2505 379846 : if (*reinterpret_cast<int*>(data) > slack) {
2506 38939 : *reinterpret_cast<int*>(data) = slack;
2507 : }
2508 379846 : }
2509 :
2510 135402 : int Map::ComputeMinObjectSlack(Isolate* isolate) {
2511 : DisallowHeapAllocation no_gc;
2512 : // Has to be an initial map.
2513 : DCHECK(GetBackPointer()->IsUndefined(isolate));
2514 :
2515 135402 : int slack = UnusedPropertyFields();
2516 : TransitionsAccessor transitions(isolate, *this, &no_gc);
2517 : transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
2518 135405 : return slack;
2519 : }
2520 :
2521 267418 : static void ShrinkInstanceSize(Map map, void* data) {
2522 267418 : int slack = *reinterpret_cast<int*>(data);
2523 : DCHECK_GE(slack, 0);
2524 : #ifdef DEBUG
2525 : int old_visitor_id = Map::GetVisitorId(map);
2526 : int new_unused = map->UnusedPropertyFields() - slack;
2527 : #endif
2528 267418 : map->set_instance_size(map->InstanceSizeFromSlack(slack));
2529 267424 : map->set_construction_counter(Map::kNoSlackTracking);
2530 : DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
2531 : DCHECK_EQ(new_unused, map->UnusedPropertyFields());
2532 267420 : }
2533 :
2534 97977 : static void StopSlackTracking(Map map, void* data) {
2535 97977 : map->set_construction_counter(Map::kNoSlackTracking);
2536 97977 : }
2537 :
2538 128930 : void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
2539 : DisallowHeapAllocation no_gc;
2540 : // Has to be an initial map.
2541 : DCHECK(GetBackPointer()->IsUndefined(isolate));
2542 :
2543 128930 : int slack = ComputeMinObjectSlack(isolate);
2544 : TransitionsAccessor transitions(isolate, *this, &no_gc);
2545 128933 : if (slack != 0) {
2546 : // Resize the initial map and all maps in its transition tree.
2547 : transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
2548 : } else {
2549 : transitions.TraverseTransitionTree(&StopSlackTracking, nullptr);
2550 : }
2551 128933 : }
2552 :
2553 84470870 : void Map::SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors,
2554 : int number_of_own_descriptors) {
2555 84470870 : set_synchronized_instance_descriptors(descriptors);
2556 84470896 : SetNumberOfOwnDescriptors(number_of_own_descriptors);
2557 : MarkingBarrierForDescriptorArray(isolate->heap(), *this, descriptors,
2558 : number_of_own_descriptors);
2559 84470891 : }
2560 :
2561 : // static
2562 626615 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
2563 : Isolate* isolate) {
2564 : Object maybe_proto_info = prototype->map()->prototype_info();
2565 626615 : if (maybe_proto_info->IsPrototypeInfo()) {
2566 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
2567 : }
2568 137145 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
2569 274290 : prototype->map()->set_prototype_info(*proto_info);
2570 137145 : return proto_info;
2571 : }
2572 :
2573 : // static
2574 4140682 : Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
2575 : Isolate* isolate) {
2576 : Object maybe_proto_info = prototype_map->prototype_info();
2577 4140682 : if (maybe_proto_info->IsPrototypeInfo()) {
2578 : return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
2579 : }
2580 453354 : Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
2581 906714 : prototype_map->set_prototype_info(*proto_info);
2582 453355 : return proto_info;
2583 : }
2584 :
2585 : // static
2586 551048 : void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
2587 : Isolate* isolate) {
2588 551048 : if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
2589 : // "False" is the implicit default value, so there's nothing to do.
2590 : return;
2591 : }
2592 1102099 : GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
2593 : }
2594 :
2595 : // static
2596 1679795 : Handle<Object> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
2597 : Isolate* isolate) {
2598 : Handle<Object> maybe_prototype;
2599 1679795 : if (map->IsJSGlobalObjectMap()) {
2600 : DCHECK(map->is_prototype_map());
2601 : // Global object is prototype of a global proxy and therefore we can
2602 : // use its validity cell for guarding global object's prototype change.
2603 43086 : maybe_prototype = isolate->global_object();
2604 : } else {
2605 : maybe_prototype =
2606 3273426 : handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
2607 : }
2608 1679801 : if (!maybe_prototype->IsJSObject()) {
2609 67682 : return handle(Smi::FromInt(Map::kPrototypeChainValid), isolate);
2610 : }
2611 : Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
2612 : // Ensure the prototype is registered with its own prototypes so its cell
2613 : // will be invalidated when necessary.
2614 : JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
2615 1612118 : isolate);
2616 :
2617 : Object maybe_cell = prototype->map()->prototype_validity_cell();
2618 : // Return existing cell if it's still valid.
2619 1612115 : if (maybe_cell->IsCell()) {
2620 : Handle<Cell> cell(Cell::cast(maybe_cell), isolate);
2621 1612037 : if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) {
2622 1181055 : return cell;
2623 : }
2624 : }
2625 : // Otherwise create a new cell.
2626 : Handle<Cell> cell = isolate->factory()->NewCell(
2627 431066 : handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
2628 862120 : prototype->map()->set_prototype_validity_cell(*cell);
2629 431061 : return cell;
2630 : }
2631 :
2632 : // static
2633 0 : bool Map::IsPrototypeChainInvalidated(Map map) {
2634 : DCHECK(map->is_prototype_map());
2635 : Object maybe_cell = map->prototype_validity_cell();
2636 0 : if (maybe_cell->IsCell()) {
2637 : Cell cell = Cell::cast(maybe_cell);
2638 : return cell->value() != Smi::FromInt(Map::kPrototypeChainValid);
2639 : }
2640 : return true;
2641 : }
2642 :
2643 : // static
2644 31646190 : void Map::SetPrototype(Isolate* isolate, Handle<Map> map,
2645 : Handle<HeapObject> prototype,
2646 : bool enable_prototype_setup_mode) {
2647 : RuntimeCallTimerScope stats_scope(isolate, *map,
2648 : RuntimeCallCounterId::kMap_SetPrototype);
2649 :
2650 : bool is_hidden = false;
2651 31646186 : if (prototype->IsJSObject()) {
2652 : Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
2653 26127929 : JSObject::OptimizeAsPrototype(prototype_jsobj, enable_prototype_setup_mode);
2654 :
2655 26127996 : Object maybe_constructor = prototype_jsobj->map()->GetConstructor();
2656 26128011 : if (maybe_constructor->IsJSFunction()) {
2657 : JSFunction constructor = JSFunction::cast(maybe_constructor);
2658 : Object data = constructor->shared()->function_data();
2659 238163 : is_hidden = (data->IsFunctionTemplateInfo() &&
2660 50505034 : FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
2661 : prototype->IsJSGlobalObject();
2662 875499 : } else if (maybe_constructor->IsFunctionTemplateInfo()) {
2663 : is_hidden =
2664 36 : FunctionTemplateInfo::cast(maybe_constructor)->hidden_prototype() ||
2665 : prototype->IsJSGlobalObject();
2666 : }
2667 : } else {
2668 : DCHECK(prototype->IsNull(isolate) || prototype->IsJSProxy());
2669 : }
2670 63292536 : map->set_has_hidden_prototype(is_hidden);
2671 :
2672 : WriteBarrierMode wb_mode =
2673 31646304 : prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
2674 31646304 : map->set_prototype(*prototype, wb_mode);
2675 31646274 : }
2676 :
2677 313126 : void Map::StartInobjectSlackTracking() {
2678 : DCHECK(!IsInobjectSlackTrackingInProgress());
2679 313126 : if (UnusedPropertyFields() == 0) return;
2680 228258 : set_construction_counter(Map::kSlackTrackingCounterStart);
2681 : }
2682 :
2683 185634 : Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
2684 : Handle<HeapObject> prototype) {
2685 : Handle<Map> new_map =
2686 185634 : TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
2687 185634 : if (new_map.is_null()) {
2688 169405 : new_map = Copy(isolate, map, "TransitionToPrototype");
2689 : TransitionsAccessor(isolate, map)
2690 169405 : .PutPrototypeTransition(prototype, new_map);
2691 169405 : Map::SetPrototype(isolate, new_map, prototype);
2692 : }
2693 185634 : return new_map;
2694 : }
2695 :
2696 111 : Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
2697 : Handle<WeakFixedArray> array(
2698 111 : isolate->factory()->NewWeakFixedArray(kEntries, AllocationType::kOld));
2699 111 : return Handle<NormalizedMapCache>::cast(array);
2700 : }
2701 :
2702 596260 : MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
2703 : PropertyNormalizationMode mode) {
2704 : DisallowHeapAllocation no_gc;
2705 : MaybeObject value = WeakFixedArray::Get(GetIndex(fast_map));
2706 : HeapObject heap_object;
2707 596260 : if (!value->GetHeapObjectIfWeak(&heap_object)) {
2708 69718 : return MaybeHandle<Map>();
2709 : }
2710 :
2711 526542 : Map normalized_map = Map::cast(heap_object);
2712 526542 : if (!normalized_map->EquivalentToForNormalization(*fast_map, mode)) {
2713 94836 : return MaybeHandle<Map>();
2714 : }
2715 431706 : return handle(normalized_map, GetIsolate());
2716 : }
2717 :
2718 164554 : void NormalizedMapCache::Set(Handle<Map> fast_map, Handle<Map> normalized_map) {
2719 : DisallowHeapAllocation no_gc;
2720 : DCHECK(normalized_map->is_dictionary_map());
2721 164554 : WeakFixedArray::Set(GetIndex(fast_map),
2722 329108 : HeapObjectReference::Weak(*normalized_map));
2723 164554 : }
2724 :
2725 : } // namespace internal
2726 122004 : } // namespace v8
|