Revision: 10314
Author:   [email protected]
Date:     Mon Jan  2 01:26:59 2012
Log:      Version 3.8.4

Performance improvements for large Smi-only arrays.

Fixed InternalArrays construction. (issue 1878)
http://code.google.com/p/v8/source/detail?r=10314

Added:
 /trunk/test/mjsunit/regress/regress-1849.js
 /trunk/test/mjsunit/regress/regress-1878.js
Modified:
 /trunk/ChangeLog
 /trunk/src/arm/builtins-arm.cc
 /trunk/src/ast.cc
 /trunk/src/bootstrapper.cc
 /trunk/src/builtins.cc
 /trunk/src/builtins.h
 /trunk/src/contexts.h
 /trunk/src/ia32/builtins-ia32.cc
 /trunk/src/objects-inl.h
 /trunk/src/objects.cc
 /trunk/src/objects.h
 /trunk/src/runtime.cc
 /trunk/src/runtime.h
 /trunk/src/version.cc
 /trunk/src/x64/builtins-x64.cc
 /trunk/test/mjsunit/regress/regress-95113.js

=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-1849.js Mon Jan  2 01:26:59 2012
@@ -0,0 +1,39 @@
+// 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:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See: http://code.google.com/p/v8/issues/detail?id=1878
+
+// Flags: --allow-natives-syntax
+
+var count = 1e5;
+var arr = new Array(count);
+assertFalse(%HasFastDoubleElements(arr));
+for (var i = 0; i < count; i++) {
+  arr[i] = 0;
+}
+assertFalse(%HasFastDoubleElements(arr));
+assertTrue(%HasFastSmiOnlyElements(arr));
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-1878.js Mon Jan  2 01:26:59 2012
@@ -0,0 +1,34 @@
+// Copyright 2009 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:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See: http://code.google.com/p/v8/issues/detail?id=1878
+
+// Flags: --allow-natives-syntax --expose_natives_as=natives
+
+var a = Array();
+var ai = natives.InternalArray();
+assertFalse(%HaveSameMap(ai, a));
=======================================
--- /trunk/ChangeLog    Tue Dec 27 02:09:42 2011
+++ /trunk/ChangeLog    Mon Jan  2 01:26:59 2012
@@ -1,3 +1,10 @@
+2012-01-02: Version 3.8.4
+
+        Performance improvements for large Smi-only arrays.
+
+        Fixed InternalArrays construction. (issue 1878)
+
+
 2011-12-27: Version 3.8.3

Avoid embedding new space objects into code objects in the lithium gap
=======================================
--- /trunk/src/arm/builtins-arm.cc      Tue Dec 13 00:07:27 2011
+++ /trunk/src/arm/builtins-arm.cc      Mon Jan  2 01:26:59 2012
@@ -70,6 +70,22 @@
   __ add(r0, r0, Operand(num_extra_args + 1));
   __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
 }
+
+
+// Load the built-in InternalArray function from the current context.
+static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
+                                              Register result) {
+  // Load the global context.
+
+ __ ldr(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  __ ldr(result,
+         FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
+  // Load the InternalArray function from the global context.
+  __ ldr(result,
+         MemOperand(result,
+                    Context::SlotOffset(
+                        Context::INTERNAL_ARRAY_FUNCTION_INDEX)));
+}


 // Load the built-in Array function from the current context.
@@ -416,6 +432,40 @@
   __ mov(r0, r3);
   __ Jump(lr);
 }
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r0     : number of arguments
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+  // Get the InternalArray function.
+  GenerateLoadInternalArrayFunction(masm, r1);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin InternalArray functions should be maps.
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
+    __ tst(r2, Operand(kSmiTagMask));
+    __ Assert(ne, "Unexpected initial map for InternalArray function");
+    __ CompareObjectType(r2, r3, r4, MAP_TYPE);
+    __ Assert(eq, "Unexpected initial map for InternalArray function");
+  }
+
+  // Run the native code for the InternalArray function called as a normal
+  // function.
+  ArrayNativeCode(masm, &generic_array_code);
+
+ // Jump to the generic array code if the specialized code cannot handle the
+  // construction.
+  __ bind(&generic_array_code);
+
+  Handle<Code> array_code =
+      masm->isolate()->builtins()->InternalArrayCodeGeneric();
+  __ Jump(array_code, RelocInfo::CODE_TARGET);
+}


 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
