From eee5e6c3fc766e7120cc5ce7934474f21b13a609 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Fri, 3 Jun 2011 07:41:37 +0000 Subject: [PATCH] Add complete ElementsKind information directly to Map for objects with elements. Review URL: http://codereview.chromium.org/6966041 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8162 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 4 +-- src/arm/ic-arm.cc | 7 ++--- src/arm/macro-assembler-arm.cc | 10 ++++++ src/arm/macro-assembler-arm.h | 6 ++++ src/heap.cc | 3 +- src/ia32/full-codegen-ia32.cc | 4 +-- src/ia32/ic-ia32.cc | 7 ++--- src/ia32/macro-assembler-ia32.cc | 10 ++++++ src/ia32/macro-assembler-ia32.h | 6 ++++ src/objects-inl.h | 52 +++++++------------------------ src/objects.cc | 39 +++++++++++++++++++++-- src/objects.h | 67 ++++++++++++++++++++++++---------------- src/x64/full-codegen-x64.cc | 4 +-- src/x64/ic-x64.cc | 7 ++--- src/x64/macro-assembler-x64.cc | 10 ++++++ src/x64/macro-assembler-x64.h | 6 ++++ 16 files changed, 148 insertions(+), 94 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index d457ca5..434abf2 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -3436,9 +3436,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList* args) { __ b(ne, &bailout); // Check that the array has fast elements. - __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); - __ tst(scratch2, Operand(1 << Map::kHasFastElements)); - __ b(eq, &bailout); + __ CheckFastElements(scratch1, scratch2, &bailout); // If the array has length zero, return the empty string. __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index 76a2723..c92296d 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -944,11 +944,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { GenerateKeyedLoadReceiverCheck( masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow); - // Check the "has fast elements" bit in the receiver's map which is - // now in r2. - __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset)); - __ tst(r3, Operand(1 << Map::kHasFastElements)); - __ b(eq, &check_number_dictionary); + // Check the receiver's map to see if it has fast elements. + __ CheckFastElements(r2, r3, &check_number_dictionary); GenerateFastArrayLoad( masm, receiver, key, r4, r3, r2, r0, NULL, &slow); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 412091d..dc90426 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1677,6 +1677,16 @@ void MacroAssembler::CompareRoot(Register obj, } +void MacroAssembler::CheckFastElements(Register map, + Register scratch, + Label* fail) { + STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); + ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); + cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue)); + b(hi, fail); +} + + void MacroAssembler::CheckMap(Register obj, Register scratch, Handle map, diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 5d2c3ba..2dda57d 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -577,6 +577,12 @@ class MacroAssembler: public Assembler { InstanceType type); + // Check if a map for a JSObject indicates that the object has fast elements. + // Jump to the specified label if it does not. + void CheckFastElements(Register map, + Register scratch, + Label* fail); + // Check if the map of an object is equal to a specified map (either // given directly or as an index into the root list) and branch to // label if not. Skip the smi check if not required (object is known diff --git a/src/heap.cc b/src/heap.cc index 75748dd..aa728fd 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -1636,7 +1636,8 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { map->set_prototype_transitions(empty_fixed_array()); map->set_unused_property_fields(0); map->set_bit_field(0); - map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements)); + map->set_bit_field2(1 << Map::kIsExtensible); + map->set_elements_kind(JSObject::FAST_ELEMENTS); // If the map object is aligned fill the padding area with Smi 0 objects. if (Map::kPadStart < Map::kSize) { diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 4799738..d13edcf 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -3374,9 +3374,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList* args) { __ j(not_equal, &bailout); // Check that the array has fast elements. - __ test_b(FieldOperand(scratch, Map::kBitField2Offset), - 1 << Map::kHasFastElements); - __ j(zero, &bailout); + __ CheckFastElements(scratch, &bailout); // If the array has length zero, return the empty string. __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index a2678b2..f5ff341 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -484,11 +484,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { GenerateKeyedLoadReceiverCheck( masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); - // Check the "has fast elements" bit in the receiver's map which is - // now in ecx. - __ test_b(FieldOperand(ecx, Map::kBitField2Offset), - 1 << Map::kHasFastElements); - __ j(zero, &check_number_dictionary); + // Check the receiver's map to see if it has fast elements. + __ CheckFastElements(ecx, &check_number_dictionary); GenerateFastArrayLoad(masm, edx, diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 05a5fbf..4aba1d6 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -279,6 +279,16 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { } +void MacroAssembler::CheckFastElements(Register map, + Label* fail, + Label::Distance distance) { + STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); + cmpb(FieldOperand(map, Map::kBitField2Offset), + Map::kMaximumBitField2FastElementValue); + j(above, fail, distance); +} + + void MacroAssembler::CheckMap(Register obj, Handle map, Label* fail, diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 2ab98c5..93d7e2e 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -216,6 +216,12 @@ class MacroAssembler: public Assembler { // Compare instance type for map. void CmpInstanceType(Register map, InstanceType type); + // Check if a map for a JSObject indicates that the object has fast elements. + // Jump to the specified label if it does not. + void CheckFastElements(Register map, + Label* fail, + Label::Distance distance = Label::kFar); + // Check if the map of an object is equal to a specified map and branch to // label if not. Skip the smi check if not required (object is known to be a // heap object) diff --git a/src/objects-inl.h b/src/objects-inl.h index 29a368c..597e0df 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2974,7 +2974,7 @@ MaybeObject* Map::GetFastElementsMap() { if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); - new_map->set_has_fast_elements(true); + new_map->set_elements_kind(JSObject::FAST_ELEMENTS); isolate()->counters()->map_slow_to_fast_elements()->Increment(); return new_map; } @@ -2987,7 +2987,7 @@ MaybeObject* Map::GetSlowElementsMap() { if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); - new_map->set_has_fast_elements(false); + new_map->set_elements_kind(JSObject::DICTIONARY_ELEMENTS); isolate()->counters()->map_fast_to_slow_elements()->Increment(); return new_map; } @@ -3776,45 +3776,15 @@ void JSRegExp::SetDataAt(int index, Object* value) { JSObject::ElementsKind JSObject::GetElementsKind() { - if (map()->has_fast_elements()) { - ASSERT(elements()->map() == GetHeap()->fixed_array_map() || - elements()->map() == GetHeap()->fixed_cow_array_map()); - return FAST_ELEMENTS; - } - HeapObject* array = elements(); - if (array->IsFixedArray()) { - // FAST_ELEMENTS or DICTIONARY_ELEMENTS are both stored in a - // FixedArray, but FAST_ELEMENTS is already handled above. - ASSERT(array->IsDictionary()); - return DICTIONARY_ELEMENTS; - } - ASSERT(!map()->has_fast_elements()); - if (array->IsExternalArray()) { - switch (array->map()->instance_type()) { - case EXTERNAL_BYTE_ARRAY_TYPE: - return EXTERNAL_BYTE_ELEMENTS; - case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: - return EXTERNAL_UNSIGNED_BYTE_ELEMENTS; - case EXTERNAL_SHORT_ARRAY_TYPE: - return EXTERNAL_SHORT_ELEMENTS; - case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: - return EXTERNAL_UNSIGNED_SHORT_ELEMENTS; - case EXTERNAL_INT_ARRAY_TYPE: - return EXTERNAL_INT_ELEMENTS; - case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: - return EXTERNAL_UNSIGNED_INT_ELEMENTS; - case EXTERNAL_FLOAT_ARRAY_TYPE: - return EXTERNAL_FLOAT_ELEMENTS; - case EXTERNAL_DOUBLE_ARRAY_TYPE: - return EXTERNAL_DOUBLE_ELEMENTS; - case EXTERNAL_PIXEL_ARRAY_TYPE: - return EXTERNAL_PIXEL_ELEMENTS; - default: - break; - } - } - UNREACHABLE(); - return DICTIONARY_ELEMENTS; + ElementsKind kind = map()->elements_kind(); + ASSERT((kind == FAST_ELEMENTS && + (elements()->map() == GetHeap()->fixed_array_map() || + elements()->map() == GetHeap()->fixed_cow_array_map())) || + (kind == DICTIONARY_ELEMENTS && + elements()->IsFixedArray() && + elements()->IsDictionary()) || + (kind > DICTIONARY_ELEMENTS)); + return kind; } diff --git a/src/objects.cc b/src/objects.cc index bf881e9..04cb528 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1941,6 +1941,42 @@ void Map::LookupInDescriptors(JSObject* holder, } +static JSObject::ElementsKind GetElementsKindFromExternalArrayType( + ExternalArrayType array_type) { + switch (array_type) { + case kExternalByteArray: + return JSObject::EXTERNAL_BYTE_ELEMENTS; + break; + case kExternalUnsignedByteArray: + return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS; + break; + case kExternalShortArray: + return JSObject::EXTERNAL_SHORT_ELEMENTS; + break; + case kExternalUnsignedShortArray: + return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS; + break; + case kExternalIntArray: + return JSObject::EXTERNAL_INT_ELEMENTS; + break; + case kExternalUnsignedIntArray: + return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS; + break; + case kExternalFloatArray: + return JSObject::EXTERNAL_FLOAT_ELEMENTS; + break; + case kExternalDoubleArray: + return JSObject::EXTERNAL_DOUBLE_ELEMENTS; + break; + case kExternalPixelArray: + return JSObject::EXTERNAL_PIXEL_ELEMENTS; + break; + } + UNREACHABLE(); + return JSObject::DICTIONARY_ELEMENTS; +} + + MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, bool safe_to_add_transition) { Heap* current_heap = heap(); @@ -1983,8 +2019,7 @@ MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, } Map* new_map = Map::cast(obj); - new_map->set_has_fast_elements(false); - new_map->set_has_external_array_elements(true); + new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type)); GetIsolate()->counters()->map_to_external_array_elements()->Increment(); // Only remember the map transition if the object's map is NOT equal to the diff --git a/src/objects.h b/src/objects.h index 0df7c78..15f2275 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1420,10 +1420,12 @@ class JSObject: public JSReceiver { }; enum ElementsKind { - // The only "fast" kind. + // The "fast" kind for tagged values. Must be first to make it possible + // to efficiently check maps if they have fast elements. FAST_ELEMENTS, - // All the kinds below are "slow". + // The "slow" kind. DICTIONARY_ELEMENTS, + // The "fast" kind for external arrays EXTERNAL_BYTE_ELEMENTS, EXTERNAL_UNSIGNED_BYTE_ELEMENTS, EXTERNAL_SHORT_ELEMENTS, @@ -1432,9 +1434,18 @@ class JSObject: public JSReceiver { EXTERNAL_UNSIGNED_INT_ELEMENTS, EXTERNAL_FLOAT_ELEMENTS, EXTERNAL_DOUBLE_ELEMENTS, - EXTERNAL_PIXEL_ELEMENTS + EXTERNAL_PIXEL_ELEMENTS, + + // Derived constants from ElementsKind + FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS, + LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS, + FIRST_ELEMENTS_KIND = FAST_ELEMENTS, + LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS }; + static const int kElementsKindCount = + LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1; + // [properties]: Backing storage for properties. // properties is a FixedArray in the fast case and a Dictionary in the // slow case. @@ -3784,31 +3795,27 @@ class Map: public HeapObject { inline void set_is_extensible(bool value); inline bool is_extensible(); - // Tells whether the instance has fast elements. - // Equivalent to instance->GetElementsKind() == FAST_ELEMENTS. - inline void set_has_fast_elements(bool value) { - if (value) { - set_bit_field2(bit_field2() | (1 << kHasFastElements)); - } else { - set_bit_field2(bit_field2() & ~(1 << kHasFastElements)); - } + inline void set_elements_kind(JSObject::ElementsKind elements_kind) { + ASSERT(elements_kind < JSObject::kElementsKindCount); + ASSERT(JSObject::kElementsKindCount <= (1 << kElementsKindBitCount)); + set_bit_field2((bit_field2() & ~kElementsKindMask) | + (elements_kind << kElementsKindShift)); + ASSERT(this->elements_kind() == elements_kind); } - inline bool has_fast_elements() { - return ((1 << kHasFastElements) & bit_field2()) != 0; + inline JSObject::ElementsKind elements_kind() { + return static_cast( + (bit_field2() & kElementsKindMask) >> kElementsKindShift); } - // Tells whether an instance has pixel array elements. - inline void set_has_external_array_elements(bool value) { - if (value) { - set_bit_field2(bit_field2() | (1 << kHasExternalArrayElements)); - } else { - set_bit_field2(bit_field2() & ~(1 << kHasExternalArrayElements)); - } + inline bool has_fast_elements() { + return elements_kind() == JSObject::FAST_ELEMENTS; } inline bool has_external_array_elements() { - return ((1 << kHasExternalArrayElements) & bit_field2()) != 0; + JSObject::ElementsKind kind(elements_kind()); + return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + kind <= JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND; } // Tells whether the map is attached to SharedFunctionInfo @@ -4029,13 +4036,21 @@ class Map: public HeapObject { // Bit positions for bit field 2 static const int kIsExtensible = 0; static const int kFunctionWithPrototype = 1; - static const int kHasFastElements = 2; - static const int kStringWrapperSafeForDefaultValueOf = 3; - static const int kAttachedToSharedFunctionInfo = 4; - static const int kHasExternalArrayElements = 5; + static const int kStringWrapperSafeForDefaultValueOf = 2; + static const int kAttachedToSharedFunctionInfo = 3; + // No bits can be used after kElementsKindFirstBit, they are all reserved for + // storing ElementKind. for anything other than storing the ElementKind. + static const int kElementsKindShift = 4; + static const int kElementsKindBitCount = 4; + + // Derived values from bit field 2 + static const int kElementsKindMask = (-1 << kElementsKindShift) & + ((1 << (kElementsKindShift + kElementsKindBitCount)) - 1); + static const int8_t kMaximumBitField2FastElementValue = static_cast( + (JSObject::FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1; // Bit positions for bit field 3 - static const int kIsShared = 1; + static const int kIsShared = 0; // Layout of the default cache. It holds alternating name and code objects. static const int kCodeCacheEntrySize = 2; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 1988cce..e9ce311 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -3333,9 +3333,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList* args) { __ j(not_equal, &bailout); // Check that the array has fast elements. - __ testb(FieldOperand(scratch, Map::kBitField2Offset), - Immediate(1 << Map::kHasFastElements)); - __ j(zero, &bailout); + __ CheckFastElements(scratch, &bailout); // Array has fast elements, so its length must be a smi. // If the array has length zero, return the empty string. diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 032a3f7..91f44f6 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -508,11 +508,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { GenerateKeyedLoadReceiverCheck( masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow); - // Check the "has fast elements" bit in the receiver's map which is - // now in rcx. - __ testb(FieldOperand(rcx, Map::kBitField2Offset), - Immediate(1 << Map::kHasFastElements)); - __ j(zero, &check_number_dictionary); + // Check the receiver's map to see if it has fast elements. + __ CheckFastElements(rcx, &check_number_dictionary); GenerateFastArrayLoad(masm, rdx, diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 2d28579..0fc7502 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -2558,6 +2558,16 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { } +void MacroAssembler::CheckFastElements(Register map, + Label* fail, + Label::Distance distance) { + STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); + cmpb(FieldOperand(map, Map::kBitField2Offset), + Immediate(Map::kMaximumBitField2FastElementValue)); + j(above, fail, distance); +} + + void MacroAssembler::CheckMap(Register obj, Handle map, Label* fail, diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 16f6d8d..f09fafc 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -754,6 +754,12 @@ class MacroAssembler: public Assembler { // Always use unsigned comparisons: above and below, not less and greater. void CmpInstanceType(Register map, InstanceType type); + // Check if a map for a JSObject indicates that the object has fast elements. + // Jump to the specified label if it does not. + void CheckFastElements(Register map, + Label* fail, + Label::Distance distance = Label::kFar); + // Check if the map of an object is equal to a specified map and // branch to label if not. Skip the smi check if not required // (object is known to be a heap object) -- 2.7.4