From 70d5e6d582bcbca3a993ff0850413a07c34ab351 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Mon, 23 May 2011 15:59:38 +0000 Subject: [PATCH] Add bit_field3 to Map objects Reuse instance_descriptor field in the map to store additional flags when there are no descriptors. When descriptors get added to the map, move the flags to the DescriptorArray and access through indirection. Review URL: http://codereview.chromium.org/7033024 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8001 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 9 ++-- src/arm/macro-assembler-arm.cc | 11 +++++ src/arm/macro-assembler-arm.h | 2 + src/heap.cc | 10 ++--- src/ia32/full-codegen-ia32.cc | 9 ++-- src/ia32/macro-assembler-ia32.cc | 11 +++++ src/ia32/macro-assembler-ia32.h | 2 + src/mark-compact.cc | 9 +++- src/objects-debug.cc | 4 +- src/objects-inl.h | 94 ++++++++++++++++++++++++++++++++++++++-- src/objects.cc | 17 +++++--- src/objects.h | 59 ++++++++++++++++++++----- src/profile-generator.cc | 8 ++-- src/x64/full-codegen-x64.cc | 9 ++-- src/x64/macro-assembler-x64.cc | 11 +++++ src/x64/macro-assembler-x64.h | 2 + 16 files changed, 219 insertions(+), 48 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 2b7cdef..d4dcc40 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -924,9 +924,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // check for an enum cache. Leave the map in r2 for the subsequent // prototype load. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); - __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset)); - __ cmp(r3, empty_descriptor_array_value); - __ b(eq, &call_runtime); + __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBitField3Offset)); + __ JumpIfSmi(r3, &call_runtime); // Check that there is an enum cache in the non-empty instance // descriptors (r3). This is the case if the next enumeration @@ -971,7 +970,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a map in register r0. Get the enumeration cache from it. __ bind(&use_cache); - __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(r0, r1); __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -2544,7 +2543,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( // Look for valueOf symbol in the descriptor array, and indicate false if // found. The type is not checked, so if it is a transition it is a false // negative. - __ ldr(r4, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(r1, r4); __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); // r4: descriptor array // r3: length of descriptor array diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 885dd5a..afc2d0a 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -3083,6 +3083,17 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, } +void MacroAssembler::LoadInstanceDescriptors(Register map, + Register descriptors) { + ldr(descriptors, + FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); + Label not_smi; + JumpIfNotSmi(descriptors, ¬_smi); + mov(descriptors, Operand(FACTORY->empty_descriptor_array())); + bind(¬_smi); +} + + CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), instructions_(instructions), diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 8996537..89fd1f9 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -1006,6 +1006,8 @@ class MacroAssembler: public Assembler { DoubleRegister temp_double_reg); + void LoadInstanceDescriptors(Register map, Register descriptors); + private: void CallCFunctionHelper(Register function, ExternalReference function_reference, diff --git a/src/heap.cc b/src/heap.cc index ef63a26..0776afc 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -1603,7 +1603,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { map->set_instance_size(instance_size); map->set_inobject_properties(0); map->set_pre_allocated_property_fields(0); - map->set_instance_descriptors(empty_descriptor_array()); + map->init_instance_descriptors(); map->set_code_cache(empty_fixed_array()); map->set_prototype_transitions(empty_fixed_array()); map->set_unused_property_fields(0); @@ -1696,15 +1696,15 @@ bool Heap::CreateInitialMaps() { set_empty_descriptor_array(DescriptorArray::cast(obj)); // Fix the instance_descriptors for the existing maps. - meta_map()->set_instance_descriptors(empty_descriptor_array()); + meta_map()->init_instance_descriptors(); meta_map()->set_code_cache(empty_fixed_array()); meta_map()->set_prototype_transitions(empty_fixed_array()); - fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); + fixed_array_map()->init_instance_descriptors(); fixed_array_map()->set_code_cache(empty_fixed_array()); fixed_array_map()->set_prototype_transitions(empty_fixed_array()); - oddball_map()->set_instance_descriptors(empty_descriptor_array()); + oddball_map()->init_instance_descriptors(); oddball_map()->set_code_cache(empty_fixed_array()); oddball_map()->set_prototype_transitions(empty_fixed_array()); @@ -3307,7 +3307,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) { // Setup the global object as a normalized object. global->set_map(new_map); - global->map()->set_instance_descriptors(empty_descriptor_array()); + global->map()->clear_instance_descriptors(); global->set_properties(dictionary); // Make sure result is a global object with properties in dictionary. diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index d20e622..5810ab1 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -887,9 +887,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // check for an enum cache. Leave the map in ebx for the subsequent // prototype load. __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); - __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); - __ cmp(edx, isolate()->factory()->empty_descriptor_array()); - __ j(equal, &call_runtime); + __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset)); + __ JumpIfSmi(edx, &call_runtime); // Check that there is an enum cache in the non-empty instance // descriptors (edx). This is the case if the next enumeration @@ -933,7 +932,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a map in register eax. Get the enumeration cache from it. __ bind(&use_cache); - __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(eax, ecx); __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -2472,7 +2471,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( // Look for valueOf symbol in the descriptor array, and indicate false if // found. The type is not checked, so if it is a transition it is a false // negative. - __ mov(ebx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(ebx, ebx); __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); // ebx: descriptor array // ecx: length of descriptor array diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 047236f..6c02ce4 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1974,6 +1974,17 @@ void MacroAssembler::Abort(const char* msg) { } +void MacroAssembler::LoadInstanceDescriptors(Register map, + Register descriptors) { + mov(descriptors, + FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); + Label not_smi; + JumpIfNotSmi(descriptors, ¬_smi); + mov(descriptors, isolate()->factory()->empty_descriptor_array()); + bind(¬_smi); +} + + void MacroAssembler::LoadPowerOf2(XMMRegister dst, Register scratch, int power) { diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 837e981..04e805e 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -284,6 +284,8 @@ class MacroAssembler: public Assembler { j(not_zero, not_smi_label); } + void LoadInstanceDescriptors(Register map, Register descriptors); + void LoadPowerOf2(XMMRegister dst, Register scratch, int power); // Abort execution if argument is not a number. Used in debug code. diff --git a/src/mark-compact.cc b/src/mark-compact.cc index b82c76a..160dba8 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -1081,8 +1081,13 @@ void MarkCompactCollector::MarkMapContents(Map* map) { FixedArray* prototype_transitions = map->unchecked_prototype_transitions(); if (!prototype_transitions->IsMarked()) SetMark(prototype_transitions); - MarkDescriptorArray(reinterpret_cast( - *HeapObject::RawField(map, Map::kInstanceDescriptorsOffset))); + Object* raw_descriptor_array = + *HeapObject::RawField(map, + Map::kInstanceDescriptorsOrBitField3Offset); + if (!raw_descriptor_array->IsSmi()) { + MarkDescriptorArray( + reinterpret_cast(raw_descriptor_array)); + } // Mark the Object* fields of the Map. // Since the descriptor array has been marked already, it is fine diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 05ae00c..4072f8f 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -272,7 +272,7 @@ void Map::MapVerify() { void Map::SharedMapVerify() { MapVerify(); ASSERT(is_shared()); - ASSERT_EQ(GetHeap()->empty_descriptor_array(), instance_descriptors()); + ASSERT(instance_descriptors()->IsEmpty()); ASSERT_EQ(0, pre_allocated_property_fields()); ASSERT_EQ(0, unused_property_fields()); ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), diff --git a/src/objects-inl.h b/src/objects-inl.h index 841fcbc..3828db8 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1674,9 +1674,21 @@ Object** FixedArray::data_start() { bool DescriptorArray::IsEmpty() { - ASSERT(this->length() > kFirstIndex || + ASSERT(this->IsSmi() || + this->length() > kFirstIndex || this == HEAP->empty_descriptor_array()); - return length() <= kFirstIndex; + return this->IsSmi() || length() <= kFirstIndex; +} + + +int DescriptorArray::bit_field3_storage() { + Object* storage = READ_FIELD(this, kBitField3StorageOffset); + return Smi::cast(storage)->value(); +} + +void DescriptorArray::set_bit_field3_storage(int value) { + ASSERT(!IsEmpty()); + WRITE_FIELD(this, kBitField3StorageOffset, Smi::FromInt(value)); } @@ -2967,8 +2979,82 @@ MaybeObject* Map::GetSlowElementsMap() { } -ACCESSORS(Map, instance_descriptors, DescriptorArray, - kInstanceDescriptorsOffset) +DescriptorArray* Map::instance_descriptors() { + Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset); + if (object->IsSmi()) { + return HEAP->empty_descriptor_array(); + } else { + return DescriptorArray::cast(object); + } +} + + +void Map::init_instance_descriptors() { + WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, Smi::FromInt(0)); +} + + +void Map::clear_instance_descriptors() { + Object* object = READ_FIELD(this, + kInstanceDescriptorsOrBitField3Offset); + if (!object->IsSmi()) { + WRITE_FIELD( + this, + kInstanceDescriptorsOrBitField3Offset, + Smi::FromInt(DescriptorArray::cast(object)->bit_field3_storage())); + } +} + + +void Map::set_instance_descriptors(DescriptorArray* value, + WriteBarrierMode mode) { + Object* object = READ_FIELD(this, + kInstanceDescriptorsOrBitField3Offset); + if (value == isolate()->heap()->empty_descriptor_array()) { + clear_instance_descriptors(); + return; + } else { + if (object->IsSmi()) { + value->set_bit_field3_storage(Smi::cast(object)->value()); + } else { + value->set_bit_field3_storage( + DescriptorArray::cast(object)->bit_field3_storage()); + } + } + ASSERT(!is_shared()); + WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value); + CONDITIONAL_WRITE_BARRIER(GetHeap(), + this, + kInstanceDescriptorsOrBitField3Offset, + mode); +} + + +int Map::bit_field3() { + Object* object = READ_FIELD(this, + kInstanceDescriptorsOrBitField3Offset); + if (object->IsSmi()) { + return Smi::cast(object)->value(); + } else { + return DescriptorArray::cast(object)->bit_field3_storage(); + } +} + + +void Map::set_bit_field3(int value) { + ASSERT(Smi::IsValid(value)); + Object* object = READ_FIELD(this, + kInstanceDescriptorsOrBitField3Offset); + if (object->IsSmi()) { + WRITE_FIELD(this, + kInstanceDescriptorsOrBitField3Offset, + Smi::FromInt(value)); + } else { + DescriptorArray::cast(object)->set_bit_field3_storage(value); + } +} + + ACCESSORS(Map, code_cache, Object, kCodeCacheOffset) ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset) ACCESSORS(Map, constructor, Object, kConstructorOffset) diff --git a/src/objects.cc b/src/objects.cc index d81e198..52b7add 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2535,6 +2535,7 @@ bool NormalizedMapCache::CheckHit(Map* slow, fast->inobject_properties()) && slow->instance_type() == fast->instance_type() && slow->bit_field() == fast->bit_field() && + slow->bit_field3() == fast->bit_field3() && (slow->bit_field2() & ~(1<bit_field2(); } @@ -2657,7 +2658,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, instance_size_delta); set_map(new_map); - new_map->set_instance_descriptors(current_heap->empty_descriptor_array()); + new_map->clear_instance_descriptors(); set_properties(dictionary); @@ -3647,8 +3648,7 @@ MaybeObject* Map::CopyDropDescriptors() { // pointing to the same transition which is bad because the garbage // collector relies on being able to reverse pointers from transitions // to maps. If properties need to be retained use CopyDropTransitions. - Map::cast(result)->set_instance_descriptors( - heap->empty_descriptor_array()); + Map::cast(result)->clear_instance_descriptors(); // Please note instance_type and instance_size are set when allocated. Map::cast(result)->set_inobject_properties(inobject_properties()); Map::cast(result)->set_unused_property_fields(unused_property_fields()); @@ -3670,6 +3670,7 @@ MaybeObject* Map::CopyDropDescriptors() { } Map::cast(result)->set_bit_field(bit_field()); Map::cast(result)->set_bit_field2(bit_field2()); + Map::cast(result)->set_bit_field3(bit_field3()); Map::cast(result)->set_is_shared(false); Map::cast(result)->ClearCodeCache(heap); return result; @@ -3698,6 +3699,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, Map::cast(result)->set_bit_field(bit_field()); Map::cast(result)->set_bit_field2(bit_field2()); + Map::cast(result)->set_bit_field3(bit_field3()); Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); @@ -3773,8 +3775,8 @@ void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { Map* meta_map = heap()->meta_map(); while (current != meta_map) { DescriptorArray* d = reinterpret_cast( - *RawField(current, Map::kInstanceDescriptorsOffset)); - if (d == heap()->empty_descriptor_array()) { + *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); + if (d->IsEmpty()) { Map* prev = current->map(); current->set_map(meta_map); callback(current, data); @@ -4245,6 +4247,7 @@ MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { heap->AllocateFixedArray(number_of_descriptors << 1); if (!maybe_array->ToObject(&array)) return maybe_array; } + result->set(kBitField3StorageIndex, Smi::FromInt(0)); result->set(kContentArrayIndex, array); result->set(kEnumerationIndexIndex, Smi::FromInt(PropertyDetails::kInitialIndex)); @@ -5701,8 +5704,8 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { // Live DescriptorArray objects will be marked, so we must use // low-level accessors to get and modify their data. DescriptorArray* d = reinterpret_cast( - *RawField(this, Map::kInstanceDescriptorsOffset)); - if (d == heap->raw_unchecked_empty_descriptor_array()) return; + *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); + if (d->IsEmpty()) return; Smi* NullDescriptorDetails = PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); FixedArray* contents = reinterpret_cast( diff --git a/src/objects.h b/src/objects.h index b511213..edcfab5 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2039,16 +2039,22 @@ class FixedArray: public HeapObject { // DescriptorArrays are fixed arrays used to hold instance descriptors. // The format of the these objects is: -// [0]: point to a fixed array with (value, detail) pairs. -// [1]: next enumeration index (Smi), or pointer to small fixed array: +// TODO(1399): It should be possible to make room for bit_field3 in the map +// without overloading the instance descriptors field in the map +// (and storing it in the DescriptorArray when the map has one). +// [0]: storage for bit_field3 for Map owning this object (Smi) +// [1]: point to a fixed array with (value, detail) pairs. +// [2]: next enumeration index (Smi), or pointer to small fixed array: // [0]: next enumeration index (Smi) // [1]: pointer to fixed array with enum cache -// [2]: first key +// [3]: first key // [length() - 1]: last key // class DescriptorArray: public FixedArray { public: - // Is this the singleton empty_descriptor_array? + // Returns true for both shared empty_descriptor_array and for smis, which the + // map uses to encode additional bit fields when the descriptor array is not + // yet used. inline bool IsEmpty(); // Returns the number of descriptors in the array. @@ -2085,6 +2091,12 @@ class DescriptorArray: public FixedArray { return bridge->get(kEnumCacheBridgeCacheIndex); } + // TODO(1399): It should be possible to make room for bit_field3 in the map + // without overloading the instance descriptors field in the map + // (and storing it in the DescriptorArray when the map has one). + inline int bit_field3_storage(); + inline void set_bit_field3_storage(int value); + // Initialize or change the enum cache, // using the supplied storage for the small "bridge". void SetEnumCache(FixedArray* bridge_storage, FixedArray* new_cache); @@ -2163,9 +2175,10 @@ class DescriptorArray: public FixedArray { // Constant for denoting key was not found. static const int kNotFound = -1; - static const int kContentArrayIndex = 0; - static const int kEnumerationIndexIndex = 1; - static const int kFirstIndex = 2; + static const int kBitField3StorageIndex = 0; + static const int kContentArrayIndex = 1; + static const int kEnumerationIndexIndex = 2; + static const int kFirstIndex = 3; // The length of the "bridge" to the enum cache. static const int kEnumCacheBridgeLength = 2; @@ -2173,7 +2186,8 @@ class DescriptorArray: public FixedArray { static const int kEnumCacheBridgeCacheIndex = 1; // Layout description. - static const int kContentArrayOffset = FixedArray::kHeaderSize; + static const int kBitField3StorageOffset = FixedArray::kHeaderSize; + static const int kContentArrayOffset = kBitField3StorageOffset + kPointerSize; static const int kEnumerationIndexOffset = kContentArrayOffset + kPointerSize; static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize; @@ -3645,6 +3659,13 @@ class Map: public HeapObject { inline byte bit_field2(); inline void set_bit_field2(byte value); + // Bit field 3. + // TODO(1399): It should be possible to make room for bit_field3 in the map + // without overloading the instance descriptors field (and storing it in the + // DescriptorArray when the map has one). + inline int bit_field3(); + inline void set_bit_field3(int value); + // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype // property is set to a value that is not a JSObject, the prototype @@ -3766,9 +3787,17 @@ class Map: public HeapObject { inline JSFunction* unchecked_constructor(); + // Should only be called by the code that initializes map to set initial valid + // value of the instance descriptor member. + inline void init_instance_descriptors(); + // [instance descriptors]: describes the object. DECL_ACCESSORS(instance_descriptors, DescriptorArray) + // Sets the instance descriptor array for the map to be an empty descriptor + // array. + inline void clear_instance_descriptors(); + // [stub cache]: contains stubs compiled for this map. DECL_ACCESSORS(code_cache, Object) @@ -3894,9 +3923,19 @@ class Map: public HeapObject { static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; static const int kConstructorOffset = kPrototypeOffset + kPointerSize; - static const int kInstanceDescriptorsOffset = + // Storage for instance descriptors is overloaded to also contain additional + // map flags when unused (bit_field3). When the map has instance descriptors, + // the flags are transferred to the instance descriptor array and accessed + // through an extra indirection. + // TODO(1399): It should be possible to make room for bit_field3 in the map + // without overloading the instance descriptors field, but the map is + // currently perfectly aligned to 32 bytes and extending it at all would + // double its size. After the increment GC work lands, this size restriction + // could be loosened and bit_field3 moved directly back in the map. + static const int kInstanceDescriptorsOrBitField3Offset = kConstructorOffset + kPointerSize; - static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize; + static const int kCodeCacheOffset = + kInstanceDescriptorsOrBitField3Offset + kPointerSize; static const int kPrototypeTransitionsOffset = kCodeCacheOffset + kPointerSize; static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize; diff --git a/src/profile-generator.cc b/src/profile-generator.cc index 82696a9..0cf96ba 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -1865,9 +1865,11 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { SetInternalReference(obj, entry, "constructor", map->constructor(), Map::kConstructorOffset); - SetInternalReference(obj, entry, - "descriptors", map->instance_descriptors(), - Map::kInstanceDescriptorsOffset); + if (!map->instance_descriptors()->IsEmpty()) { + SetInternalReference(obj, entry, + "descriptors", map->instance_descriptors(), + Map::kInstanceDescriptorsOrBitField3Offset); + } SetInternalReference(obj, entry, "code_cache", map->code_cache(), Map::kCodeCacheOffset); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index d5a220f..e2bdef7 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -896,9 +896,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // check for an enum cache. Leave the map in rbx for the subsequent // prototype load. __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); - __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset)); - __ cmpq(rdx, empty_descriptor_array_value); - __ j(equal, &call_runtime); + __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset)); + __ JumpIfSmi(rdx, &call_runtime); // Check that there is an enum cache in the non-empty instance // descriptors (rdx). This is the case if the next enumeration @@ -941,7 +940,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a map in register rax. Get the enumeration cache from it. __ bind(&use_cache); - __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(rax, rcx); __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -2442,7 +2441,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( // Look for valueOf symbol in the descriptor array, and indicate false if // found. The type is not checked, so if it is a transition it is a false // negative. - __ movq(rbx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(rbx, rbx); __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); // rbx: descriptor array // rcx: length of descriptor array diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 64f42f4..0cfec36 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -2601,6 +2601,17 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, } +void MacroAssembler::LoadInstanceDescriptors(Register map, + Register descriptors) { + movq(descriptors, FieldOperand(map, + Map::kInstanceDescriptorsOrBitField3Offset)); + Label not_smi; + JumpIfNotSmi(descriptors, ¬_smi, Label::kNear); + Move(descriptors, isolate()->factory()->empty_descriptor_array()); + bind(¬_smi); +} + + void MacroAssembler::DispatchMap(Register obj, Handle map, Handle success, diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index d7d5af3..978fa0d 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -782,6 +782,8 @@ class MacroAssembler: public Assembler { Register result_reg, Register temp_reg); + void LoadInstanceDescriptors(Register map, Register descriptors); + // Abort execution if argument is not a number. Used in debug code. void AbortIfNotNumber(Register object); -- 2.7.4