=======================================
--- /trunk/src/ast.cc   Tue Dec 13 00:07:27 2011
+++ /trunk/src/ast.cc   Mon Jan  2 01:26:59 2012
@@ -748,7 +748,8 @@
     type->LookupInDescriptors(NULL, *name, &lookup);
     // If the function wasn't found directly in the map, we start
     // looking upwards through the prototype chain.
-    if (!lookup.IsFound() && type->prototype()->IsJSObject()) {
+    if ((!lookup.IsFound() || IsTransitionType(lookup.type()))
+        && type->prototype()->IsJSObject()) {
       holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
       type = Handle<Map>(holder()->map());
     } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) {
=======================================
--- /trunk/src/bootstrapper.cc  Tue Dec 13 00:07:27 2011
+++ /trunk/src/bootstrapper.cc  Mon Jan  2 01:26:59 2012
@@ -1613,16 +1613,13 @@
     // doesn't inherit from Object.prototype.
     // To be used only for internal work by builtins. Instances
     // must not be leaked to user code.
-    // Only works correctly when called as a constructor. The normal
-    // Array code uses Array.prototype as prototype when called as
-    // a function.
     Handle<JSFunction> array_function =
         InstallFunction(builtins,
                         "InternalArray",
                         JS_ARRAY_TYPE,
                         JSArray::kSize,
                         isolate()->initial_object_prototype(),
-                        Builtins::kArrayCode,
+                        Builtins::kInternalArrayCode,
                         true);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
@@ -1654,6 +1651,8 @@

     array_function->initial_map()->set_instance_descriptors(
         *array_descriptors);
+
+    global_context()->set_internal_array_function(*array_function);
   }

   if (FLAG_disable_native_files) {
=======================================
--- /trunk/src/builtins.cc      Tue Dec 13 00:07:27 2011
+++ /trunk/src/builtins.cc      Mon Jan  2 01:26:59 2012
@@ -184,31 +184,28 @@
 }


