Revision: 6725
Author: [email protected]
Date: Thu Feb 10 04:02:36 2011
Log: Implement crankshaft support for pixel array loads.

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

Modified:
 /branches/bleeding_edge/src/api.cc
 /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/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /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/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/v8-counters.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/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/src/api.cc  Wed Feb  9 11:09:26 2011
+++ /branches/bleeding_edge/src/api.cc  Thu Feb 10 04:02:36 2011
@@ -2757,9 +2757,9 @@
     return;
   }
i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
-  i::Handle<i::Map> slow_map =
-      i::Factory::GetSlowElementsMap(i::Handle<i::Map>(self->map()));
-  self->set_map(*slow_map);
+  i::Handle<i::Map> pixel_array_map =
+      i::Factory::GetPixelArrayElementsMap(i::Handle<i::Map>(self->map()));
+  self->set_map(*pixel_array_map);
   self->set_elements(*pixels);
 }

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Thu Feb 10 02:31:55 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Thu Feb 10 04:02:36 2011
@@ -1498,6 +1498,12 @@
   LOperand* array = UseRegisterAtStart(instr->value());
   return DefineAsRegister(new LJSArrayLength(array));
 }
+
+
+LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LPixelArrayLength(array));
+}


 LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
@@ -1714,7 +1720,14 @@

 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
   LOperand* input = UseRegisterAtStart(instr->value());
-  return DefineSameAsFirst(new LLoadElements(input));
+  return DefineAsRegister(new LLoadElements(input));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
+    HLoadPixelArrayExternalPointer* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
 }


@@ -1727,6 +1740,19 @@
   LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
   return AssignEnvironment(DefineSameAsFirst(result));
 }
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
+    HLoadPixelArrayElement* instr) {
+  ASSERT(instr->representation().IsInteger32());
+  ASSERT(instr->key()->representation().IsInteger32());
+  LOperand* external_pointer =
+      UseRegisterAtStart(instr->external_pointer());
+  LOperand* key = UseRegisterAtStart(instr->key());
+  LLoadPixelArrayElement* result =
+      new LLoadPixelArrayElement(external_pointer, key);
+  return DefineAsRegister(result);
+}


 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Tue Feb  8 02:45:21 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Thu Feb 10 04:02:36 2011
@@ -122,6 +122,8 @@
   V(LoadKeyedGeneric)                           \
   V(LoadNamedField)                             \
   V(LoadNamedGeneric)                           \
+  V(LoadPixelArrayElement)                      \
+  V(LoadPixelArrayExternalPointer)              \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -131,6 +133,7 @@
   V(OsrEntry)                                   \
   V(OuterContext)                               \
   V(Parameter)                                  \
+  V(PixelArrayLength)                           \
   V(PushArgument)                               \
   V(RegExpLiteral)                              \
   V(Return)                                     \
@@ -977,6 +980,17 @@
 };


+class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LPixelArrayLength(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+};
+
+
 class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LFixedArrayLength(LOperand* value) {
@@ -1126,6 +1140,17 @@
 };


+class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
+                               "load-pixel-array-external-pointer")
+};
+
+
 class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
  public:
   LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
@@ -1141,6 +1166,22 @@
 };


+class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+    inputs_[0] = external_pointer;
+    inputs_[1] = key;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
+                               "load-pixel-array-element")
+  DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+
+  LOperand* external_pointer() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+};
+
+
 class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
  public:
   LLoadKeyedGeneric(LOperand* obj, LOperand* key) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Feb 9 06:57:24 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Feb 10 04:02:36 2011
@@ -1320,6 +1320,13 @@
   Register array = ToRegister(instr->InputAt(0));
   __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
 }
+
+
+void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->InputAt(0));
+  __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset));
+}


 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
