Revision: 8901
Author:   [email protected]
Date:     Thu Aug 11 07:00:16 2011
Log: Create a common base class for Fixed-, FixedDouble- and ExternalArrays.

Also unify Crankshaft code to load array length.

BUG=v8:1493
TEST=external-arrays.js

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

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/test/mjsunit/external-array.js

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Thu Aug 11 00:22:16 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Thu Aug 11 07:00:16 2011
@@ -1509,16 +1509,10 @@
 }


-LInstruction* LChunkBuilder::DoExternalArrayLength(
-    HExternalArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+    HFixedArrayBaseLength* instr) {
   LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LExternalArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
-  LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LFixedArrayLength(array));
+  return DefineAsRegister(new LFixedArrayBaseLength(array));
 }


=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Tue Jul 19 06:04:00 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Thu Aug 11 07:00:16 2011
@@ -92,8 +92,7 @@
   V(DivI)                                       \
   V(DoubleToI)                                  \
   V(ElementsKind)                               \
-  V(ExternalArrayLength)                        \
-  V(FixedArrayLength)                           \
+  V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
   V(GlobalObject)                               \
@@ -915,25 +914,15 @@
 };


-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
  public:
-  explicit LExternalArrayLength(LOperand* value) {
+  explicit LFixedArrayBaseLength(LOperand* value) {
     inputs_[0] = value;
   }

- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
-  explicit LFixedArrayLength(LOperand* value) {
-    inputs_[0] = value;
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+                               "fixed-array-base-length")
+  DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
 };


=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Aug 11 00:22:16 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Aug 11 07:00:16 2011
@@ -1378,17 +1378,10 @@
 }


-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
   Register result = ToRegister(instr->result());
   Register array = ToRegister(instr->InputAt(0));
-  __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
-  Register result = ToRegister(instr->result());
-  Register array = ToRegister(instr->InputAt(0));
-  __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
+  __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
 }


=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Aug 2 06:36:38 2011 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Aug 11 07:00:16 2011
@@ -3489,9 +3489,9 @@

   // Check that the index is in range.
   __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
-  __ cmp(ip, Operand(key, ASR, kSmiTagSize));
+  __ cmp(key, ip);
   // Unsigned comparison catches both negative and too-large values.
-  __ b(lo, &miss_force_generic);
+  __ b(hs, &miss_force_generic);

   __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
   // r3: base pointer of external storage
@@ -3811,22 +3811,20 @@
   // This stub is meant to be tail-jumped to, the receiver must already
   // have been verified by the caller to not be a smi.

-  __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
   // Check that the key is a smi.
   __ JumpIfNotSmi(key, &miss_force_generic);

+  __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
   // Check that the index is in range
-  __ SmiUntag(r4, key);
   __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
-  __ cmp(r4, ip);
+  __ cmp(key, ip);
   // Unsigned comparison catches both negative and too-large values.
   __ b(hs, &miss_force_generic);

   // Handle both smis and HeapNumbers in the fast path. Go to the
   // runtime for all other kinds of values.
   // r3: external array.
-  // r4: key (integer).
   if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
     __ JumpIfNotSmi(value, &slow);
@@ -3837,32 +3835,32 @@
   __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));

   // r3: base pointer of external storage.
-  // r4: key (integer).
   // r5: value (integer).
   switch (elements_kind) {
     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
       // Clamp the value to [0..255].
       __ Usat(r5, 8, Operand(r5));
-      __ strb(r5, MemOperand(r3, r4, LSL, 0));
+      __ strb(r5, MemOperand(r3, key, LSR, 1));
       break;
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-      __ strb(r5, MemOperand(r3, r4, LSL, 0));
+      __ strb(r5, MemOperand(r3, key, LSR, 1));
       break;
     case JSObject::EXTERNAL_SHORT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-      __ strh(r5, MemOperand(r3, r4, LSL, 1));
+      __ strh(r5, MemOperand(r3, key, LSL, 0));
       break;
     case JSObject::EXTERNAL_INT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-      __ str(r5, MemOperand(r3, r4, LSL, 2));
+      __ str(r5, MemOperand(r3, key, LSL, 1));
       break;
     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
       // Perform int-to-float conversion and store to memory.
+      __ SmiUntag(r4, key);
       StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
       break;
     case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
-      __ add(r3, r3, Operand(r4, LSL, 3));
+      __ add(r3, r3, Operand(key, LSL, 2));
       // r3: effective address of the double element
       FloatingPointHelper::Destination destination;
       if (CpuFeatures::IsSupported(VFP3)) {
@@ -3895,7 +3893,6 @@

   if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
     // r3: external array.
-    // r4: index (integer).
     __ bind(&check_heap_number);
     __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
     __ b(ne, &slow);
@@ -3903,7 +3900,6 @@
     __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));

     // r3: base pointer of external storage.