-BUILTIN(ArrayCodeGeneric) {
+static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
+                                           Isolate* isolate,
+                                           JSFunction* constructor) {
   Heap* heap = isolate->heap();
   isolate->counters()->array_function_runtime()->Increment();

   JSArray* array;
   if (CalledAsConstructor(isolate)) {
-    array = JSArray::cast(*args.receiver());
+    array = JSArray::cast((*args)[0]);
   } else {
     // Allocate the JS Array
-    JSFunction* constructor =
-        isolate->context()->global_context()->array_function();
     Object* obj;
     { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
     }
     array = JSArray::cast(obj);
   }
-
-  // 'array' now contains the JSArray we should initialize.
-  ASSERT(array->HasFastTypeElements());

   // Optimize the case where there is one argument and the argument is a
   // small smi.
-  if (args.length() == 2) {
-    Object* obj = args[1];
+  if (args->length() == 2) {
+    Object* obj = (*args)[1];
     if (obj->IsSmi()) {
       int len = Smi::cast(obj)->value();
       if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
@@ -225,18 +222,18 @@
     { MaybeObject* maybe_obj = array->Initialize(0);
       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
     }
-    return array->SetElementsLength(args[1]);
+    return array->SetElementsLength((*args)[1]);
   }

   // Optimize the case where there are no parameters passed.
-  if (args.length() == 1) {
+  if (args->length() == 1) {
     return array->Initialize(JSArray::kPreallocatedArrayElements);
   }

   // Set length and elements on the array.
-  int number_of_elements = args.length() - 1;
+  int number_of_elements = args->length() - 1;
   MaybeObject* maybe_object =
-      array->EnsureCanContainElements(&args, 1, number_of_elements,
+      array->EnsureCanContainElements(args, 1, number_of_elements,
                                       ALLOW_CONVERTED_DOUBLE_ELEMENTS);
   if (maybe_object->IsFailure()) return maybe_object;

@@ -257,7 +254,7 @@
     case FAST_SMI_ONLY_ELEMENTS: {
       FixedArray* smi_elms = FixedArray::cast(elms);
       for (int index = 0; index < number_of_elements; index++) {
-        smi_elms->set(index, args[index+1], SKIP_WRITE_BARRIER);
+        smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
       }
       break;
     }
@@ -266,14 +263,14 @@
       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
       FixedArray* object_elms = FixedArray::cast(elms);
       for (int index = 0; index < number_of_elements; index++) {
-        object_elms->set(index, args[index+1], mode);
+        object_elms->set(index, (*args)[index+1], mode);
       }
       break;
     }
     case FAST_DOUBLE_ELEMENTS: {
       FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
       for (int index = 0; index < number_of_elements; index++) {
-        double_elms->set(index, args[index+1]->Number());
+        double_elms->set(index, (*args)[index+1]->Number());
       }
       break;
     }
@@ -286,6 +283,22 @@
   array->set_length(Smi::FromInt(number_of_elements));
   return array;
 }
+
+
+BUILTIN(InternalArrayCodeGeneric) {
+  return ArrayCodeGenericCommon(
+      &args,
+      isolate,
+      isolate->context()->global_context()->internal_array_function());
+}
+
+
+BUILTIN(ArrayCodeGeneric) {
+  return ArrayCodeGenericCommon(
+      &args,
+      isolate,
+      isolate->context()->global_context()->array_function());
+}


 MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
=======================================
--- /trunk/src/builtins.h       Thu Nov 10 03:38:15 2011
+++ /trunk/src/builtins.h       Mon Jan  2 01:26:59 2012
@@ -44,6 +44,7 @@
                                                                     \
   V(EmptyFunction, NO_EXTRA_ARGUMENTS)                              \
                                                                     \
+  V(InternalArrayCodeGeneric, NO_EXTRA_ARGUMENTS)                   \
   V(ArrayCodeGeneric, NO_EXTRA_ARGUMENTS)                           \
                                                                     \
   V(ArrayPush, NO_EXTRA_ARGUMENTS)                                  \
@@ -178,6 +179,8 @@
   V(FunctionApply,                  BUILTIN, UNINITIALIZED,             \
                                     Code::kNoExtraICState)              \
                                                                         \
+  V(InternalArrayCode,              BUILTIN, UNINITIALIZED,             \
+                                    Code::kNoExtraICState)              \
   V(ArrayCode,                      BUILTIN, UNINITIALIZED,             \
                                     Code::kNoExtraICState)              \
   V(ArrayConstructCode,             BUILTIN, UNINITIALIZED,             \
@@ -359,6 +362,7 @@
   static void Generate_FunctionCall(MacroAssembler* masm);
   static void Generate_FunctionApply(MacroAssembler* masm);

+  static void Generate_InternalArrayCode(MacroAssembler* masm);
   static void Generate_ArrayCode(MacroAssembler* masm);
   static void Generate_ArrayConstructCode(MacroAssembler* masm);

=======================================
--- /trunk/src/contexts.h       Thu Nov 17 00:34:43 2011
+++ /trunk/src/contexts.h       Mon Jan  2 01:26:59 2012
@@ -104,6 +104,7 @@
   V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
   V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
+  V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
   V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
   V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
   V(JSON_OBJECT_INDEX, JSObject, json_object) \
@@ -244,6 +245,7 @@
     STRING_FUNCTION_INDEX,
     STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
     OBJECT_FUNCTION_INDEX,
+    INTERNAL_ARRAY_FUNCTION_INDEX,
     ARRAY_FUNCTION_INDEX,
     DATE_FUNCTION_INDEX,
     JSON_OBJECT_INDEX,
=======================================
--- /trunk/src/ia32/builtins-ia32.cc    Tue Dec 13 00:07:27 2011
+++ /trunk/src/ia32/builtins-ia32.cc    Mon Jan  2 01:26:59 2012
@@ -1306,6 +1306,40 @@
   }
   __ jmp(call_generic_code);
 }
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax : argc
+  //  -- esp[0] : return address
+  //  -- esp[4] : last argument
+  // -----------------------------------
+  Label generic_array_code;
+
+  // Get the InternalArray function.
+  __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin InternalArray function shoud be a map.
+ __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    __ test(ebx, Immediate(kSmiTagMask));
+ __ Assert(not_zero, "Unexpected initial map for InternalArray function");
+    __ CmpObjectType(ebx, MAP_TYPE, ecx);
+    __ Assert(equal, "Unexpected initial map for InternalArray function");
+  }
+
+  // Run the native code for the InternalArray function called as a normal
+  // function.
+  ArrayNativeCode(masm, false, &generic_array_code);
+
+ // Jump to the generic array code in case the specialized code cannot handle
+  // the construction.
+  __ bind(&generic_array_code);
+  Handle<Code> array_code =
+      masm->isolate()->builtins()->InternalArrayCodeGeneric();
+  __ jmp(array_code, RelocInfo::CODE_TARGET);
+}


 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
