Revision: 4941
Author: [email protected]
Date: Thu Jun 24 06:56:35 2010
Log: Add "has fast elements" bit to maps and use it in inlined keyed loads.

A potential issue with this change is creating lots of maps when
objects flip between fast/slow elements modes.  We could add special
transitions to avoid this.  Yet testing this on our benchmarks, gmail,
and wave seems to indicate that this is not a real problem.

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

Modified:
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/ic-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/builtins.cc
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/objects-debug.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/api.cc  Fri Jun 18 03:52:59 2010
+++ /branches/bleeding_edge/src/api.cc  Thu Jun 24 06:56:35 2010
@@ -2606,6 +2606,8 @@
     return;
   }
i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
+  self->set_map(
+      *i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map())));
   self->set_elements(*pixels);
 }

@@ -2659,6 +2661,8 @@
   }
   i::Handle<i::ExternalArray> array =
       i::Factory::NewExternalArray(length, array_type, data);
+  self->set_map(
+      *i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map())));
   self->set_elements(*array);
 }

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Tue Jun 22 03:07:57 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Thu Jun 24 06:56:35 2010
@@ -1110,6 +1110,7 @@
   void EndBlockConstPool() {
     const_pool_blocked_nesting_--;
   }
+ bool is_const_pool_blocked() const { return const_pool_blocked_nesting_
0; }

  private:
   // Code buffer:
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Jun 24 04:05:38 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Jun 24 06:56:35 2010
@@ -6123,10 +6123,12 @@
       // Get the elements array from the receiver and check that it
       // is not a dictionary.
__ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
-      __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset));
-      __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
-      __ cmp(scratch2, ip);
-      deferred->Branch(ne);
+      if (FLAG_debug_code) {
+        __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset));
+        __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
+        __ cmp(scratch2, ip);
+        __ Assert(eq, "JSObject with fast elements map has slow elements");
+      }

       // Check that key is within bounds. Use unsigned comparison to handle
       // negative keys.
@@ -6147,7 +6149,7 @@

       __ mov(r0, scratch1);
       // Make sure that the expected number of instructions are generated.
-      ASSERT_EQ(kInlinedKeyedLoadInstructionsAfterPatch,
+      ASSERT_EQ(GetInlinedKeyedLoadInstructionsAfterPatch(),
masm_->InstructionsGeneratedSince(&check_inlined_codesize));
     }

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Thu Jun 17 14:51:51 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Thu Jun 24 06:56:35 2010
@@ -276,7 +276,9 @@
   static int InlineRuntimeCallArgumentsCount(Handle<String> name);

   // Constants related to patching of inlined load/store.
-  static const int kInlinedKeyedLoadInstructionsAfterPatch = 17;
+  static int GetInlinedKeyedLoadInstructionsAfterPatch() {
+    return FLAG_debug_code ? 27 : 13;
+  }
   static const int kInlinedKeyedStoreInstructionsAfterPatch = 5;

  private:
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc   Wed Jun 23 02:10:21 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc   Thu Jun 24 06:56:35 2010
@@ -930,7 +930,7 @@
   // Patch the map check.
   Address ldr_map_instr_address =
       inline_end_address -
