Revision: 10583
Author:   [email protected]
Date:     Thu Feb  2 03:22:26 2012
Log: Handle single element array growth + transition in generic KeyedStoreIC

BUG=none
TEST=3d-cube faster

Review URL: https://chromiumcodereview.appspot.com/9235007
http://code.google.com/p/v8/source/detail?r=10583

Modified:
 /branches/bleeding_edge/src/arm/builtins-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/contexts.h
 /branches/bleeding_edge/src/ia32/builtins-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-printer.cc
 /branches/bleeding_edge/src/x64/builtins-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/builtins-arm.cc     Fri Jan 27 05:03:19 2012
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc     Thu Feb  2 03:22:26 2012
@@ -114,7 +114,7 @@
                                  Label* gc_required) {
   const int initial_capacity = JSArray::kPreallocatedArrayElements;
   STATIC_ASSERT(initial_capacity >= 0);
- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+  __ LoadInitialArrayMap(array_function, scratch2, scratch1);

// Allocate the JSArray object together with space for a fixed array with the
   // requested elements.
@@ -208,8 +208,7 @@
                             bool fill_with_hole,
                             Label* gc_required) {
   // Load the initial map from the array function.
-  __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2,
-                                          elements_array_storage);
+  __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage);

   if (FLAG_debug_code) {  // Assert that array size is not zero.
     __ tst(array_size, array_size);
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc   Mon Jan 23 08:18:10 2012
+++ /branches/bleeding_edge/src/arm/ic-arm.cc   Thu Feb  2 03:22:26 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -1312,14 +1312,16 @@
   Label slow, array, extra, check_if_double_array;
   Label fast_object_with_map_check, fast_object_without_map_check;
   Label fast_double_with_map_check, fast_double_without_map_check;
+  Label transition_smi_elements, finish_object_store, non_double_value;
+  Label transition_double_elements;

   // Register usage.
   Register value = r0;
   Register key = r1;
   Register receiver = r2;
-  Register elements = r3;  // Elements array of the receiver.
+  Register receiver_map = r3;
   Register elements_map = r6;
-  Register receiver_map = r7;
+  Register elements = r7;  // Elements array of the receiver.
   // r4 and r5 are used as general scratch registers.

   // Check that the key is a smi.
@@ -1417,9 +1419,11 @@
   __ Ret();

   __ bind(&non_smi_value);
-  // Escape to slow case when writing non-smi into smi-only array.
-  __ CheckFastObjectElements(receiver_map, scratch_value, &slow);
+  // Escape to elements kind transition case.
+  __ CheckFastObjectElements(receiver_map, scratch_value,
+                             &transition_smi_elements);
   // Fast elements array, store the value to the elements backing store.
+  __ bind(&finish_object_store);
__ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
   __ str(value, MemOperand(address));
@@ -1445,12 +1449,56 @@
                                  key,
                                  receiver,
                                  elements,
+                                 r3,
                                  r4,
                                  r5,
                                  r6,
-                                 r7,
-                                 &slow);
+                                 &transition_double_elements);
   __ Ret();
+
+  __ bind(&transition_smi_elements);
+  // Transition the array appropriately depending on the value type.
+  __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
+  __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
+  __ b(ne, &non_double_value);
+
+  // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+  // FAST_DOUBLE_ELEMENTS and complete the store.
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_DOUBLE_ELEMENTS,
+                                         receiver_map,
+                                         r4,
+                                         &slow);
+  ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
+  ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ jmp(&fast_double_without_map_check);
+
+  __ bind(&non_double_value);
+  // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         receiver_map,
+                                         r4,
+                                         &slow);
+  ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
+  ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
+
+  __ bind(&transition_double_elements);
+  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         receiver_map,
+                                         r4,
+                                         &slow);
+  ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
+  ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
 }


=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Jan 27 08:54:22 2012 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Feb 2 03:22:26 2012
@@ -2879,27 +2879,42 @@
 }