@@ -2354,23 +2361,34 @@


 void LCodeGen::DoLoadElements(LLoadElements* instr) {
-  ASSERT(instr->result()->Equals(instr->InputAt(0)));
-  Register reg = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  Register input = ToRegister(instr->InputAt(0));
   Register scratch = scratch0();

-  __ ldr(reg, FieldMemOperand(reg, JSObject::kElementsOffset));
+  __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
   if (FLAG_debug_code) {
     Label done;
-    __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
+    __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
     __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
     __ cmp(scratch, ip);
     __ b(eq, &done);
+    __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
+    __ cmp(scratch, ip);
+    __ b(eq, &done);
     __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
     __ cmp(scratch, ip);
     __ Check(eq, "Check for fast elements failed.");
     __ bind(&done);
   }
 }
+
+
+void LCodeGen::DoLoadPixelArrayExternalPointer(
+    LLoadPixelArrayExternalPointer* instr) {
+  Register to_reg = ToRegister(instr->result());
+  Register from_reg  = ToRegister(instr->InputAt(0));
+ __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset));
+}


 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
@@ -2407,6 +2425,16 @@
   __ cmp(result, scratch);
   DeoptimizeIf(eq, instr->environment());
 }
+
+
+void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
+  Register external_elements = ToRegister(instr->external_pointer());
+  Register key = ToRegister(instr->key());
+  Register result = ToRegister(instr->result());
+
+  // Load the result.
+  __ ldrb(result, MemOperand(external_elements, key));
+}


 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/factory.cc      Wed Feb  2 05:31:52 2011
+++ /branches/bleeding_edge/src/factory.cc      Thu Feb 10 04:02:36 2011
@@ -332,6 +332,11 @@
 Handle<Map> Factory::GetSlowElementsMap(Handle<Map> src) {
   CALL_HEAP_FUNCTION(src->GetSlowElementsMap(), Map);
 }
+
+
+Handle<Map> Factory::GetPixelArrayElementsMap(Handle<Map> src) {
+  CALL_HEAP_FUNCTION(src->GetPixelArrayElementsMap(), Map);
+}


 Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
=======================================
--- /branches/bleeding_edge/src/factory.h       Wed Feb  2 05:31:52 2011
+++ /branches/bleeding_edge/src/factory.h       Thu Feb 10 04:02:36 2011
@@ -196,6 +196,8 @@

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

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

   // Numbers (eg, literals) are pretenured by the parser.
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Thu Feb 10 01:00:50 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Thu Feb 10 04:02:36 2011
@@ -1233,6 +1233,14 @@
   key()->PrintNameTo(stream);
   stream->Add("]");
 }
+
+
+void HLoadPixelArrayElement::PrintDataTo(StringStream* stream) const {
+  external_pointer()->PrintNameTo(stream);
+  stream->Add("[");
+  key()->PrintNameTo(stream);
+  stream->Add("]");
+}


 void HStoreNamed::PrintDataTo(StringStream* stream) const {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Thu Feb 10 01:00:50 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Thu Feb 10 04:02:36 2011
@@ -127,12 +127,15 @@
   V(LoadKeyedGeneric)                          \
   V(LoadNamedField)                            \
   V(LoadNamedGeneric)                          \
+  V(LoadPixelArrayElement)                     \
+  V(LoadPixelArrayExternalPointer)             \
   V(Mod)                                       \
   V(Mul)                                       \
   V(ObjectLiteral)                             \
   V(OsrEntry)                                  \
   V(OuterContext)                              \
   V(Parameter)                                 \
+  V(PixelArrayLength)                          \
   V(Power)                                     \
   V(PushArgument)                              \
   V(RegExpLiteral)                             \
@@ -164,6 +167,7 @@
   V(InobjectFields)                            \
   V(BackingStoreFields)                        \
   V(ArrayElements)                             \
+  V(PixelArrayElements)                        \
   V(GlobalVars)                                \
   V(Maps)                                      \
   V(ArrayLengths)                              \
@@ -289,6 +293,7 @@
     kTagged,
     kDouble,
     kInteger32,
+    kExternal,
     kNumRepresentations
   };