-    // r4: key (integer).

     // The WebGL specification leaves the behavior of storing NaN and
     // +/-Infinity into integer arrays basically undefined. For more
@@ -3916,13 +3912,13 @@
         // include -kHeapObjectTag into it.
         __ sub(r5, r0, Operand(kHeapObjectTag));
         __ vldr(d0, r5, HeapNumber::kValueOffset);
-        __ add(r5, r3, Operand(r4, LSL, 2));
+        __ add(r5, r3, Operand(key, LSL, 1));
         __ vcvt_f32_f64(s0, d0);
         __ vstr(s0, r5, 0);
       } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
         __ sub(r5, r0, Operand(kHeapObjectTag));
         __ vldr(d0, r5, HeapNumber::kValueOffset);
-        __ add(r5, r3, Operand(r4, LSL, 3));
+        __ add(r5, r3, Operand(key, LSL, 2));
         __ vstr(d0, r5, 0);
       } else {
// Hoisted load. vldr requires offset to be a multiple of 4 so we can
@@ -3934,15 +3930,15 @@
         switch (elements_kind) {
           case JSObject::EXTERNAL_BYTE_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ strb(r5, MemOperand(r3, r4, LSL, 0));
+            __ strb(r5, MemOperand(r3, key, LSR, 1));
             break;
           case JSObject::EXTERNAL_SHORT_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ strh(r5, MemOperand(r3, r4, LSL, 1));
+            __ strh(r5, MemOperand(r3, key, LSL, 0));
             break;
           case JSObject::EXTERNAL_INT_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ str(r5, MemOperand(r3, r4, LSL, 2));
+            __ str(r5, MemOperand(r3, key, LSL, 1));
             break;
           case JSObject::EXTERNAL_PIXEL_ELEMENTS:
           case JSObject::EXTERNAL_FLOAT_ELEMENTS:
@@ -4004,7 +4000,7 @@
         __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));

         __ bind(&done);
-        __ str(r5, MemOperand(r3, r4, LSL, 2));
+        __ str(r5, MemOperand(r3, key, LSL, 1));
// Entry registers are intact, r0 holds the value which is the return
         // value.
         __ Ret();
@@ -4017,7 +4013,7 @@
         __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
         __ b(&done);
       } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
-        __ add(r7, r3, Operand(r4, LSL, 3));
+        __ add(r7, r3, Operand(key, LSL, 2));
         // r7: effective address of destination element.
         __ str(r6, MemOperand(r7, 0));
         __ str(r5, MemOperand(r7, Register::kSizeInBytes));
@@ -4073,15 +4069,15 @@
         switch (elements_kind) {
           case JSObject::EXTERNAL_BYTE_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ strb(r5, MemOperand(r3, r4, LSL, 0));
+            __ strb(r5, MemOperand(r3, key, LSR, 1));
             break;
           case JSObject::EXTERNAL_SHORT_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ strh(r5, MemOperand(r3, r4, LSL, 1));
+            __ strh(r5, MemOperand(r3, key, LSL, 0));
             break;
           case JSObject::EXTERNAL_INT_ELEMENTS:
           case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ str(r5, MemOperand(r3, r4, LSL, 2));
+            __ str(r5, MemOperand(r3, key, LSL, 1));
             break;
           case JSObject::EXTERNAL_PIXEL_ELEMENTS:
           case JSObject::EXTERNAL_FLOAT_ELEMENTS:
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Jul 26 09:31:11 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Thu Aug 11 07:00:16 2011
@@ -104,8 +104,7 @@
   V(Div)                                       \
   V(ElementsKind)                              \
   V(EnterInlined)                              \
-  V(ExternalArrayLength)                       \
-  V(FixedArrayLength)                          \
+  V(FixedArrayBaseLength)                      \
   V(ForceRepresentation)                       \
   V(FunctionLiteral)                           \
   V(GetCachedArrayIndex)                       \
@@ -1702,9 +1701,9 @@
 };