-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+    ElementsKind expected_kind,
+    ElementsKind transitioned_kind,
+    Register map_in_out,
+    Register scratch,
+    Label* no_map_match) {
+  // Load the global or builtins object from the current context.
+  ldr(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check that the function's map is the same as the expected cached map.
+  int expected_index =
+      Context::GetContextMapIndexFromElementsKind(expected_kind);
+  ldr(ip, MemOperand(scratch, Context::SlotOffset(expected_index)));
+  cmp(map_in_out, ip);
+  b(ne, no_map_match);
+
+  // Use the transitioned cached map.
+  int trans_index =
+      Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+  ldr(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
     Register function_in, Register scratch, Register map_out) {
   ASSERT(!function_in.is(map_out));
   Label done;
   ldr(map_out, FieldMemOperand(function_in,
                                JSFunction::kPrototypeOrInitialMapOffset));
   if (!FLAG_smi_only_arrays) {
-    // Load the global or builtins object from the current context.
- ldr(scratch, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); - ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
-
-    // Check that the function's map is same as the cached map.
-    ldr(ip, MemOperand(
-        scratch, Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
-    cmp(map_out, ip);
-    b(ne, &done);
-
-    // Use the cached transitioned map.
-    ldr(map_out,
-        MemOperand(scratch,
- Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+    LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                        FAST_ELEMENTS,
+                                        map_out,
+                                        scratch,
+                                        &done);
   }
   bind(&done);
 }
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Jan 27 08:54:22 2012 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Feb 2 03:22:26 2012
@@ -491,10 +491,21 @@

   void LoadContext(Register dst, int context_chain_length);

-  // Load the initial map for new Arrays of a given type.
-  void LoadGlobalInitialConstructedArrayMap(Register function_in,
-                                            Register scratch,
-                                            Register map_out);
+  // Conditionally load the cached Array transitioned map of type
+  // transitioned_kind from the global context if the map in register
+  // map_in_out is the cached Array map in the global context of
+  // expected_kind.
+  void LoadTransitionedArrayMapConditional(
+      ElementsKind expected_kind,
+      ElementsKind transitioned_kind,
+      Register map_in_out,
+      Register scratch,
+      Label* no_map_match);
+
+  // Load the initial map for new Arrays from a JSFunction.
+  void LoadInitialArrayMap(Register function_in,
+                           Register scratch,
+                           Register map_out);

   void LoadGlobalFunction(int index, Register function);

=======================================
--- /branches/bleeding_edge/src/contexts.h      Thu Jan 26 13:47:57 2012
+++ /branches/bleeding_edge/src/contexts.h      Thu Feb  2 03:22:26 2012
@@ -368,6 +368,18 @@
   void RemoveOptimizedFunction(JSFunction* function);
   Object* OptimizedFunctionsListHead();
   void ClearOptimizedFunctions();
+
+  static int GetContextMapIndexFromElementsKind(
+      ElementsKind elements_kind) {
+    if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+      return Context::DOUBLE_JS_ARRAY_MAP_INDEX;
+    } else if (elements_kind == FAST_ELEMENTS) {
+      return Context::OBJECT_JS_ARRAY_MAP_INDEX;
+    } else {
+      ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
+      return Context::SMI_JS_ARRAY_MAP_INDEX;
+    }
+  }

 #define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
   void  set_##name(type* value) {                         \
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Fri Jan 27 05:03:19 2012 +++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Thu Feb 2 03:22:26 2012
@@ -894,7 +894,7 @@
   const int initial_capacity = JSArray::kPreallocatedArrayElements;
   STATIC_ASSERT(initial_capacity >= 0);

- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+  __ LoadInitialArrayMap(array_function, scratch2, scratch1);

// Allocate the JSArray object together with space for a fixed array with the
   // requested elements.
@@ -997,9 +997,7 @@
   ASSERT(!fill_with_hole || array_size.is(ecx));  // rep stos count
   ASSERT(!fill_with_hole || !result.is(eax));  // result is never eax

-  __ LoadGlobalInitialConstructedArrayMap(array_function,
-                                          scratch,
-                                          elements_array);
+  __ LoadInitialArrayMap(array_function, scratch, elements_array);

// Allocate the JSArray object together with space for a FixedArray with the
   // requested elements.
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Mon Jan 23 08:18:10 2012
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Thu Feb  2 03:22:26 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -765,7 +765,8 @@
   // -----------------------------------
   Label slow, fast_object_with_map_check, fast_object_without_map_check;
   Label fast_double_with_map_check, fast_double_without_map_check;
-  Label check_if_double_array, array, extra;
+  Label check_if_double_array, array, extra, transition_smi_elements;
+  Label finish_object_store, non_double_value, transition_double_elements;

   // Check that the object isn't a smi.
   __ JumpIfSmi(edx, &slow);
@@ -862,11 +863,12 @@
   __ ret(0);

   __ bind(&non_smi_value);
-  // Escape to slow case when writing non-smi into smi-only array.
+  // Escape to elements kind transition case.
   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
-  __ CheckFastObjectElements(edi, &slow, Label::kNear);
+  __ CheckFastObjectElements(edi, &transition_smi_elements);

   // Fast elements array, store the value to the elements backing store.
+  __ bind(&finish_object_store);
   __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
   // Update write barrier for the elements array address.
   __ mov(edx, eax);  // Preserve the value which is returned.
@@ -882,8 +884,54 @@
   __ bind(&fast_double_without_map_check);
// If the value is a number, store it as a double in the FastDoubleElements
   // array.
-  __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0, &slow, false);
+  __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0,
+                                 &transition_double_elements, false);
   __ ret(0);
+
+  __ bind(&transition_smi_elements);
+  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+
+  // Transition the array appropriately depending on the value type.
+  __ CheckMap(eax,
+              masm->isolate()->factory()->heap_number_map(),
+              &non_double_value,
+              DONT_DO_SMI_CHECK);
+
+  // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+  // FAST_DOUBLE_ELEMENTS and complete the store.
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_DOUBLE_ELEMENTS,
+                                         ebx,
+                                         edi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+  __ jmp(&fast_double_without_map_check);
+
+  __ bind(&non_double_value);
+  // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         ebx,
+                                         edi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
+
+  __ bind(&transition_double_elements);
+  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         ebx,
+                                         edi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
 }


=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Jan 26 13:47:57 2012 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Feb 2 03:22:26 2012
@@ -2168,27 +2168,41 @@
 }