-      (CodeGenerator::kInlinedKeyedLoadInstructionsAfterPatch *
+      (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
       Assembler::kInstrSize);
   Assembler::set_target_address_at(ldr_map_instr_address,
                                    reinterpret_cast<Address>(map));
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jun 17 14:51:51 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jun 24 06:56:35 2010
@@ -1548,6 +1548,8 @@


 void MacroAssembler::Abort(const char* msg) {
+  Label abort_start;
+  bind(&abort_start);
   // We want to pass the msg string like a smi to avoid GC
   // problems, however msg is not guaranteed to be aligned
   // properly. Instead, we pass an aligned pointer that is
@@ -1571,6 +1573,17 @@
   push(r0);
   CallRuntime(Runtime::kAbort, 2);
   // will not return here
+  if (is_const_pool_blocked()) {
+    // If the calling code cares about the exact number of
+    // instructions generated, we insert padding here to keep the size
+    // of the Abort macro constant.
+    static const int kExpectedAbortInstructions = 10;
+    int abort_instructions = InstructionsGeneratedSince(&abort_start);
+    ASSERT(abort_instructions <= kExpectedAbortInstructions);
+    while (abort_instructions++ < kExpectedAbortInstructions) {
+      nop();
+    }
+  }
 }


=======================================
--- /branches/bleeding_edge/src/builtins.cc     Tue Jun  8 05:04:49 2010
+++ /branches/bleeding_edge/src/builtins.cc     Thu Jun 24 06:56:35 2010
@@ -195,6 +195,7 @@
   }

   // 'array' now contains the JSArray we should initialize.
+  ASSERT(array->HasFastElements());

   // Optimize the case where there is one argument and the argument is a
   // small smi.
=======================================
--- /branches/bleeding_edge/src/factory.cc      Wed Apr 28 05:05:40 2010
+++ /branches/bleeding_edge/src/factory.cc      Thu Jun 24 06:56:35 2010
@@ -273,10 +273,21 @@
   copy->set_instance_size(copy->instance_size() + instance_size_delta);
   return copy;
 }
+

 Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
   CALL_HEAP_FUNCTION(src->CopyDropTransitions(), Map);
 }
+
+
+Handle<Map> Factory::GetFastElementsMap(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(src->GetFastElementsMap(), Map);
+}
+
+
+Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(src->GetSlowElementsMap(), Map);
+}


 Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
=======================================
--- /branches/bleeding_edge/src/factory.h       Wed Apr 28 05:05:40 2010
+++ /branches/bleeding_edge/src/factory.h       Thu Jun 24 06:56:35 2010
@@ -180,6 +180,10 @@

   static Handle<Map> CopyMapDropTransitions(Handle<Map> map);

+  static Handle<Map> GetFastElementsMap(Handle<Map> map);
+
+  static Handle<Map> GetSlowElementsMap(Handle<Map> map);
+
   static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);

   // Numbers (eg, literals) are pretenured by the parser.
=======================================
--- /branches/bleeding_edge/src/heap.cc Thu Jun 24 05:11:24 2010
+++ /branches/bleeding_edge/src/heap.cc Thu Jun 24 06:56:35 2010
@@ -1283,7 +1283,7 @@
   map->set_code_cache(empty_fixed_array());
   map->set_unused_property_fields(0);
   map->set_bit_field(0);
-  map->set_bit_field2(1 << Map::kIsExtensible);
+ map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements));

   // If the map object is aligned fill the padding area with Smi 0 objects.
   if (Map::kPadStart < Map::kSize) {
@@ -2611,6 +2611,7 @@
   map->set_inobject_properties(in_object_properties);
   map->set_unused_property_fields(in_object_properties);
   map->set_prototype(prototype);
+  ASSERT(map->has_fast_elements());

   // If the function has only simple this property assignments add
   // field descriptors for these to the initial map as the object
@@ -2664,8 +2665,8 @@
   // properly initialized.
   ASSERT(map->instance_type() != JS_FUNCTION_TYPE);

-  // Both types of globla objects should be allocated using
-  // AllocateGloblaObject to be properly initialized.
+  // Both types of global objects should be allocated using
+  // AllocateGlobalObject to be properly initialized.
   ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
   ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);

@@ -2689,6 +2690,7 @@
   InitializeJSObjectFromMap(JSObject::cast(obj),
                             FixedArray::cast(properties),
                             map);
+  ASSERT(JSObject::cast(obj)->HasFastElements());
   return obj;
 }

=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Jun 17 09:19:28 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Jun 24 06:56:35 2010
@@ -8853,7 +8853,7 @@
     // Use masm-> here instead of the double underscore macro since extra
     // coverage code can interfere with the patching.
     masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