-class HFixedArrayLength: public HUnaryOperation {
+class HFixedArrayBaseLength: public HUnaryOperation {
  public:
-  explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
+  explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     SetFlag(kDependsOnArrayLengths);
@@ -1714,28 +1713,7 @@
     return Representation::Tagged();
   }

-  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength)
-
- protected:
-  virtual bool DataEquals(HValue* other) { return true; }
-};
-
-
-class HExternalArrayLength: public HUnaryOperation {
- public:
-  explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) {
-    set_representation(Representation::Integer32());
- // The result of this instruction is idempotent as long as its inputs don't - // change. The length of a pixel array cannot change once set, so it's not - // necessary to introduce a kDependsOnArrayLengths or any other dependency.
-    SetFlag(kUseGVN);
-  }
-
-  virtual Representation RequiredInputRepresentation(int index) const {
-    return Representation::Tagged();
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength)
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)

  protected:
   virtual bool DataEquals(HValue* other) { return true; }
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Wed Aug 10 09:05:17 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Thu Aug 11 07:00:16 2011
@@ -3940,7 +3940,7 @@
   HInstruction* length = NULL;
   HInstruction* checked_key = NULL;
   if (map->has_external_array_elements()) {
-    length = AddInstruction(new(zone()) HExternalArrayLength(elements));
+    length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
     checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
     HLoadExternalArrayPointer* external_elements =
         new(zone()) HLoadExternalArrayPointer(elements);
@@ -3952,7 +3952,7 @@
   if (map->instance_type() == JS_ARRAY_TYPE) {
     length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
   } else {
-    length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+    length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
   }
   checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
   if (is_store) {
@@ -4024,7 +4024,7 @@
     if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
         && todo_external_array) {
       HInstruction* length =
-          AddInstruction(new(zone()) HExternalArrayLength(elements));
+          AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
       checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
       external_elements = new(zone()) HLoadExternalArrayPointer(elements);
       AddInstruction(external_elements);
@@ -4088,7 +4088,7 @@
         if_jsarray->Goto(join);

         set_current_block(if_fastobject);
-        length = AddInstruction(new(zone()) HFixedArrayLength(elements));
+ length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
         if (is_store) {
           if (fast_double_elements) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Aug 11 00:22:16 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Aug 11 07:00:16 2011
@@ -1211,17 +1211,11 @@
 }


-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(
+    LFixedArrayBaseLength* instr) {
   Register result = ToRegister(instr->result());
   Register array = ToRegister(instr->InputAt(0));
-  __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
-  Register result = ToRegister(instr->result());
-  Register array = ToRegister(instr->InputAt(0));
-  __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
+  __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
 }


=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Aug 11 00:22:16 2011 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Aug 11 07:00:16 2011
@@ -1538,16 +1538,10 @@
 }


-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+    HFixedArrayBaseLength* instr) {
   LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LFixedArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoExternalArrayLength(
-    HExternalArrayLength* instr) {
-  LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LExternalArrayLength(array));
+  return DefineAsRegister(new LFixedArrayBaseLength(array));
 }


=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Jul 28 06:33:51 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Aug 11 07:00:16 2011
@@ -86,8 +86,7 @@
   V(DivI)                                       \
   V(DoubleToI)                                  \
   V(ElementsKind)                               \
-  V(ExternalArrayLength)                        \
-  V(FixedArrayLength)                           \
+  V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
   V(GlobalObject)                               \
@@ -922,25 +921,15 @@
 };


-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
  public:
-  explicit LExternalArrayLength(LOperand* value) {
+  explicit LFixedArrayBaseLength(LOperand* value) {
     inputs_[0] = value;
   }

- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
-  explicit LFixedArrayLength(LOperand* value) {
-    inputs_[0] = value;
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+                               "fixed-array-base-length")
+  DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
 };


=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Aug 2 06:36:38 2011 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Aug 11 07:00:16 2011
@@ -3400,37 +3400,37 @@
   __ JumpIfNotSmi(eax, &miss_force_generic);

   // Check that the index is in range.