=======================================
--- /trunk/src/objects-inl.h    Mon Dec 19 04:13:11 2011
+++ /trunk/src/objects-inl.h    Mon Jan  2 01:26:59 2012
@@ -1219,7 +1219,7 @@
         map != heap->free_space_map()) {
       for (int i = 0; i < fixed_array->length(); i++) {
         Object* current = fixed_array->get(i);
-        ASSERT(current->IsSmi() || current == heap->the_hole_value());
+        ASSERT(current->IsSmi() || current->IsTheHole());
       }
     }
   }
@@ -1290,20 +1290,35 @@
 }


-void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
+void JSObject::set_map_and_elements(Map* new_map,
+                                    FixedArrayBase* value,
+                                    WriteBarrierMode mode) {
+  ASSERT(value->HasValidElements());
+#ifdef DEBUG
+  ValidateSmiOnlyElements();
+#endif
+  if (new_map != NULL) {
+    if (mode == UPDATE_WRITE_BARRIER) {
+      set_map(new_map);
+    } else {
+      ASSERT(mode == SKIP_WRITE_BARRIER);
+      set_map_no_write_barrier(new_map);
+    }
+  }
   ASSERT((map()->has_fast_elements() ||
           map()->has_fast_smi_only_elements()) ==
          (value->map() == GetHeap()->fixed_array_map() ||
           value->map() == GetHeap()->fixed_cow_array_map()));
   ASSERT(map()->has_fast_double_elements() ==
          value->IsFixedDoubleArray());
-  ASSERT(value->HasValidElements());
-#ifdef DEBUG
-  ValidateSmiOnlyElements();
-#endif
   WRITE_FIELD(this, kElementsOffset, value);
   CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, value, mode);
 }
