Apply fix for issue 109 from bleeding_edge branch. Update
version from 0.3.4 to 0.3.4.1.
Review URL: http://codereview.chromium.org/6529

git-svn-id: http://v8.googlecode.com/svn/trunk@459 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 09e91a6..7b22484 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2216,7 +2216,7 @@
 
 
 const char* v8::V8::GetVersion() {
-  return "0.3.4";
+  return "0.3.4.1";
 }
 
 
diff --git a/src/builtins.cc b/src/builtins.cc
index a0684a2..43049f4 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -575,6 +575,11 @@
 }
 
 
+static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateExtendStorage(masm);
+}
+
+
 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
   KeyedStoreIC::GenerateMiss(masm);
 }
diff --git a/src/builtins.h b/src/builtins.h
index 531c9e2..14d4ee6 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -63,6 +63,7 @@
   V(KeyedStoreIC_Miss,          BUILTIN, UNINITIALIZED)        \
                                                                \
   V(StoreIC_ExtendStorage,      BUILTIN, UNINITIALIZED)        \
+  V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED)        \
                                                                \
   V(LoadIC_Initialize,          LOAD_IC, UNINITIALIZED)        \
   V(LoadIC_PreMonomorphic,      LOAD_IC, PREMONOMORPHIC)       \
diff --git a/src/ic-arm.cc b/src/ic-arm.cc
index c9a7629..8c165a6 100644
--- a/src/ic-arm.cc
+++ b/src/ic-arm.cc
@@ -538,6 +538,9 @@
 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
 }
 
+void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+}
+
 
 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   // ----------- S t a t e -------------
@@ -569,7 +572,8 @@
   __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit());
 
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ExtendStorage)), 3);
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
 }
 
 
diff --git a/src/ic-ia32.cc b/src/ic-ia32.cc
index a70177f..496af24 100644
--- a/src/ic-ia32.cc
+++ b/src/ic-ia32.cc
@@ -702,7 +702,8 @@
   __ push(eax);
   __ push(ebx);
   // Perform tail call to the entry.
-  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_ExtendStorage)), 3);
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
 }
 
 
@@ -749,6 +750,27 @@
 }
 
 
+void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : transition map
+  //  -- esp[0] : return address
+  //  -- esp[4] : key
+  //  -- esp[8] : receiver
+  // -----------------------------------
+
+  // Move the return address below the arguments.
+  __ pop(ebx);
+  __ push(Operand(esp, 1 * kPointerSize));
+  __ push(ecx);
+  __ push(eax);
+  __ push(ebx);
+
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(
+      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
+}
+
 #undef __
 
 
diff --git a/src/ic.cc b/src/ic.cc
index 10bcf6b..61dc3d0 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1115,7 +1115,7 @@
 // Extend storage is called in a store inline cache when
 // it is necessary to extend the properties array of a
 // JSObject.