-  __ mov(ecx, eax);
-  __ SmiUntag(ecx);  // Untag the index.
   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
-  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
+  __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &miss_force_generic);
   __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
   // ebx: base pointer of external storage
   switch (elements_kind) {
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
-      __ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
+      __ SmiUntag(eax);  // Untag the index.
+      __ movsx_b(eax, Operand(ebx, eax, times_1, 0));
       break;
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
-      __ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
+      __ SmiUntag(eax);  // Untag the index.
+      __ movzx_b(eax, Operand(ebx, eax, times_1, 0));
       break;
     case JSObject::EXTERNAL_SHORT_ELEMENTS:
-      __ movsx_w(eax, Operand(ebx, ecx, times_2, 0));
+      __ movsx_w(eax, Operand(ebx, eax, times_1, 0));
       break;
     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-      __ movzx_w(eax, Operand(ebx, ecx, times_2, 0));
+      __ movzx_w(eax, Operand(ebx, eax, times_1, 0));
       break;
     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
     case JSObject::EXTERNAL_INT_ELEMENTS:
-      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
+      __ mov(ecx, Operand(ebx, eax, times_2, 0));
       break;
     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
-      __ fld_s(Operand(ebx, ecx, times_4, 0));
+      __ fld_s(Operand(ebx, eax, times_2, 0));
       break;
     case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
-      __ fld_d(Operand(ebx, ecx, times_8, 0));
+      __ fld_d(Operand(ebx, eax, times_4, 0));
       break;
     default:
       UNREACHABLE();
@@ -3556,9 +3556,7 @@

   // Check that the index is in range.
   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
-  __ mov(ebx, ecx);
-  __ SmiUntag(ebx);
-  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
+  __ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &slow);

@@ -3568,7 +3566,6 @@
   // edx: receiver
   // ecx: key
   // edi: elements array
-  // ebx: untagged index
   if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
     __ JumpIfNotSmi(eax, &slow);
   } else {
@@ -3576,44 +3573,39 @@
   }

   // smi case
- __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
-  __ SmiUntag(ecx);
+  __ mov(ebx, eax);  // Preserve the value in eax as the return value.
+  __ SmiUntag(ebx);
   __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
-  // ecx: base pointer of external storage
+  // edi: base pointer of external storage
   switch (elements_kind) {
     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
-      {  // Clamp the value to [0..255].
-        Label done;
-        __ test(ecx, Immediate(0xFFFFFF00));
-        __ j(zero, &done, Label::kNear);
-        __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
-        __ dec_b(ecx);  // 0 if negative, 255 if positive.
-        __ bind(&done);
-      }
-      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+      __ ClampUint8(ebx);
+      __ SmiUntag(ecx);
+      __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
       break;
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+      __ SmiUntag(ecx);
+      __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
       break;
     case JSObject::EXTERNAL_SHORT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
+      __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
       break;
     case JSObject::EXTERNAL_INT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-      __ mov(Operand(edi, ebx, times_4, 0), ecx);
+      __ mov(Operand(edi, ecx, times_2, 0), ebx);
       break;
     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
     case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
       // Need to perform int-to-float conversion.
-      __ push(ecx);
+      __ push(ebx);
       __ fild_s(Operand(esp, 0));
-      __ pop(ecx);
+      __ pop(ebx);
       if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
-        __ fstp_s(Operand(edi, ebx, times_4, 0));
+        __ fstp_s(Operand(edi, ecx, times_2, 0));
       } else {  // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
-        __ fstp_d(Operand(edi, ebx, times_8, 0));
+        __ fstp_d(Operand(edi, ecx, times_4, 0));
       }
       break;
     default:
@@ -3629,7 +3621,6 @@
     // edx: receiver
     // ecx: key
     // edi: elements array
-    // ebx: untagged index
     __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
            Immediate(masm->isolate()->factory()->heap_number_map()));
     __ j(not_equal, &slow);
@@ -3638,15 +3629,14 @@
     // +/-Infinity into integer arrays basically undefined. For more
     // reproducible behavior, convert these to zero.
     __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
-    // ebx: untagged index
     // edi: base pointer of external storage
     if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
       __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
-      __ fstp_s(Operand(edi, ebx, times_4, 0));
+      __ fstp_s(Operand(edi, ecx, times_2, 0));
       __ ret(0);
     } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
       __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