@@ -298,6 +303,7 @@
   static Representation Tagged() { return Representation(kTagged); }
   static Representation Integer32() { return Representation(kInteger32); }
   static Representation Double() { return Representation(kDouble); }
+  static Representation External() { return Representation(kExternal); }

   bool Equals(const Representation& other) const {
     return kind_ == other.kind_;
@@ -308,6 +314,7 @@
   bool IsTagged() const { return kind_ == kTagged; }
   bool IsInteger32() const { return kind_ == kInteger32; }
   bool IsDouble() const { return kind_ == kDouble; }
+  bool IsExternal() const { return kind_ == kExternal; }
   bool IsSpecialization() const {
     return kind_ == kInteger32 || kind_ == kDouble;
   }
@@ -1418,6 +1425,27 @@
 };


+class HPixelArrayLength: public HUnaryOperation {
+ public:
+  explicit HPixelArrayLength(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(PixelArrayLength, "pixel_array_length")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const { return true; }
+};
+
+
 class HBitNot: public HUnaryOperation {
  public:
   explicit HBitNot(HValue* value) : HUnaryOperation(value) {
@@ -1536,6 +1564,30 @@
 };


+class HLoadPixelArrayExternalPointer: public HUnaryOperation {
+ public:
+  explicit HLoadPixelArrayExternalPointer(HValue* value)
+      : HUnaryOperation(value) {
+    set_representation(Representation::External());
+ // The result of this instruction is idempotent as long as its inputs don't
+    // change.  The external array of a pixel array elements object cannot
+    // change once set, so it's no necessary to introduce any additional
+    // dependencies on top of the inputs.
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
+                               "load-pixel-array-external-pointer")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const { return true; }
+};
+
+
 class HCheckMap: public HUnaryOperation {
  public:
   HCheckMap(HValue* value, Handle<Map> map)
@@ -2952,6 +3004,37 @@
 };


+class HLoadPixelArrayElement: public HBinaryOperation {
+ public:
+  HLoadPixelArrayElement(HValue* external_elements, HValue* key)
+      : HBinaryOperation(external_elements, key) {
+    set_representation(Representation::Integer32());
+    SetFlag(kDependsOnPixelArrayElements);
+    // Native code could change the pixel array.
+    SetFlag(kDependsOnCalls);
+    SetFlag(kUseGVN);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    // The key is supposed to be Integer32, but the base pointer
+    // for the element load is a naked pointer.
+    return (index == 1) ? Representation::Integer32()
+        : Representation::External();
+  }
+
+  HValue* external_pointer() const { return OperandAt(0); }
+  HValue* key() const { return OperandAt(1); }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
+                               "load_pixel_array_element")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const { return true; }
+};
+
+
 class HLoadKeyedGeneric: public HLoadKeyed {
  public:
   HLoadKeyedGeneric(HContext* context, HValue* obj, HValue* key)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu Feb 10 02:28:59 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Thu Feb 10 04:02:36 2011
@@ -3741,6 +3741,28 @@
   }
   return new HLoadKeyedFastElement(elements, key);
 }
+
+
+HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
+                                                             HValue* key,
+ Property* expr) {
+  ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
+  AddInstruction(new HCheckNonSmi(object));
+  Handle<Map> map = expr->GetMonomorphicReceiverType();
+  ASSERT(!map->has_fast_elements());
+  ASSERT(map->has_pixel_array_elements());
+  AddInstruction(new HCheckMap(object, map));
+  HLoadElements* elements = new HLoadElements(object);
+  AddInstruction(elements);
+  HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+  AddInstruction(new HBoundsCheck(key, length));
+  HLoadPixelArrayExternalPointer* external_elements =
+      new HLoadPixelArrayExternalPointer(elements);
+  AddInstruction(external_elements);
+  HLoadPixelArrayElement* pixel_array_value =
+      new HLoadPixelArrayElement(external_elements, key);
+  return pixel_array_value;
+}


 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