+
+
+void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
+  set_map_and_elements(NULL, value, mode);
+}


 void JSObject::initialize_properties() {
=======================================
--- /trunk/src/objects.cc       Tue Dec 27 02:09:42 2011
+++ /trunk/src/objects.cc       Mon Jan  2 01:26:59 2012
@@ -8188,10 +8188,13 @@
   Map* new_map = NULL;
   if (elements()->map() != heap->non_strict_arguments_elements_map()) {
     Object* object;
+ // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces + // it, or if it's allowed and the old elements array contained only SMIs.
     bool has_fast_smi_only_elements =
-        (set_capacity_mode == kAllowSmiOnlyElements) &&
-        (elements()->map()->has_fast_smi_only_elements() ||
-         elements() == heap->empty_fixed_array());
+        (set_capacity_mode == kForceSmiOnlyElements) ||
+        ((set_capacity_mode == kAllowSmiOnlyElements) &&
+         (elements()->map()->has_fast_smi_only_elements() ||
+          elements() == heap->empty_fixed_array()));
     ElementsKind elements_kind = has_fast_smi_only_elements
         ? FAST_SMI_ONLY_ELEMENTS
         : FAST_ELEMENTS;
@@ -8209,8 +8212,7 @@
       WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
       CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
                              new_elements, mode);
-      set_map(new_map);
-      set_elements(new_elements);
+      set_map_and_elements(new_map, new_elements);
       break;
     }
     case DICTIONARY_ELEMENTS: {
@@ -8219,8 +8221,7 @@
       CopySlowElementsToFast(NumberDictionary::cast(old_elements_raw),
                              new_elements,
                              mode);
-      set_map(new_map);
-      set_elements(new_elements);
+      set_map_and_elements(new_map, new_elements);
       break;
     }
     case NON_STRICT_ARGUMENTS_ELEMENTS: {
@@ -9241,11 +9242,20 @@
     } else {
       new_length = dictionary->max_number_key() + 1;
     }
-    MaybeObject* result = CanConvertToFastDoubleElements()
+    SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
+        ? kAllowSmiOnlyElements
+        : kDontAllowSmiOnlyElements;
+    bool has_smi_only_elements = false;
+    bool should_convert_to_fast_double_elements =
+        ShouldConvertToFastDoubleElements(&has_smi_only_elements);
+    if (has_smi_only_elements) {
+      set_capacity_mode = kForceSmiOnlyElements;
+    }
+    MaybeObject* result = should_convert_to_fast_double_elements
         ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
         : SetFastElementsCapacityAndLength(new_length,
                                            new_length,
-                                           kDontAllowSmiOnlyElements);
+                                           set_capacity_mode);
     if (result->IsFailure()) return result;
 #ifdef DEBUG
     if (FLAG_trace_normalization) {
@@ -9724,17 +9734,25 @@
 }


-bool JSObject::CanConvertToFastDoubleElements() {
+bool JSObject::ShouldConvertToFastDoubleElements(
+    bool* has_smi_only_elements) {
+  *has_smi_only_elements = false;
   if (FLAG_unbox_double_arrays) {
     ASSERT(HasDictionaryElements());
     NumberDictionary* dictionary = NumberDictionary::cast(elements());
+    bool found_double = false;
     for (int i = 0; i < dictionary->Capacity(); i++) {
       Object* key = dictionary->KeyAt(i);
       if (key->IsNumber()) {
-        if (!dictionary->ValueAt(i)->IsNumber()) return false;
+        Object* value = dictionary->ValueAt(i);
+        if (!value->IsNumber()) return false;
+        if (!value->IsSmi()) {
+          found_double = true;
+        }
       }
     }
-    return true;
+    *has_smi_only_elements = !found_double;
+    return found_double;
   } else {
     return false;
   }
=======================================
--- /trunk/src/objects.h        Mon Dec 19 04:13:11 2011
+++ /trunk/src/objects.h        Mon Jan  2 01:26:59 2012
@@ -1473,6 +1473,11 @@
   bool HasDictionaryArgumentsElements();
   inline NumberDictionary* element_dictionary();  // Gets slow elements.

+  inline void set_map_and_elements(
+      Map* map,
+      FixedArrayBase* value,
+      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
   // Requires: HasFastElements().
   MUST_USE_RESULT inline MaybeObject* EnsureWritableFastElements();

@@ -1644,8 +1649,9 @@
   // elements.
   bool ShouldConvertToFastElements();
// Returns true if the elements of JSObject contains only values that can be
-  // represented in a FixedDoubleArray.
-  bool CanConvertToFastDoubleElements();
+ // represented in a FixedDoubleArray and has at least one value that can only
+  // be represented as a double and not a Smi.
+  bool ShouldConvertToFastDoubleElements(bool* has_smi_only_elements);

   // Tells whether the index'th element is present.
   bool HasElementWithReceiver(JSReceiver* receiver, uint32_t index);
@@ -1708,6 +1714,7 @@

   enum SetFastElementsCapacityMode {
     kAllowSmiOnlyElements,
+    kForceSmiOnlyElements,
     kDontAllowSmiOnlyElements
   };

=======================================
--- /trunk/src/runtime.cc       Wed Dec 21 00:29:34 2011
+++ /trunk/src/runtime.cc       Mon Jan  2 01:26:59 2012
@@ -9227,22 +9227,6 @@
     PrintF("\n");
   }
 }
-
-
-RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
-  ASSERT(args.length() == 5);
-  CONVERT_ARG_CHECKED(JSObject, obj, 0);
-  CONVERT_SMI_ARG_CHECKED(from_kind, 1);
-  CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
-  CONVERT_SMI_ARG_CHECKED(to_kind, 3);
-  CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
-  NoHandleAllocation ha;
-  PrintF("*");
-  obj->PrintElementsTransition(stdout,
-      static_cast<ElementsKind>(from_kind), *from_elements,
-      static_cast<ElementsKind>(to_kind), *to_elements);
-  return isolate->heap()->undefined_value();
-}


 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