-      __ fstp_d(Operand(edi, ebx, times_8, 0));
+      __ fstp_d(Operand(edi, ecx, times_4, 0));
       __ ret(0);
     } else {
       // Perform float-to-int conversion with truncation (round-to-zero)
@@ -3661,27 +3651,20 @@
             elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
           ASSERT(CpuFeatures::IsSupported(SSE2));
           CpuFeatures::Scope scope(SSE2);
-          __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
+          __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
           // ecx: untagged integer value
           switch (elements_kind) {
             case JSObject::EXTERNAL_PIXEL_ELEMENTS:
-              {  // Clamp the value to [0..255].
-                Label done;
-                __ test(ecx, Immediate(0xFFFFFF00));
-                __ j(zero, &done, Label::kNear);
-                __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
-                __ dec_b(ecx);  // 0 if negative, 255 if positive.
-                __ bind(&done);
-              }
-              __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
-              break;
+              __ ClampUint8(ebx);
+              // Fall through.
             case JSObject::EXTERNAL_BYTE_ELEMENTS:
             case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-              __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+              __ SmiUntag(ecx);
+              __ mov_b(Operand(edi, ecx, times_1, 0), ebx);
               break;
             case JSObject::EXTERNAL_SHORT_ELEMENTS:
             case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-              __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
+              __ mov_w(Operand(edi, ecx, times_1, 0), ebx);
               break;
             default:
               UNREACHABLE();
@@ -3698,7 +3681,7 @@
             __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
             __ sub(Operand(esp), Immediate(2 * kPointerSize));
             __ fisttp_d(Operand(esp, 0));
-            __ pop(ecx);
+            __ pop(ebx);
             __ add(Operand(esp), Immediate(kPointerSize));
           } else {
             ASSERT(CpuFeatures::IsSupported(SSE2));
@@ -3709,15 +3692,15 @@
             // Note: we could do better for signed int arrays.
             __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
// We will need the key if we have to make the slow runtime call.
-            __ push(ecx);
-            __ LoadPowerOf2(xmm1, ecx, 31);
-            __ pop(ecx);
+            __ push(ebx);
+            __ LoadPowerOf2(xmm1, ebx, 31);
+            __ pop(ebx);
             __ ucomisd(xmm1, xmm0);
             __ j(above_equal, &slow);
-            __ cvttsd2si(ecx, Operand(xmm0));
-          }
-          // ecx: untagged integer value
-          __ mov(Operand(edi, ebx, times_4, 0), ecx);
+            __ cvttsd2si(ebx, Operand(xmm0));
+          }
+          // ebx: untagged integer value
+          __ mov(Operand(edi, ecx, times_2, 0), ebx);
         }
         __ ret(0);  // Return original value.
       }
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Aug 3 03:07:34 2011 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Thu Aug 11 07:00:16 2011
@@ -3494,7 +3494,7 @@
   __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
   __ sra(t2, key, kSmiTagSize);
   // Unsigned comparison catches both negative and too-large values.
-  __ Branch(&miss_force_generic, Uless, t1, Operand(t2));
+  __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));

   __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
   // a3: base pointer of external storage
@@ -3822,16 +3822,16 @@
   // This stub is meant to be tail-jumped to, the receiver must already
   // have been verified by the caller to not be a smi.

-  __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
-
-  // Check that the key is a smi.
+    // Check that the key is a smi.
   __ JumpIfNotSmi(key, &miss_force_generic);

+  __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
   // Check that the index is in range.
   __ SmiUntag(t0, key);
   __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
-  __ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1));
+  __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));

   // Handle both smis and HeapNumbers in the fast path. Go to the
   // runtime for all other kinds of values.
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Aug  8 09:14:46 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Thu Aug 11 07:00:16 2011
@@ -2114,12 +2114,6 @@


 SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
-SMI_ACCESSORS(ByteArray, length, kLengthOffset)
-
-// TODO(1493): Investigate if it's possible to s/INT/SMI/ here (and
-// subsequently unify H{Fixed,External}ArrayLength).
-INT_ACCESSORS(ExternalArray, length, kLengthOffset)
-

 SMI_ACCESSORS(String, length, kLengthOffset)