@@ -3852,12 +3874,20 @@
     HValue* key = Pop();
     HValue* obj = Pop();

-    bool is_fast_elements = expr->IsMonomorphic() &&
-        expr->GetMonomorphicReceiverType()->has_fast_elements();
-
-    instr = is_fast_elements
-        ? BuildLoadKeyedFastElement(obj, key, expr)
-        : BuildLoadKeyedGeneric(obj, key);
+    if (expr->IsMonomorphic()) {
+      Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
+ // An object has either fast elements or pixel array elements, but never + // both. Pixel array maps that are assigned to pixel array elements are
+      // always created with the fast elements flag cleared.
+      if (receiver_type->has_pixel_array_elements()) {
+        instr = BuildLoadKeyedPixelArrayElement(obj, key, expr);
+      } else if (receiver_type->has_fast_elements()) {
+        instr = BuildLoadKeyedFastElement(obj, key, expr);
+      }
+    }
+    if (instr == NULL) {
+      instr = BuildLoadKeyedGeneric(obj, key);
+    }
   }
   instr->set_position(expr->position());
   ast_context()->ReturnInstruction(instr, expr->id());
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Thu Feb  3 05:10:28 2011
+++ /branches/bleeding_edge/src/hydrogen.h      Thu Feb 10 04:02:36 2011
@@ -791,6 +791,9 @@
   HInstruction* BuildLoadKeyedFastElement(HValue* object,
                                           HValue* key,
                                           Property* expr);
+  HInstruction* BuildLoadKeyedPixelArrayElement(HValue* object,
+                                                HValue* key,
+                                                Property* expr);
   HInstruction* BuildLoadKeyedGeneric(HValue* object,
                                       HValue* key);

=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Feb 10 01:00:50 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Feb 10 04:02:36 2011
@@ -1000,6 +1000,13 @@
   Register array = ToRegister(instr->InputAt(0));
   __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
 }
+
+
+void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->InputAt(0));
+  __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
+}


 void LCodeGen::DoValueOf(LValueOf* instr) {
@@ -2024,20 +2031,31 @@


 void LCodeGen::DoLoadElements(LLoadElements* instr) {
-  ASSERT(instr->result()->Equals(instr->InputAt(0)));
-  Register reg = ToRegister(instr->InputAt(0));
-  __ mov(reg, FieldOperand(reg, JSObject::kElementsOffset));
+  Register result = ToRegister(instr->result());
+  Register input = ToRegister(instr->InputAt(0));
+  __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
   if (FLAG_debug_code) {
     NearLabel done;
-    __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
+    __ cmp(FieldOperand(result, HeapObject::kMapOffset),
            Immediate(Factory::fixed_array_map()));
     __ j(equal, &done);
-    __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
+    __ cmp(FieldOperand(result, HeapObject::kMapOffset),
+           Immediate(Factory::pixel_array_map()));
+    __ j(equal, &done);
+    __ cmp(FieldOperand(result, HeapObject::kMapOffset),
            Immediate(Factory::fixed_cow_array_map()));
-    __ Check(equal, "Check for fast elements failed.");
+    __ Check(equal, "Check for fast elements or pixel array failed.");
     __ bind(&done);
   }
 }
+
+
+void LCodeGen::DoLoadPixelArrayExternalPointer(
+    LLoadPixelArrayExternalPointer* instr) {
+  Register result = ToRegister(instr->result());
+  Register input = ToRegister(instr->InputAt(0));
+  __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
+}


 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
@@ -2071,6 +2089,17 @@
   __ cmp(result, Factory::the_hole_value());
   DeoptimizeIf(equal, instr->environment());
 }
+
+
+void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
+  Register external_elements = ToRegister(instr->external_pointer());
+  Register key = ToRegister(instr->key());
+  Register result = ToRegister(instr->result());
+  ASSERT(result.is(external_elements));
+
+  // Load the result.
+  __ movzx_b(result, Operand(external_elements, key, times_1, 0));
+}


 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Feb 10 02:31:55 2011 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Feb 10 04:02:36 2011