-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+    ElementsKind expected_kind,
+    ElementsKind transitioned_kind,
+    Register map_in_out,
+    Register scratch,
+    Label* no_map_match) {
+  // Load the global or builtins object from the current context.
+  mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check that the function's map is the same as the expected cached map.
+  int expected_index =
+      Context::GetContextMapIndexFromElementsKind(expected_kind);
+  cmp(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+  j(not_equal, no_map_match);
+
+  // Use the transitioned cached map.
+  int trans_index =
+      Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+  mov(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
     Register function_in, Register scratch, Register map_out) {
   ASSERT(!function_in.is(map_out));
   Label done;
   mov(map_out, FieldOperand(function_in,
                             JSFunction::kPrototypeOrInitialMapOffset));
   if (!FLAG_smi_only_arrays) {
-    // Load the global or builtins object from the current context.
-    mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
- mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
-
-    // Check that the function's map is same as the cached map.
-    cmp(map_out,
-        Operand(scratch,
-                Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
-    j(not_equal, &done);
-
-    // Use the cached transitioned map.
-    mov(map_out,
-        Operand(scratch,
-                Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+    LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                        FAST_ELEMENTS,
+                                        map_out,
+                                        scratch,
+                                        &done);
   }
   bind(&done);
 }
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Jan 26 13:47:57 2012 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Feb 2 03:22:26 2012
@@ -221,10 +221,21 @@
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);

-  // Load the initial map for new Arrays of a given type.
-  void LoadGlobalInitialConstructedArrayMap(Register function_in,
-                                            Register scratch,
-                                            Register map_out);
+  // Conditionally load the cached Array transitioned map of type
+  // transitioned_kind from the global context if the map in register
+  // map_in_out is the cached Array map in the global context of
+  // expected_kind.
+  void LoadTransitionedArrayMapConditional(
+      ElementsKind expected_kind,
+      ElementsKind transitioned_kind,
+      Register map_in_out,
+      Register scratch,
+      Label* no_map_match);
+
+  // Load the initial map for new Arrays from a JSFunction.
+  void LoadInitialArrayMap(Register function_in,
+                           Register scratch,
+                           Register map_out);

   // Load the global function with the given index.
   void LoadGlobalFunction(int index, Register function);
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc      Mon Jan 16 04:38:59 2012
+++ /branches/bleeding_edge/src/objects-printer.cc      Thu Feb  2 03:22:26 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -569,7 +569,11 @@
   HeapObject::PrintHeader(out, "FixedDoubleArray");
   PrintF(out, " - length: %d", length());
   for (int i = 0; i < length(); i++) {
-    PrintF(out, "\n  [%d]: %g", i, get_scalar(i));
+    if (is_the_hole(i)) {
+      PrintF(out, "\n  [%d]: <the hole>", i);
+    } else {
+      PrintF(out, "\n  [%d]: %g", i, get_scalar(i));
+    }
   }
   PrintF(out, "\n");
 }
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc     Fri Jan 27 05:03:19 2012
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc     Thu Feb  2 03:22:26 2012
@@ -972,7 +972,7 @@
   const int initial_capacity = JSArray::kPreallocatedArrayElements;
   STATIC_ASSERT(initial_capacity >= 0);

- __ LoadGlobalInitialConstructedArrayMap(array_function, scratch2, scratch1);
+  __ LoadInitialArrayMap(array_function, scratch2, scratch1);

// Allocate the JSArray object together with space for a fixed array with the
   // requested elements.
@@ -1071,9 +1071,7 @@
                             Register scratch,
                             bool fill_with_hole,
                             Label* gc_required) {
-  __ LoadGlobalInitialConstructedArrayMap(array_function,
-                                          scratch,
-                                          elements_array);
+  __ LoadInitialArrayMap(array_function, scratch, elements_array);

   if (FLAG_debug_code) {  // Assert that array size is not zero.
     __ testq(array_size, array_size);
=======================================
--- /branches/bleeding_edge/src/x64/ic-x64.cc   Mon Jan 23 08:18:10 2012
+++ /branches/bleeding_edge/src/x64/ic-x64.cc   Thu Feb  2 03:22:26 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 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:
@@ -635,6 +635,8 @@
Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
   Label fast_object_with_map_check, fast_object_without_map_check;
   Label fast_double_with_map_check, fast_double_without_map_check;
+  Label transition_smi_elements, finish_object_store, non_double_value;
+  Label transition_double_elements;

   // Check that the object isn't a smi.
   __ JumpIfSmi(rdx, &slow_with_tagged_index);
@@ -737,7 +739,8 @@
   __ bind(&non_smi_value);
   // Writing a non-smi, check whether array allows non-smi elements.
   // r9: receiver's map
-  __ CheckFastObjectElements(r9, &slow, Label::kNear);
+  __ CheckFastObjectElements(r9, &transition_smi_elements);
+  __ bind(&finish_object_store);
__ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
           rax);
   __ movq(rdx, rax);  // Preserve the value which is returned.
@@ -754,8 +757,52 @@
   __ bind(&fast_double_without_map_check);
// If the value is a number, store it as a double in the FastDoubleElements
   // array.
-  __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, &slow);
+  __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
+                                 &transition_double_elements);
   __ ret(0);
+
+  __ bind(&transition_smi_elements);
+  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+
+  // Transition the array appropriately depending on the value type.
+  __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
+  __ j(not_equal, &non_double_value);
+
+  // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
+  // FAST_DOUBLE_ELEMENTS and complete the store.
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_DOUBLE_ELEMENTS,
+                                         rbx,
+                                         rdi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
+  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ jmp(&fast_double_without_map_check);
+
+  __ bind(&non_double_value);
+  // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         rbx,
+                                         rdi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
+  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
+
+  __ bind(&transition_double_elements);
+  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
+  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
+                                         FAST_ELEMENTS,
+                                         rbx,
+                                         rdi,
+                                         &slow);
+  ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
+  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ jmp(&finish_object_store);
 }


