Revision: 8162
Author:   [email protected]
Date:     Fri Jun  3 00:41:37 2011
Log: Add complete ElementsKind information directly to Map for objects with elements.

Review URL: http://codereview.chromium.org/6966041
http://code.google.com/p/v8/source/detail?r=8162

Modified:
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/ic-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/ic-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/ic-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue May 31 09:38:40 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Jun 3 00:41:37 2011
@@ -3436,9 +3436,7 @@
   __ 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));
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc   Tue May 31 09:38:40 2011
+++ /branches/bleeding_edge/src/arm/ic-arm.cc   Fri Jun  3 00:41:37 2011
@@ -944,11 +944,8 @@
   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);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue May 31 09:38:40 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Jun 3 00:41:37 2011
@@ -1675,6 +1675,16 @@
   LoadRoot(ip, index);
   cmp(obj, ip);
 }
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue May 31 08:21:25 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Jun 3 00:41:37 2011
@@ -577,6 +577,12 @@
                            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
=======================================
--- /branches/bleeding_edge/src/heap.cc Wed Jun  1 05:24:55 2011
+++ /branches/bleeding_edge/src/heap.cc Fri Jun  3 00:41:37 2011
@@ -1636,7 +1636,8 @@
   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) {
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue May 31 09:38:40 2011 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Jun 3 00:41:37 2011
@@ -3374,9 +3374,7 @@
   __ 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));
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Tue May 31 09:38:40 2011
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Fri Jun  3 00:41:37 2011
@@ -484,11 +484,8 @@
   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,
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue May 31 09:38:40 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Jun 3 00:41:37 2011
@@ -277,6 +277,16 @@
   cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
        static_cast<int8_t>(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,
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue May 31 08:21:25 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Fri Jun 3 00:41:37 2011
@@ -216,6 +216,12 @@
   // 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)
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Thu Jun  2 03:12:00 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Fri Jun  3 00:41:37 2011
@@ -2974,7 +2974,7 @@
     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 @@
     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 @@


 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;
 }


=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Jun  2 03:12:00 2011
+++ /branches/bleeding_edge/src/objects.cc      Fri Jun  3 00:41:37 2011
@@ -1939,6 +1939,42 @@
     result->NotFound();
   }
 }
+
+
+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,
@@ -1983,8 +2019,7 @@
   }
   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
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue May 31 09:38:40 2011
+++ /branches/bleeding_edge/src/objects.h       Fri Jun  3 00:41:37 2011
@@ -1420,10 +1420,12 @@
   };

   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 @@
     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 @@
   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<JSObject::ElementsKind>(
+        (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 @@
   // 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<int8_t>(
+      (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;
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue May 31 09:38:40 2011 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Jun 3 00:41:37 2011
@@ -3333,9 +3333,7 @@
   __ 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.
=======================================
--- /branches/bleeding_edge/src/x64/ic-x64.cc   Tue May 31 09:38:40 2011
+++ /branches/bleeding_edge/src/x64/ic-x64.cc   Fri Jun  3 00:41:37 2011
@@ -508,11 +508,8 @@
   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,
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue May 31 08:21:25 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Fri Jun 3 00:41:37 2011
@@ -2556,6 +2556,16 @@
   cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
        Immediate(static_cast<int8_t>(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,
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue May 31 08:21:25 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Fri Jun 3 00:41:37 2011
@@ -754,6 +754,12 @@
// 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)

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to