@@ -1548,6 +1548,12 @@
   LOperand* array = UseRegisterAtStart(instr->value());
   return DefineAsRegister(new LFixedArrayLength(array));
 }
+
+
+LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LPixelArrayLength(array));
+}


 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
@@ -1763,7 +1769,14 @@

 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
   LOperand* input = UseRegisterAtStart(instr->value());
-  return DefineSameAsFirst(new LLoadElements(input));
+  return DefineAsRegister(new LLoadElements(input));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
+    HLoadPixelArrayExternalPointer* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
 }


@@ -1776,6 +1789,19 @@
   LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
   return AssignEnvironment(DefineSameAsFirst(result));
 }
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
+    HLoadPixelArrayElement* instr) {
+  ASSERT(instr->representation().IsInteger32());
+  ASSERT(instr->key()->representation().IsInteger32());
+  LOperand* external_pointer =
+      UseRegisterAtStart(instr->external_pointer());
+  LOperand* key = UseRegisterAtStart(instr->key());
+  LLoadPixelArrayElement* result =
+      new LLoadPixelArrayElement(external_pointer, key);
+  return DefineSameAsFirst(result);
+}


 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Feb 10 01:00:50 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Feb 10 04:02:36 2011
@@ -124,6 +124,8 @@
   V(LoadKeyedGeneric)                           \
   V(LoadNamedField)                             \
   V(LoadNamedGeneric)                           \
+  V(LoadPixelArrayElement)                      \
+  V(LoadPixelArrayExternalPointer)              \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -133,6 +135,7 @@
   V(OsrEntry)                                   \
   V(OuterContext)                               \
   V(Parameter)                                  \
+  V(PixelArrayLength)                           \
   V(Power)                                      \
   V(PushArgument)                               \
   V(RegExpLiteral)                              \
@@ -1022,6 +1025,17 @@
 };


+class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LPixelArrayLength(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+};
+
+
 class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LFixedArrayLength(LOperand* value) {
@@ -1186,6 +1200,17 @@
 };


+class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
+                               "load-pixel-array-external-pointer")
+};
+
+
 class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
  public:
   LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
@@ -1201,6 +1226,22 @@
 };


+class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+    inputs_[0] = external_pointer;
+    inputs_[1] = key;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
+                               "load-pixel-array-element")
+  DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+
+  LOperand* external_pointer() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+};
+
+
 class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> {
  public:
   LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Thu Feb 10 04:02:36 2011
@@ -2745,6 +2745,22 @@
   Counters::map_fast_to_slow_elements.Increment();
   return new_map;
 }