=======================================
--- /trunk/src/runtime.h        Mon Dec 19 04:13:11 2011
+++ /trunk/src/runtime.h        Mon Jan  2 01:26:59 2012
@@ -341,7 +341,6 @@
   /* Debugging */ \
   F(DebugPrint, 1, 1) \
   F(DebugTrace, 0, 1) \
-  F(TraceElementsKindTransition, 5, 1) \
   F(TraceEnter, 0, 1) \
   F(TraceExit, 1, 1) \
   F(Abort, 2, 1) \
=======================================
--- /trunk/src/version.cc       Tue Dec 27 02:09:42 2011
+++ /trunk/src/version.cc       Mon Jan  2 01:26:59 2012
@@ -34,7 +34,7 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     8
-#define BUILD_NUMBER      3
+#define BUILD_NUMBER      4
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
=======================================
--- /trunk/src/x64/builtins-x64.cc      Tue Dec 13 00:07:27 2011
+++ /trunk/src/x64/builtins-x64.cc      Mon Jan  2 01:26:59 2012
@@ -1325,6 +1325,41 @@
   __ movq(rax, rbx);
   __ ret(0);
 }
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- rax : argc
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : last argument
+  // -----------------------------------
+  Label generic_array_code;
+
+  // Get the InternalArray function.
+  __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, rdi);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin InternalArray functions should be maps.
+ __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    STATIC_ASSERT(kSmiTag == 0);
+    Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
+    __ Check(not_smi, "Unexpected initial map for InternalArray function");
+    __ CmpObjectType(rbx, MAP_TYPE, rcx);
+    __ Check(equal, "Unexpected initial map for InternalArray function");
+  }
+
+  // Run the native code for the InternalArray function called as a normal
+  // function.
+  ArrayNativeCode(masm, &generic_array_code);
+
+ // Jump to the generic array code in case the specialized code cannot handle
+  // the construction.
+  __ bind(&generic_array_code);
+  Handle<Code> array_code =
+      masm->isolate()->builtins()->InternalArrayCodeGeneric();
+  __ Jump(array_code, RelocInfo::CODE_TARGET);
+}


 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
=======================================
--- /trunk/test/mjsunit/regress/regress-95113.js        Wed Sep  7 05:44:28 2011
+++ /trunk/test/mjsunit/regress/regress-95113.js        Mon Jan  2 01:26:59 2012
@@ -32,7 +32,7 @@
   var i = 0;
   while (!%HasFastDoubleElements(a)) {
     a[i] = i;
-    i++;
+    i += 0.5;
   }
   assertTrue(%HasFastDoubleElements(a));
   a.length = 1;

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

Reply via email to