-              Immediate(Factory::null_value()));
+               Immediate(Factory::null_value()));
     deferred->Branch(not_equal);

     // Check that the key is a smi.
@@ -8868,9 +8868,11 @@
     // is not a dictionary.
     __ mov(elements.reg(),
            FieldOperand(receiver.reg(), JSObject::kElementsOffset));
-    __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
-           Immediate(Factory::fixed_array_map()));
-    deferred->Branch(not_equal);
+    if (FLAG_debug_code) {
+      __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
+             Immediate(Factory::fixed_array_map()));
+ __ Assert(equal, "JSObject with fast elements map has slow elements");
+    }

     // Check that the key is within bounds.
     __ cmp(key.reg(),
=======================================
--- /branches/bleeding_edge/src/ic.cc   Tue Jun 22 05:12:32 2010
+++ /branches/bleeding_edge/src/ic.cc   Thu Jun 24 06:56:35 2010
@@ -992,12 +992,14 @@
       }
     }
     set_target(stub);
-    // For JSObjects that are not value wrappers and that do not have
-    // indexed interceptors, we initialize the inlined fast case (if
-    // present) by patching the inlined map check.
+    // For JSObjects with fast elements that are not value wrappers
+    // and that do not have indexed interceptors, we initialize the
+    // inlined fast case (if present) by patching the inlined map
+    // check.
     if (object->IsJSObject() &&
         !object->IsJSValue() &&
-        !JSObject::cast(*object)->HasIndexedInterceptor()) {
+        !JSObject::cast(*object)->HasIndexedInterceptor() &&
+        JSObject::cast(*object)->HasFastElements()) {
       Map* map = JSObject::cast(*object)->map();
       PatchInlinedLoad(address(), map);
     }
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc        Thu Jun 17 09:19:28 2010
+++ /branches/bleeding_edge/src/objects-debug.cc        Thu Jun 24 06:56:35 2010
@@ -539,6 +539,9 @@
              (map()->inobject_properties() + properties()->length() -
               map()->NextFreePropertyIndex()));
   }
+  ASSERT(map()->has_fast_elements() ==
+         (elements()->map() == Heap::fixed_array_map()));
+  ASSERT(map()->has_fast_elements() == HasFastElements());
 }


=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Thu Jun 17 09:19:28 2010
+++ /branches/bleeding_edge/src/objects-inl.h   Thu Jun 24 06:56:35 2010
@@ -1166,6 +1166,8 @@


 void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
+  ASSERT(map()->has_fast_elements() ==
+         (value->map() == Heap::fixed_array_map()));
   // In the assert below Dictionary is covered under FixedArray.
   ASSERT(value->IsFixedArray() || value->IsPixelArray() ||
          value->IsExternalArray());
@@ -1181,9 +1183,19 @@


 void JSObject::initialize_elements() {
+  ASSERT(map()->has_fast_elements());
   ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
   WRITE_FIELD(this, kElementsOffset, Heap::empty_fixed_array());
 }
+
+
+Object* JSObject::ResetElements() {
+  Object* obj = map()->GetFastElementsMap();
+  if (obj->IsFailure()) return obj;
+  set_map(Map::cast(obj));
+  initialize_elements();
+  return this;
+}


 ACCESSORS(Oddball, to_string, String, kToStringOffset)
@@ -2333,6 +2345,26 @@
   WRITE_FIELD(this, kPrototypeOffset, value);
   CONDITIONAL_WRITE_BARRIER(this, kPrototypeOffset, mode);
 }