-Object* StoreIC_ExtendStorage(Arguments args) {
+Object* SharedStoreIC_ExtendStorage(Arguments args) {
   NoHandleAllocation na;
   ASSERT(args.length() == 3);
 
diff --git a/src/ic.h b/src/ic.h
index ed655bc..fd5c72b 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -34,17 +34,17 @@
 
 // IC_UTIL_LIST defines all utility functions called from generated
 // inline caching code. The argument for the macro, ICU, is the function name.
-#define IC_UTIL_LIST(ICU)       \
-  ICU(LoadIC_Miss)              \
-  ICU(KeyedLoadIC_Miss)         \
-  ICU(CallIC_Miss)              \
-  ICU(StoreIC_Miss)             \
-  ICU(StoreIC_ExtendStorage)    \
-  ICU(KeyedStoreIC_Miss)        \
-  /* Utilities for IC stubs. */ \
-  ICU(LoadCallbackProperty)     \
-  ICU(StoreCallbackProperty)    \
-  ICU(LoadInterceptorProperty)  \
+#define IC_UTIL_LIST(ICU)          \
+  ICU(LoadIC_Miss)                 \
+  ICU(KeyedLoadIC_Miss)            \
+  ICU(CallIC_Miss)                 \
+  ICU(StoreIC_Miss)                \
+  ICU(SharedStoreIC_ExtendStorage) \
+  ICU(KeyedStoreIC_Miss)           \
+  /* Utilities for IC stubs. */    \
+  ICU(LoadCallbackProperty)        \
+  ICU(StoreCallbackProperty)       \
+  ICU(LoadInterceptorProperty)     \
   ICU(StoreInterceptorProperty)
 
 //
@@ -333,6 +333,7 @@
   static void GenerateInitialize(MacroAssembler* masm);
   static void GenerateMiss(MacroAssembler* masm);
   static void GenerateGeneric(MacroAssembler* masm);
+  static void GenerateExtendStorage(MacroAssembler* masm);
 
  private:
   static void Generate(MacroAssembler* masm, const ExternalReference& f);
diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc
index 708ac3c..dbbfb0a 100644
--- a/src/stub-cache-arm.cc
+++ b/src/stub-cache-arm.cc
@@ -411,41 +411,42 @@
   // checks.
   ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
 
-  // Get the properties array
-  __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
-
   // Perform map transition for the receiver if necessary.
-  if (transition != NULL) {
-    if (object->map()->unused_property_fields() == 0) {
-      // The properties must be extended before we can store the value.
-      // We jump to a runtime call that extends the propeties array.
-      __ mov(r2, Operand(Handle<Map>(transition)));
-      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
-      __ Jump(ic, RelocInfo::CODE_TARGET);
-    } else {
+  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+    // The properties must be extended before we can store the value.
+    // We jump to a runtime call that extends the propeties array.
+    __ mov(r2, Operand(Handle<Map>(transition)));
+    // Please note, if we implement keyed store for arm we need
+    // to call the Builtins::KeyedStoreIC_ExtendStorage.
+    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
+    __ Jump(ic, RelocInfo::CODE_TARGET);
+  } else {
+    // Get the properties array
+    __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
+
+    if (transition != NULL) {
       // Update the map of the object; no write barrier updating is
       // needed because the map is never in new space.
       __ mov(ip, Operand(Handle<Map>(transition)));
       __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
     }
+
+    // Write to the properties array.
+    int offset = index * kPointerSize + Array::kHeaderSize;
+    __ str(r0, FieldMemOperand(r1, offset));
+
+    // Skip updating write barrier if storing a smi.
+    __ tst(r0, Operand(kSmiTagMask));
+    __ b(eq, &exit);
+
+    // Update the write barrier for the array address.
+    __ mov(r3, Operand(offset));
+    __ RecordWrite(r1, r3, r2);  // OK to clobber r2, since we return
+
+    // Return the value (register r0).
+    __ bind(&exit);
+    __ Ret();
   }
-
-  // Write to the properties array.
-  int offset = index * kPointerSize + Array::kHeaderSize;
-  __ str(r0, FieldMemOperand(r1, offset));
-
-  // Skip updating write barrier if storing a smi.
-  __ tst(r0, Operand(kSmiTagMask));
-  __ b(eq, &exit);
-
-  // Update the write barrier for the array address.
-  __ mov(r3, Operand(offset));
-  __ RecordWrite(r1, r3, r2);  // OK to clobber r2, since we return
-
-  // Return the value (register r0).
-  __ bind(&exit);
-  __ Ret();
-
   // Handle store cache miss.
   __ bind(&miss);
   __ mov(r2, Operand(Handle<String>(name)));  // restore name
diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc
index c18fd9f..a7d8a7b 100644
--- a/src/stub-cache-ia32.cc
+++ b/src/stub-cache-ia32.cc
@@ -406,6 +406,7 @@
 
 
 void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Builtins::Name storage_extend,
                                       JSObject* object,
                                       int index,
                                       Map* transition,
@@ -431,23 +432,23 @@
   // checks.
   ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
 
+  // Perform map transition for the receiver if necessary.
+  if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+    // The properties must be extended before we can store the value.
+    // We jump to a runtime call that extends the propeties array.
+    __ mov(Operand(ecx), Immediate(Handle<Map>(transition)));
+    Handle<Code> ic(Builtins::builtin(storage_extend));
+    __ jmp(ic, RelocInfo::CODE_TARGET);
+    return;
+  }
+
   // Get the properties array (optimistically).
   __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-
-  // Perform map transition for the receiver if necessary.
   if (transition != NULL) {
-    if (object->map()->unused_property_fields() == 0) {
-      // The properties must be extended before we can store the value.
-      // We jump to a runtime call that extends the propeties array.
-      __ mov(Operand(ecx), Immediate(Handle<Map>(transition)));
-      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
-      __ jmp(ic, RelocInfo::CODE_TARGET);
-    } else {
-      // Update the map of the object; no write barrier updating is
-      // needed because the map is never in new space.
-      __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
-             Immediate(Handle<Map>(transition)));
-    }
+    // Update the map of the object; no write barrier updating is
+    // needed because the map is never in new space.
+    __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+           Immediate(Handle<Map>(transition)));
   }
 
   // Write to the properties array.
@@ -737,7 +738,13 @@
   __ mov(ebx, Operand(esp, 1 * kPointerSize));
 
   // Generate store field code.  Trashes the name register.
-  GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
+  GenerateStoreField(masm(),
+                     Builtins::StoreIC_ExtendStorage,
+                     object,
+                     index,
+                     transition,
+                     ebx, ecx, edx,
+                     &miss);
 
   // Handle store cache miss.
   __ bind(&miss);
@@ -887,7 +894,13 @@
   __ mov(ebx, Operand(esp, 2 * kPointerSize));
 
   // Generate store field code.  Trashes the name register.
-  GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
+  GenerateStoreField(masm(),
+                     Builtins::KeyedStoreIC_ExtendStorage,
+                     object,
+                     index,
+                     transition,
+                     ebx, ecx, edx,
+                     &miss);
 
   // Handle store cache miss.
   __ bind(&miss);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 1b47f85..718995f 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -351,6 +351,7 @@
                                             Register scratch2,
                                             Label* miss_label);
   static void GenerateStoreField(MacroAssembler* masm,
+                                 Builtins::Name storage_extend,
                                  JSObject* object,
                                  int index,
                                  Map* transition,
diff --git a/test/mjsunit/keyed-storage-extend.js b/test/mjsunit/keyed-storage-extend.js
new file mode 100644
index 0000000..04d2f04
--- /dev/null
+++ b/test/mjsunit/keyed-storage-extend.js
@@ -0,0 +1,55 @@
+// Copyright 2008 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.
+
+function F() { }
+
+function GrowNamed(o) {
+  o.a = 1;
+  o.b = 2;
+  o.c = 3;
+  o.d = 4;
+  o.e = 5;
+  o.f = 6;
+}
+
+function GrowKeyed(o) {
+  var names = ['a','b','c','d','e','f']; 
+  var i = 0;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+  o[names[i++]] = i;
+}
+
+GrowNamed(new F());
+GrowNamed(new F());
+GrowNamed(new F());
+GrowKeyed(new F());
+GrowKeyed(new F());
+GrowKeyed(new F());