=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Aug 10 09:05:17 2011
+++ /branches/bleeding_edge/src/objects.h       Thu Aug 11 07:00:16 2011
@@ -62,17 +62,8 @@
 //           - JSMessageObject
 //         - JSProxy
 //           - JSFunctionProxy
-//       - ByteArray
-//       - ExternalArray
-//         - ExternalPixelArray
-//         - ExternalByteArray
-//         - ExternalUnsignedByteArray
-//         - ExternalShortArray
-//         - ExternalUnsignedShortArray
-//         - ExternalIntArray
-//         - ExternalUnsignedIntArray
-//         - ExternalFloatArray
 //       - FixedArrayBase
+//         - ByteArray
 //         - FixedArray
 //           - DescriptorArray
 //           - HashTable
@@ -85,6 +76,15 @@
 //           - JSFunctionResultCache
 //           - SerializedScopeInfo
 //         - FixedDoubleArray
+//         - ExternalArray
+//           - ExternalPixelArray
+//           - ExternalByteArray
+//           - ExternalUnsignedByteArray
+//           - ExternalShortArray
+//           - ExternalUnsignedShortArray
+//           - ExternalIntArray
+//           - ExternalUnsignedIntArray
+//           - ExternalFloatArray
 //       - String
 //         - SeqString
 //           - SeqAsciiString
@@ -2084,6 +2084,7 @@
   static const int kHeaderSize = kLengthOffset + kPointerSize;
 };

+
 class FixedDoubleArray;

 // FixedArray describes fixed-sized arrays with element type Object*.
@@ -3053,12 +3054,8 @@
// ByteArray represents fixed sized byte arrays. Used by the outside world,
 // such as PCRE, and also by the memory allocator and garbage collector to
 // fill in free blocks in the heap.
-class ByteArray: public HeapObject {
+class ByteArray: public FixedArrayBase {
  public:
-  // [length]: length of the array.
-  inline int length();
-  inline void set_length(int value);
-
   // Setter and getter.
   inline byte get(int index);
   inline void set(int index, byte value);
@@ -3103,10 +3100,6 @@
 #endif

   // Layout description.
-  // Length is smi tagged when it is stored.
-  static const int kLengthOffset = HeapObject::kHeaderSize;
-  static const int kHeaderSize = kLengthOffset + kPointerSize;
-
   static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);

   // Maximal memory consumption for a single ByteArray.
@@ -3130,11 +3123,8 @@
 // Out-of-range values passed to the setter are converted via a C
 // cast, not clamping. Out-of-range indices cause exceptions to be
 // raised rather than being silently ignored.
-class ExternalArray: public HeapObject {
+class ExternalArray: public FixedArrayBase {
  public:
-  // [length]: length of the array.
-  inline int length();
-  inline void set_length(int value);

   inline bool is_the_hole(int index) { return false; }

@@ -3149,9 +3139,8 @@
   static const int kMaxLength = 0x3fffffff;

   // ExternalArray headers are not quadword aligned.
-  static const int kLengthOffset = HeapObject::kHeaderSize;
   static const int kExternalPointerOffset =
-      POINTER_SIZE_ALIGN(kLengthOffset + kIntSize);
+      POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize);
   static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
   static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);

=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Aug 11 00:22:16 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Aug 11 07:00:16 2011
@@ -1216,17 +1216,10 @@
 }


-void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
+void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
   Register result = ToRegister(instr->result());
   Register array = ToRegister(instr->InputAt(0));
-  __ movq(result, FieldOperand(array, FixedArray::kLengthOffset));
-}
-
-
-void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
-  Register result = ToRegister(instr->result());
-  Register array = ToRegister(instr->InputAt(0));
-  __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset));
+  __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Thu Aug 11 00:22:16 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Thu Aug 11 07:00:16 2011
@@ -1498,16 +1498,10 @@
 }


-LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
+LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
+    HFixedArrayBaseLength* instr) {
   LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LFixedArrayLength(array));
-}
-
-
-LInstruction* LChunkBuilder::DoExternalArrayLength(
-    HExternalArrayLength* instr) {
-  LOperand* array = UseRegisterAtStart(instr->value());
-  return DefineAsRegister(new LExternalArrayLength(array));
+  return DefineAsRegister(new LFixedArrayBaseLength(array));
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Tue Jul 19 06:04:00 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Thu Aug 11 07:00:16 2011
@@ -92,8 +92,7 @@
   V(DivI)                                       \
   V(DoubleToI)                                  \
   V(ElementsKind)                               \
-  V(ExternalArrayLength)                        \
-  V(FixedArrayLength)                           \
+  V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
   V(GlobalObject)                               \
@@ -913,25 +912,15 @@
 };