+
+
+MaybeObject* Map::GetPixelArrayElementsMap() {
+  if (has_pixel_array_elements()) return this;
+  // TODO(danno): Special case empty object map (or most common case)
+  // to return a pre-canned pixel array map.
+  Object* obj;
+  { MaybeObject* maybe_obj = CopyDropTransitions();
+    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+  }
+  Map* new_map = Map::cast(obj);
+  new_map->set_has_fast_elements(false);
+  new_map->set_has_pixel_array_elements(true);
+  Counters::map_to_pixel_array_elements.Increment();
+  return new_map;
+}


 ACCESSORS(Map, instance_descriptors, DescriptorArray,
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Feb  8 11:42:14 2011
+++ /branches/bleeding_edge/src/objects.h       Thu Feb 10 04:02:36 2011
@@ -3592,6 +3592,19 @@
   inline bool has_fast_elements() {
     return ((1 << kHasFastElements) & bit_field2()) != 0;
   }
+
+  // Tells whether an instance has pixel array elements.
+  inline void set_has_pixel_array_elements(bool value) {
+    if (value) {
+      set_bit_field2(bit_field2() | (1 << kHasPixelArrayElements));
+    } else {
+      set_bit_field2(bit_field2() & ~(1 << kHasPixelArrayElements));
+    }
+  }
+
+  inline bool has_pixel_array_elements() {
+    return ((1 << kHasPixelArrayElements) & bit_field2()) != 0;
+  }

   // Tells whether the map is attached to SharedFunctionInfo
   // (for inobject slack tracking).
@@ -3651,6 +3664,11 @@
   // from the descriptors and the fast elements bit cleared.
   MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap();

+ // Returns this map if it has the pixel array elements bit is set, otherwise
+  // returns a copy of the map, with all transitions dropped from the
+  // descriptors and the pixel array elements bit set.
+  MUST_USE_RESULT inline MaybeObject* GetPixelArrayElementsMap();
+
   // Returns the property index for name (only valid for FAST MODE).
   int PropertyIndexFor(String* name);

@@ -3769,6 +3787,7 @@
   static const int kStringWrapperSafeForDefaultValueOf = 3;
   static const int kAttachedToSharedFunctionInfo = 4;
   static const int kIsShared = 5;
+  static const int kHasPixelArrayElements = 6;

// Layout of the default cache. It holds alternating name and code objects.
   static const int kCodeCacheEntrySize = 2;
=======================================
--- /branches/bleeding_edge/src/v8-counters.h   Wed Jan  5 03:17:37 2011
+++ /branches/bleeding_edge/src/v8-counters.h   Thu Feb 10 04:02:36 2011
@@ -128,6 +128,7 @@
   SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles)         \
   SC(map_slow_to_fast_elements, V8.MapSlowToFastElements)             \
   SC(map_fast_to_slow_elements, V8.MapFastToSlowElements)             \
+  SC(map_to_pixel_array_elements, V8.MapToPixelArrayElements)         \
   /* How is the generic keyed-load stub used? */                      \
   SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi)                  \
   SC(keyed_load_generic_symbol, V8.KeyedLoadGenericSymbol)            \
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Feb 9 04:46:22 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Feb 10 04:02:36 2011
@@ -925,6 +925,13 @@
   Register array = ToRegister(instr->InputAt(0));
   __ movq(result, FieldOperand(array, FixedArray::kLengthOffset));
 }
+
+
+void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->InputAt(0));
+  __ movq(result, FieldOperand(array, PixelArray::kLengthOffset));
+}


 void LCodeGen::DoValueOf(LValueOf* instr) {
@@ -1726,20 +1733,31 @@


 void LCodeGen::DoLoadElements(LLoadElements* instr) {
-  ASSERT(instr->result()->Equals(instr->InputAt(0)));
-  Register reg = ToRegister(instr->InputAt(0));
-  __ movq(reg, FieldOperand(reg, JSObject::kElementsOffset));
+  Register result = ToRegister(instr->result());
+  Register input = ToRegister(instr->InputAt(0));
+  __ movq(result, FieldOperand(input, JSObject::kElementsOffset));
   if (FLAG_debug_code) {
     NearLabel done;
-    __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+    __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
            Factory::fixed_array_map());
     __ j(equal, &done);
-    __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+    __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
+           Factory::pixel_array_map());
+    __ j(equal, &done);
+    __ Cmp(FieldOperand(result, HeapObject::kMapOffset),
            Factory::fixed_cow_array_map());
     __ Check(equal, "Check for fast elements failed.");
     __ bind(&done);
   }
 }
+
+
+void LCodeGen::DoLoadPixelArrayExternalPointer(
+    LLoadPixelArrayExternalPointer* instr) {
+  Register result = ToRegister(instr->result());
+  Register input = ToRegister(instr->InputAt(0));
+  __ movq(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
+}


 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
@@ -1763,6 +1781,17 @@
   __ Cmp(result, Factory::the_hole_value());
   DeoptimizeIf(equal, instr->environment());
 }
+
+
+void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
+  Register external_elements = ToRegister(instr->external_pointer());
+  Register key = ToRegister(instr->key());
+  Register result = ToRegister(instr->result());
+  ASSERT(result.is(external_elements));
+
+  // Load the result.
+  __ movzxbq(result, Operand(external_elements, key, times_1, 0));
+}


 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Thu Feb 10 02:31:55 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Thu Feb 10 04:02:36 2011