=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Jan 26 13:47:57 2012 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Feb 2 03:22:26 2012
@@ -4034,27 +4034,41 @@
 }


-void MacroAssembler::LoadGlobalInitialConstructedArrayMap(
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+    ElementsKind expected_kind,
+    ElementsKind transitioned_kind,
+    Register map_in_out,
+    Register scratch,
+    Label* no_map_match) {
+  // Load the global or builtins object from the current context.
+  movq(scratch, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+  movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check that the function's map is the same as the expected cached map.
+  int expected_index =
+      Context::GetContextMapIndexFromElementsKind(expected_kind);
+  cmpq(map_in_out, Operand(scratch, Context::SlotOffset(expected_index)));
+  j(not_equal, no_map_match);
+
+  // Use the transitioned cached map.
+  int trans_index =
+      Context::GetContextMapIndexFromElementsKind(transitioned_kind);
+  movq(map_in_out, Operand(scratch, Context::SlotOffset(trans_index)));
+}
+
+
+void MacroAssembler::LoadInitialArrayMap(
     Register function_in, Register scratch, Register map_out) {
   ASSERT(!function_in.is(map_out));
   Label done;
   movq(map_out, FieldOperand(function_in,
                              JSFunction::kPrototypeOrInitialMapOffset));
   if (!FLAG_smi_only_arrays) {
-    // Load the global or builtins object from the current context.
- movq(scratch, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); - movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
-
-    // Check that the function's map is same as the cached map.
-    cmpq(map_out,
-         Operand(scratch,
-                 Context::SlotOffset(Context::SMI_JS_ARRAY_MAP_INDEX)));
-    j(not_equal, &done);
-
-    // Use the cached transitioned map.
-    movq(map_out,
-         Operand(scratch,
-                 Context::SlotOffset(Context::OBJECT_JS_ARRAY_MAP_INDEX)));
+    LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
+                                        FAST_ELEMENTS,
+                                        map_out,
+                                        scratch,
+                                        &done);
   }
   bind(&done);
 }
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Thu Jan 26 13:47:57 2012 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Thu Feb 2 03:22:26 2012
@@ -1123,10 +1123,21 @@
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);

-  // Load the initial map for new Arrays of a given type.
-  void LoadGlobalInitialConstructedArrayMap(Register function_in,
-                                            Register scratch,
-                                            Register map_out);
+  // Conditionally load the cached Array transitioned map of type
+  // transitioned_kind from the global context if the map in register
+  // map_in_out is the cached Array map in the global context of
+  // expected_kind.
+  void LoadTransitionedArrayMapConditional(
+      ElementsKind expected_kind,
+      ElementsKind transitioned_kind,
+      Register map_in_out,
+      Register scratch,
+      Label* no_map_match);
+
+  // Load the initial map for new Arrays from a JSFunction.
+  void LoadInitialArrayMap(Register function_in,
+                           Register scratch,
+                           Register map_out);

   // Load the global function with the given index.
   void LoadGlobalFunction(int index, Register function);

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

Reply via email to