-class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
+class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
  public:
-  explicit LExternalArrayLength(LOperand* value) {
+  explicit LFixedArrayBaseLength(LOperand* value) {
     inputs_[0] = value;
   }

- DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
-};
-
-
-class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
- public:
-  explicit LFixedArrayLength(LOperand* value) {
-    inputs_[0] = value;
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
-  DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
+  DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
+                               "fixed-array-base-length")
+  DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
 };


=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Aug 2 06:36:38 2011 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Aug 11 07:00:16 2011
@@ -3243,8 +3243,7 @@

   // Check that the index is in range.
   __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
-  __ SmiToInteger32(rcx, rax);
-  __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
+  __ cmpl(rax, FieldOperand(rbx, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &miss_force_generic);

@@ -3256,29 +3255,31 @@
   // rbx: base pointer of external storage
   switch (elements_kind) {
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
+      __ SmiToInteger32(rcx, rax);
       __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
       break;
     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+      __ SmiToInteger32(rcx, rax);
       __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
       break;
     case JSObject::EXTERNAL_SHORT_ELEMENTS:
-      __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
+      __ movsxwq(rcx, Operand(rbx, rax, times_1, 0));
       break;
     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-      __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
+      __ movzxwq(rcx, Operand(rbx, rax, times_1, 0));
       break;
     case JSObject::EXTERNAL_INT_ELEMENTS:
-      __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
+      __ movsxlq(rcx, Operand(rbx, rax, times_2, 0));
       break;
     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-      __ movl(rcx, Operand(rbx, rcx, times_4, 0));
+      __ movl(rcx, Operand(rbx, rax, times_2, 0));
       break;
     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
-      __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
+      __ cvtss2sd(xmm0, Operand(rbx, rax, times_2, 0));
       break;
     case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
-      __ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
+      __ movsd(xmm0, Operand(rbx, rax, times_4, 0));
       break;
     default:
       UNREACHABLE();
@@ -3378,8 +3379,7 @@

   // Check that the index is in range.
   __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
-  __ SmiToInteger32(rdi, rcx);  // Untag the index.
-  __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
+  __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &miss_force_generic);

@@ -3389,7 +3389,6 @@
   // rcx: key (a smi)
   // rdx: receiver (a JSObject)
   // rbx: elements array
-  // rdi: untagged key
   Label check_heap_number;
   if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Float to pixel conversion is only implemented in the runtime for now.
@@ -3403,37 +3402,32 @@
   // rbx: base pointer of external storage
   switch (elements_kind) {
     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
-      {  // Clamp the value to [0..255].
-        Label done;
-        __ testl(rdx, Immediate(0xFFFFFF00));
-        __ j(zero, &done, Label::kNear);
-        __ setcc(negative, rdx);  // 1 if negative, 0 if positive.
-        __ decb(rdx);  // 0 if negative, 255 if positive.
-        __ bind(&done);
-      }
+      __ ClampUint8(rdx);
+      __ SmiToInteger32(rdi, rcx);
       __ movb(Operand(rbx, rdi, times_1, 0), rdx);
       break;
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+      __ SmiToInteger32(rdi, rcx);
       __ movb(Operand(rbx, rdi, times_1, 0), rdx);
       break;
     case JSObject::EXTERNAL_SHORT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-      __ movw(Operand(rbx, rdi, times_2, 0), rdx);
+      __ movw(Operand(rbx, rcx, times_1, 0), rdx);
       break;
     case JSObject::EXTERNAL_INT_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
-      __ movl(Operand(rbx, rdi, times_4, 0), rdx);
+      __ movl(Operand(rbx, rcx, times_2, 0), rdx);
       break;
     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
       // Need to perform int-to-float conversion.
       __ cvtlsi2ss(xmm0, rdx);
-      __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
+      __ movss(Operand(rbx, rcx, times_2, 0), xmm0);
       break;
     case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
       // Need to perform int-to-float conversion.
       __ cvtlsi2sd(xmm0, rdx);
-      __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
+      __ movsd(Operand(rbx, rcx, times_4, 0), xmm0);
       break;
     case JSObject::FAST_ELEMENTS:
     case JSObject::FAST_DOUBLE_ELEMENTS:
@@ -3451,7 +3445,6 @@
     // rcx: key (a smi)
     // rdx: receiver (a JSObject)
     // rbx: elements array
-    // rdi: untagged key
     __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
     __ j(not_equal, &slow);
     // No more branches to slow case on this path.
@@ -3461,15 +3454,15 @@
     // reproducible behavior, convert these to zero.
     __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
     __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
-    // rdi: untagged index
     // rbx: base pointer of external storage
+    // rcx: key
     // top of FPU stack: value
     if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
       __ cvtsd2ss(xmm0, xmm0);
-      __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
+      __ movss(Operand(rbx, rcx, times_2, 0), xmm0);
       __ ret(0);
     } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
-      __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
+      __ movsd(Operand(rbx, rcx, times_4, 0), xmm0);
       __ ret(0);
     } else {
       // Perform float-to-int conversion with truncation (round-to-zero)
@@ -3482,24 +3475,31 @@
       // rdi: untagged index
       // rbx: base pointer of external storage
       switch (elements_kind) {
+        case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+          __ ClampUint8(rdx);
+          __ cvttsd2si(rdx, xmm0);
+          __ SmiToInteger32(rdi, rcx);
+          __ movb(Operand(rbx, rdi, times_1, 0), rdx);
+          break;
         case JSObject::EXTERNAL_BYTE_ELEMENTS:
         case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
           __ cvttsd2si(rdx, xmm0);
+          __ SmiToInteger32(rdi, rcx);
           __ movb(Operand(rbx, rdi, times_1, 0), rdx);
           break;
         case JSObject::EXTERNAL_SHORT_ELEMENTS:
         case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
           __ cvttsd2si(rdx, xmm0);
-          __ movw(Operand(rbx, rdi, times_2, 0), rdx);
+          __ SmiToInteger32(rdi, rcx);
+          __ movw(Operand(rbx, rcx, times_1, 0), rdx);
           break;
         case JSObject::EXTERNAL_INT_ELEMENTS:
         case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
           // Convert to int64, so that NaN and infinities become
           // 0x8000000000000000, which is zero mod 2^32.
           __ cvttsd2siq(rdx, xmm0);
-          __ movl(Operand(rbx, rdi, times_4, 0), rdx);
+          __ movl(Operand(rbx, rcx, times_2, 0), rdx);
           break;
-        case JSObject::EXTERNAL_PIXEL_ELEMENTS:
         case JSObject::EXTERNAL_FLOAT_ELEMENTS:
         case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
         case JSObject::FAST_ELEMENTS:
=======================================
--- /branches/bleeding_edge/test/mjsunit/external-array.js Thu May 26 05:07:22 2011 +++ /branches/bleeding_edge/test/mjsunit/external-array.js Thu Aug 11 07:00:16 2011
@@ -189,10 +189,20 @@
   %DeoptimizeFunction(test_func);
   gc();  // Makes V8 forget about type information for test_func.
 }
+
+function run_bounds_test(test_func, array, expected_result) {
+  assertEquals(undefined, a[kElementCount]);
+  a[kElementCount] = 456;
+  assertEquals(undefined, a[kElementCount]);
+  assertEquals(undefined, a[kElementCount+1]);
+  a[kElementCount+1] = 456;
+  assertEquals(undefined, a[kElementCount+1]);
+}

 for (var t = 0; t < types.length; t++) {
   var type = types[t];
   var a = new type(kElementCount);
+
   for (var i = 0; i < kElementCount; i++) {
     a[i] = i;
   }
@@ -220,6 +230,16 @@
     assertTrue(delete a.length);
     a.length = 2;
     assertEquals(2, a.length);
+
+    // Make sure bounds checks are handled correctly for external arrays.
+    run_bounds_test(a);
+    run_bounds_test(a);
+    run_bounds_test(a);
+    %OptimizeFunctionOnNextCall(run_bounds_test);
+    run_bounds_test(a);
+    %DeoptimizeFunction(run_bounds_test);
+    gc();  // Makes V8 forget about type information for test_func.
+
   }

   function array_load_set_smi_check(a) {

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

Reply via email to