}
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+ HStorePixelArrayElement* instr) {
+ Abort("DoStorePixelArrayElement not implemented");
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* obj = UseFixed(instr->object(), r2);
LOperand* key = UseFixed(instr->key(), r1);
case kTagged: return "t";
case kDouble: return "d";
case kInteger32: return "i";
- default:
+ case kExternal: return "x";
+ case kNumRepresentations:
UNREACHABLE();
return NULL;
}
+ UNREACHABLE();
+ return NULL;
}
}
+void HStorePixelArrayElement::PrintDataTo(StringStream* stream) const {
+ external_pointer()->PrintNameTo(stream);
+ stream->Add("[");
+ key()->PrintNameTo(stream);
+ stream->Add("] = ");
+ value()->PrintNameTo(stream);
+}
+
+
void HLoadGlobal::PrintDataTo(StringStream* stream) const {
stream->Add("[%p]", *cell());
if (check_hole_value()) stream->Add(" (deleteable/read-only)");
V(StoreContextSlot) \
V(StoreGlobal) \
V(StoreKeyedFastElement) \
+ V(StorePixelArrayElement) \
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
};
+class HStorePixelArrayElement: public HInstruction {
+ public:
+ HStorePixelArrayElement(HValue* external_elements, HValue* key, HValue* val) {
+ SetFlag(kChangesPixelArrayElements);
+ SetOperandAt(0, external_elements);
+ SetOperandAt(1, key);
+ SetOperandAt(2, val);
+ }
+
+ virtual void PrintDataTo(StringStream* stream) const;
+ virtual int OperandCount() const { return operands_.length(); }
+ virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ if (index == 0) {
+ return Representation::External();
+ } else {
+ return Representation::Integer32();
+ }
+ }
+
+ HValue* external_pointer() const { return operands_[0]; }
+ HValue* key() const { return operands_[1]; }
+ HValue* value() const { return operands_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+ "store_pixel_array_element")
+
+ protected:
+ virtual void InternalSetOperandAt(int index, HValue* value) {
+ operands_[index] = value;
+ }
+
+ HOperandVector<3> operands_;
+};
+
+
class HStoreKeyedGeneric: public HStoreKeyed {
public:
HStoreKeyedGeneric(HValue* context,
HValue* key = Pop();
HValue* object = Pop();
- bool is_fast_elements = expr->IsMonomorphic() &&
- expr->GetMonomorphicReceiverType()->has_fast_elements();
-
- instr = is_fast_elements
- ? BuildStoreKeyedFastElement(object, key, value, expr)
- : BuildStoreKeyedGeneric(object, key, value);
+ 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 = BuildStoreKeyedPixelArrayElement(object, key, value, expr);
+ } else if (receiver_type->has_fast_elements()) {
+ instr = BuildStoreKeyedFastElement(object, key, value, expr);
+ }
+ }
+ if (instr == NULL) {
+ instr = BuildStoreKeyedGeneric(object, key, value);
+ }
}
Push(value);
AddInstruction(new HCheckMap(object, map));
HLoadElements* elements = new HLoadElements(object);
AddInstruction(elements);
- HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+ HInstruction* length = new HPixelArrayLength(elements);
+ AddInstruction(length);
AddInstruction(new HBoundsCheck(key, length));
HLoadPixelArrayExternalPointer* external_elements =
new HLoadPixelArrayExternalPointer(elements);
}
+HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr) {
+ ASSERT(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);
+ return new HStorePixelArrayElement(external_elements, key, val);
+}
+
+
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
HValue* val,
Expression* expr);
+ HInstruction* BuildStoreKeyedPixelArrayElement(HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr);
+
HCompare* BuildSwitchCompare(HSubgraph* subgraph,
HValue* switch_value,
CaseClause* clause);
void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
- Register external_elements = ToRegister(instr->external_pointer());
+ Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
Register result = ToRegister(instr->result());
- ASSERT(result.is(external_elements));
+ ASSERT(result.is(external_pointer));
// Load the result.
- __ movzx_b(result, Operand(external_elements, key, times_1, 0));
+ __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
}
}
+void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+ Register external_pointer = ToRegister(instr->external_pointer());
+ Register key = ToRegister(instr->key());
+ Register value = ToRegister(instr->value());
+ ASSERT(ToRegister(instr->TempAt(0)).is(eax));
+
+ __ mov(eax, value);
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ test(eax, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, eax); // 1 if negative, 0 if positive.
+ __ dec_b(eax); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+ __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
+}
+
+
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
Register value = ToRegister(instr->value());
Register elements = ToRegister(instr->object());
}
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+ HStorePixelArrayElement* instr) {
+ ASSERT(instr->value()->representation().IsInteger32());
+ ASSERT(instr->external_pointer()->representation().IsExternal());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* val = UseRegister(instr->value());
+ LOperand* key = UseRegister(instr->key());
+ // The generated code requires that the clamped value is in a byte
+ // register. eax is an arbitrary choice to satisfy this requirement.
+ LOperand* clamped = FixedTemp(eax);
+
+ return new LStorePixelArrayElement(external_pointer, key, val, clamped);
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), edx);
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
+ V(StorePixelArrayElement) \
V(StringCharCodeAt) \
V(StringLength) \
V(SubI) \
};
+class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 1> {
+ public:
+ LStorePixelArrayElement(LOperand* external_pointer,
+ LOperand* key,
+ LOperand* val,
+ LOperand* clamped) {
+ inputs_[0] = external_pointer;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ temps_[0] = clamped;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+ "store-pixel-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+
+ LOperand* external_pointer() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+};
+
+
class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 0> {
public:
LStoreKeyedGeneric(LOperand* context,
}
+void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
+ Register external_pointer = ToRegister(instr->external_pointer());
+ Register key = ToRegister(instr->key());
+ Register value = ToRegister(instr->value());
+
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ testl(value, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, value); // 1 if negative, 0 if positive.
+ __ decb(value); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+
+ __ movb(Operand(external_pointer, key, times_1, 0), value);
+}
+
+
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
if (instr->length()->IsRegister()) {
__ cmpq(ToRegister(instr->index()), ToRegister(instr->length()));
}
+LInstruction* LChunkBuilder::DoStorePixelArrayElement(
+ HStorePixelArrayElement* instr) {
+ ASSERT(instr->value()->representation().IsInteger32());
+ ASSERT(instr->external_pointer()->representation().IsExternal());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* external_pointer = UseRegister(instr->external_pointer());
+ LOperand* val = UseTempRegister(instr->value());
+ LOperand* key = UseRegister(instr->key());
+
+ return new LStorePixelArrayElement(external_pointer, key, val);
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
return NULL;
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
+ V(StorePixelArrayElement) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
};
+class LStorePixelArrayElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+ LStorePixelArrayElement(LOperand* external_pointer,
+ LOperand* key,
+ LOperand* val) {
+ inputs_[0] = external_pointer;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StorePixelArrayElement,
+ "store-pixel-array-element")
+ DECLARE_HYDROGEN_ACCESSOR(StorePixelArrayElement)
+
+ LOperand* external_pointer() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+};
+
+
class LStoreKeyedGeneric: public LStoreKeyed {
public:
LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val)
"result");
CHECK_EQ(32640, result->Int32Value());
+ // Make sure that pixel array stores are optimized by crankshaft.
+ result = CompileRun("function pa_init(p) {"
+ "for (var i = 0; i < 256; ++i) { p[i] = i; }"
+ "}"
+ "function pa_load(p) {"
+ " var sum = 0;"
+ " for (var i=0; i<256; ++i) {"
+ " sum += p[i];"
+ " }"
+ " return sum; "
+ "}"
+ "for (var i = 0; i < 100000; ++i) {"
+ " pa_init(pixels);"
+ "}"
+ "result = pa_load(pixels);"
+ "result");
+ CHECK_EQ(32640, result->Int32Value());
+
free(pixel_data);
}