@@ -1440,6 +1440,12 @@
   LOperand* array = UseRegisterAtStart(instr->value());
   return DefineAsRegister(new LFixedArrayLength(array));
 }
+
+
+LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LPixelArrayLength(array));
+}


 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
@@ -1638,7 +1644,14 @@

 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
   LOperand* input = UseRegisterAtStart(instr->value());
-  return DefineSameAsFirst(new LLoadElements(input));
+  return DefineAsRegister(new LLoadElements(input));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
+    HLoadPixelArrayExternalPointer* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
 }


@@ -1651,6 +1664,19 @@
   LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
   return AssignEnvironment(DefineSameAsFirst(result));
 }
+
+
+LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
+    HLoadPixelArrayElement* instr) {
+  ASSERT(instr->representation().IsInteger32());
+  ASSERT(instr->key()->representation().IsInteger32());
+  LOperand* external_pointer =
+      UseRegisterAtStart(instr->external_pointer());
+  LOperand* key = UseRegisterAtStart(instr->key());
+  LLoadPixelArrayElement* result =
+      new LLoadPixelArrayElement(external_pointer, key);
+  return DefineSameAsFirst(result);
+}


 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Tue Feb  8 06:37:50 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Thu Feb 10 04:02:36 2011
@@ -121,6 +121,8 @@
   V(LoadNamedField)                             \
   V(LoadNamedGeneric)                           \
   V(LoadFunctionPrototype)                      \
+  V(LoadPixelArrayElement)                      \
+  V(LoadPixelArrayExternalPointer)              \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -129,6 +131,7 @@
   V(ObjectLiteral)                              \
   V(OsrEntry)                                   \
   V(Parameter)                                  \
+  V(PixelArrayLength)                           \
   V(Power)                                      \
   V(PushArgument)                               \
   V(RegExpLiteral)                              \
@@ -978,6 +981,17 @@
 };


+class LPixelArrayLength: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LPixelArrayLength(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(PixelArrayLength, "pixel-array-length")
+  DECLARE_HYDROGEN_ACCESSOR(PixelArrayLength)
+};
+
+
 class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LFixedArrayLength(LOperand* value) {
@@ -1140,6 +1154,17 @@
 };


+class LLoadPixelArrayExternalPointer: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadPixelArrayExternalPointer(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayExternalPointer,
+                               "load-pixel-array-external-pointer")
+};
+
+
 class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
  public:
   LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
@@ -1155,6 +1180,22 @@
 };


+class LLoadPixelArrayElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadPixelArrayElement(LOperand* external_pointer, LOperand* key) {
+    inputs_[0] = external_pointer;
+    inputs_[1] = key;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadPixelArrayElement,
+                               "load-pixel-array-element")
+  DECLARE_HYDROGEN_ACCESSOR(LoadPixelArrayElement)
+
+  LOperand* external_pointer() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+};
+
+
 class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
  public:
   LLoadKeyedGeneric(LOperand* obj, LOperand* key) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Wed Feb  9 11:34:04 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Thu Feb 10 04:02:36 2011
@@ -10674,6 +10674,21 @@
                       "result");
   CHECK_EQ(32640, result->Int32Value());

+    // Make sure that pixel array loads are optimized by crankshaft.
+  result = CompileRun("function pa_load(p) {"
+                      "  var sum = 0;"
+                      "  for (var i=0; i<256; ++i) {"
+                      "    sum += p[i];"
+                      "  }"
+                      "  return sum; "
+                      "}"
+                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
+                      "for (var i = 0; i < 10000; ++i) {"
+                      "  result = pa_load(pixels);"
+                      "}"
+                      "result");
+  CHECK_EQ(32640, result->Int32Value());
+
   free(pixel_data);
 }

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

Reply via email to