+
+
+Object* Map::GetFastElementsMap() {
+  if (has_fast_elements()) return this;
+  Object* obj = CopyDropTransitions();
+  if (obj->IsFailure()) return obj;
+  Map* new_map = Map::cast(obj);
+  new_map->set_has_fast_elements(true);
+  return new_map;
+}
+
+
+Object* Map::GetSlowElementsMap() {
+  if (!has_fast_elements()) return this;
+  Object* obj = CopyDropTransitions();
+  if (obj->IsFailure()) return obj;
+  Map* new_map = Map::cast(obj);
+  new_map->set_has_fast_elements(false);
+  return new_map;
+}


 ACCESSORS(Map, instance_descriptors, DescriptorArray,
@@ -2838,11 +2870,14 @@
   if (array->IsFixedArray()) {
// FAST_ELEMENTS or DICTIONARY_ELEMENTS are both stored in a FixedArray.
     if (array->map() == Heap::fixed_array_map()) {
+      ASSERT(map()->has_fast_elements());
       return FAST_ELEMENTS;
     }
     ASSERT(array->IsDictionary());
+    ASSERT(!map()->has_fast_elements());
     return DICTIONARY_ELEMENTS;
   }
+  ASSERT(!map()->has_fast_elements());
   if (array->IsExternalArray()) {
     switch (array->map()->instance_type()) {
       case EXTERNAL_BYTE_ARRAY_TYPE:
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Jun 21 13:52:43 2010
+++ /branches/bleeding_edge/src/objects.cc      Thu Jun 24 06:56:35 2010
@@ -2222,6 +2222,11 @@
 Object* JSObject::NormalizeElements() {
   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
   if (HasDictionaryElements()) return this;
+  ASSERT(map()->has_fast_elements());
+
+  Object* obj = map()->GetSlowElementsMap();
+  if (obj->IsFailure()) return obj;
+  Map* new_map = Map::cast(obj);

   // Get number of entries.
   FixedArray* array = FixedArray::cast(elements());
@@ -2230,7 +2235,7 @@
   int length = IsJSArray() ?
                Smi::cast(JSArray::cast(this)->length())->value() :
                array->length();
-  Object* obj = NumberDictionary::Allocate(length);
+  obj = NumberDictionary::Allocate(length);
   if (obj->IsFailure()) return obj;
   NumberDictionary* dictionary = NumberDictionary::cast(obj);
   // Copy entries.
@@ -2243,7 +2248,10 @@
       dictionary = NumberDictionary::cast(result);
     }
   }
-  // Switch to using the dictionary as the backing storage for elements.
+  // Switch to using the dictionary as the backing storage for
+  // elements. Set the new map first to satify the elements type
+  // assert in set_elements().
+  set_map(new_map);
   set_elements(dictionary);

   Counters::elements_to_dictionary.Increment();
@@ -5473,14 +5481,18 @@
 #endif  // ENABLE_DISASSEMBLER


-void JSObject::SetFastElements(FixedArray* elems) {
+Object* JSObject::SetFastElementsCapacityAndLength(int capacity, int length) {
   // We should never end in here with a pixel or external array.
   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
-#ifdef DEBUG
-  // Check the provided array is filled with the_hole.
-  uint32_t len = static_cast<uint32_t>(elems->length());
-  for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole());
-#endif
+
+  Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+  if (obj->IsFailure()) return obj;
+  FixedArray* elems = FixedArray::cast(obj);
+
+  obj = map()->GetFastElementsMap();
+  if (obj->IsFailure()) return obj;
+  Map* new_map = Map::cast(obj);
+
   AssertNoAllocation no_gc;
   WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
   switch (GetElementsKind()) {
@@ -5508,7 +5520,15 @@
       UNREACHABLE();
       break;
   }
+
+  set_map(new_map);
   set_elements(elems);
+
+  if (IsJSArray()) {
+    JSArray::cast(this)->set_length(Smi::FromInt(length));
+  }
+
+  return this;
 }


@@ -5595,7 +5615,7 @@

   Object* smi_length = len->ToSmi();
   if (smi_length->IsSmi()) {
-    int value = Smi::cast(smi_length)->value();
+    const int value = Smi::cast(smi_length)->value();
     if (value < 0) return ArrayLengthRangeError();
     switch (GetElementsKind()) {
       case FAST_ELEMENTS: {
@@ -5617,12 +5637,8 @@
         int new_capacity = value > min ? value : min;
         if (new_capacity <= kMaxFastElementsLength ||
             !ShouldConvertToSlowElements(new_capacity)) {
-          Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
+ Object* obj = SetFastElementsCapacityAndLength(new_capacity, value);
           if (obj->IsFailure()) return obj;
-          if (IsJSArray()) {
-            JSArray::cast(this)->set_length(Smi::cast(smi_length));
-          }
-          SetFastElements(FixedArray::cast(obj));
           return this;
         }
         break;
@@ -5633,7 +5649,8 @@
             // If the length of a slow array is reset to zero, we clear
             // the array and flush backing storage. This has the added
             // benefit that the array returns to fast mode.
-            initialize_elements();
+            Object* obj = ResetElements();
+            if (obj->IsFailure()) return obj;
           } else {
             // Remove deleted elements.
             uint32_t old_length =
@@ -6092,12 +6109,8 @@
     if (new_capacity <= kMaxFastElementsLength ||
         !ShouldConvertToSlowElements(new_capacity)) {
       ASSERT(static_cast<uint32_t>(new_capacity) > index);
-      Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
+ Object* obj = SetFastElementsCapacityAndLength(new_capacity, index + 1);
       if (obj->IsFailure()) return obj;
-      SetFastElements(FixedArray::cast(obj));
-      if (IsJSArray()) {
-        JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
-      }
       FixedArray::cast(elements())->set(index, value);
       return value;
     }
@@ -6216,13 +6229,11 @@
         uint32_t new_length = 0;
         if (IsJSArray()) {
           CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
-          JSArray::cast(this)->set_length(Smi::FromInt(new_length));
         } else {
new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
         }
-        Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
+ Object* obj = SetFastElementsCapacityAndLength(new_length, new_length);
         if (obj->IsFailure()) return obj;
-        SetFastElements(FixedArray::cast(obj));
 #ifdef DEBUG
         if (FLAG_trace_normalization) {
           PrintF("Object elements are fast case again:\n");
@@ -7526,14 +7537,18 @@
     }
     // Convert to fast elements.

+    Object* obj = map()->GetFastElementsMap();
+    if (obj->IsFailure()) return obj;
+    Map* new_map = Map::cast(obj);
+
     PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED;
     Object* new_array =
         Heap::AllocateFixedArray(dict->NumberOfElements(), tenure);
-    if (new_array->IsFailure()) {
-      return new_array;
-    }
+    if (new_array->IsFailure()) return new_array;
     FixedArray* fast_elements = FixedArray::cast(new_array);
     dict->CopyValuesTo(fast_elements);
+
+    set_map(new_map);
     set_elements(fast_elements);
   }
   ASSERT(HasFastElements());
=======================================
--- /branches/bleeding_edge/src/objects.h       Fri Jun 18 03:52:59 2010
+++ /branches/bleeding_edge/src/objects.h       Thu Jun 24 06:56:35 2010
@@ -1191,6 +1191,7 @@
   // case, and a PixelArray or ExternalArray in special cases.
   DECL_ACCESSORS(elements, HeapObject)
   inline void initialize_elements();
+  inline Object* ResetElements();
   inline ElementsKind GetElementsKind();
   inline bool HasFastElements();
   inline bool HasDictionaryElements();
@@ -1367,7 +1368,7 @@
   // The undefined object if index is out of bounds.
   Object* GetElementWithReceiver(JSObject* receiver, uint32_t index);

-  void SetFastElements(FixedArray* elements);
+  Object* SetFastElementsCapacityAndLength(int capacity, int length);
   Object* SetSlowElements(Object* length);

// Lookup interceptors are used for handling properties controlled by host
@@ -2986,6 +2987,19 @@
   inline bool is_extensible() {
     return ((1 << kIsExtensible) & bit_field2()) != 0;
   }
+
+  // Tells whether the instance has fast elements.
+  void set_has_fast_elements(bool value) {
+    if (value) {
+      set_bit_field2(bit_field2() | (1 << kHasFastElements));
+    } else {
+      set_bit_field2(bit_field2() & ~(1 << kHasFastElements));
+    }
+  }
+
+  bool has_fast_elements() {
+    return ((1 << kHasFastElements) & bit_field2()) != 0;
+  }

   // Tells whether the instance needs security checks when accessing its
   // properties.
@@ -3010,6 +3024,16 @@
   // instance descriptors.
   Object* CopyDropTransitions();

+  // Returns this map if it has the fast elements bit set, otherwise
+  // returns a copy of the map, with all transitions dropped from the
+  // descriptors and the fast elements bit set.
+  inline Object* GetFastElementsMap();
+
+  // Returns this map if it has the fast elements bit cleared,
+  // otherwise returns a copy of the map, with all transitions dropped
+  // from the descriptors and the fast elements bit cleared.
+  inline Object* GetSlowElementsMap();
+
   // Returns the property index for name (only valid for FAST MODE).
   int PropertyIndexFor(String* name);

@@ -3111,6 +3135,7 @@
   // Bit positions for bit field 2
   static const int kIsExtensible = 0;
   static const int kFunctionWithPrototype = 1;
+  static const int kHasFastElements = 2;

// Layout of the default cache. It holds alternating name and code objects.
   static const int kCodeCacheEntrySize = 2;
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Jun 17 09:19:28 2010
+++ /branches/bleeding_edge/src/runtime.cc      Thu Jun 24 06:56:35 2010
@@ -7449,7 +7449,7 @@
   uint32_t index_limit_;
// Index after last seen index. Always less than or equal to index_limit_.
   uint32_t index_offset_;
-  bool fast_elements_;
+  const bool fast_elements_;
 };


@@ -7766,13 +7766,14 @@
     // The backing storage array must have non-existing elements to
     // preserve holes across concat operations.
     storage = Factory::NewFixedArrayWithHoles(result_length);
-
+ result->set_map(*Factory::GetFastElementsMap(Handle<Map>(result->map())));
   } else {
     // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
     uint32_t at_least_space_for = estimate_nof_elements +
                                   (estimate_nof_elements >> 2);
     storage = Handle<FixedArray>::cast(
                   Factory::NewNumberDictionary(at_least_space_for));
+ result->set_map(*Factory::GetSlowElementsMap(Handle<Map>(result->map())));
   }

Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
@@ -7822,9 +7823,19 @@
   ASSERT(args.length() == 2);
   CONVERT_CHECKED(JSArray, from, args[0]);
   CONVERT_CHECKED(JSArray, to, args[1]);
-  to->SetContent(FixedArray::cast(from->elements()));
+  HeapObject* new_elements = from->elements();
+  Object* new_map;
+  if (new_elements->map() == Heap::fixed_array_map()) {
+    new_map = to->map()->GetFastElementsMap();
+  } else {
+    new_map = to->map()->GetSlowElementsMap();
+  }
+  if (new_map->IsFailure()) return new_map;
+  to->set_map(Map::cast(new_map));
+  to->set_elements(new_elements);
   to->set_length(from->length());
-  from->SetContent(Heap::empty_fixed_array());
+  Object* obj = from->ResetElements();
+  if (obj->IsFailure()) return obj;
   from->set_length(Smi::FromInt(0));
   return to;
 }
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Jun 24 02:03:49 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Jun 24 06:56:35 2010
@@ -7529,9 +7529,11 @@
     // is not a dictionary.
     __ movq(elements.reg(),
             FieldOperand(receiver.reg(), JSObject::kElementsOffset));
-    __ Cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
-           Factory::fixed_array_map());
-    deferred->Branch(not_equal);
+    if (FLAG_debug_code) {
+      __ Cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
+             Factory::fixed_array_map());
+ __ Assert(equal, "JSObject with fast elements map has slow elements");
+    }

     // Check that key is within bounds.
     __ SmiCompare(key.reg(),

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

Reply via email to