}
+LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
+ HValue* value = instr->value();
+ Representation input_rep = value->representation();
+ LOperand* reg = UseRegister(value);
+ if (input_rep.IsDouble()) {
+ return DefineAsRegister(new LClampDoubleToUint8(reg, FixedTemp(d1)));
+ } else if (input_rep.IsInteger32()) {
+ return DefineAsRegister(new LClampIToUint8(reg));
+ } else {
+ ASSERT(input_rep.IsTagged());
+ // Register allocator doesn't (yet) support allocation of double
+ // temps. Reserve d1 explicitly.
+ LClampTaggedToUint8* result = new LClampTaggedToUint8(reg, FixedTemp(d1));
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
return new LReturn(UseFixed(instr->value(), r0));
}
V(CheckMap) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClampDoubleToUint8) \
+ V(ClampIToUint8) \
+ V(ClampTaggedToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpID) \
};
+class LClampDoubleToUint8: public LTemplateInstruction<1, 1, 1> {
+ public:
+ explicit LClampDoubleToUint8(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampDoubleToUint8, "clamp-d-to-uint8")
+};
+
+
+class LClampIToUint8: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LClampIToUint8(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
+};
+
+
+class LClampTaggedToUint8: public LTemplateInstruction<1, 1, 1> {
+ public:
+ explicit LClampTaggedToUint8(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampTaggedToUint8, "clamp-t-to-uint8")
+};
+
+
class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
: MemOperand(external_pointer, key, LSL, shift_size));
switch (array_type) {
case kExternalPixelArray:
- // Clamp the value to [0..255].
- __ Usat(value, 8, Operand(value));
- // Fall through to the next case for the store instruction:
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ strb(value, mem_operand);
}
+void LCodeGen::DoClampDoubleToUint8(LClampDoubleToUint8* instr) {
+ DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
+ __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
+}
+
+
+void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+ Register unclamped_reg = ToRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ __ ClampUint8(result_reg, unclamped_reg);
+}
+
+
+void LCodeGen::DoClampTaggedToUint8(LClampTaggedToUint8* instr) {
+ Register scratch = scratch0();
+ Register input_reg = ToRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
+ Label is_smi, done, heap_number;
+
+ // Both smi and heap number cases are handled.
+ __ JumpIfSmi(input_reg, &is_smi);
+
+ // Check for heap number
+ __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+ __ cmp(scratch, Operand(factory()->heap_number_map()));
+ __ b(eq, &heap_number);
+
+ // Check for undefined. Undefined is converted to zero for clamping
+ // conversions.
+ __ cmp(input_reg, Operand(factory()->undefined_value()));
+ DeoptimizeIf(ne, instr->environment());
+ __ movt(input_reg, 0);
+ __ jmp(&done);
+
+ // Heap number
+ __ bind(&heap_number);
+ __ vldr(double_scratch0(), FieldMemOperand(input_reg,
+ HeapNumber::kValueOffset));
+ __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
+ __ jmp(&done);
+
+ // smi
+ __ bind(&is_smi);
+ __ SmiUntag(result_reg, input_reg);
+ __ ClampUint8(result_reg, result_reg);
+
+ __ bind(&done);
+}
+
+
void LCodeGen::LoadHeapObject(Register result,
Handle<HeapObject> object) {
if (heap()->InNewSpace(*object)) {
}
+void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
+ Usat(output_reg, 8, Operand(input_reg));
+}
+
+
+void MacroAssembler::ClampDoubleToUint8(Register result_reg,
+ DoubleRegister input_reg,
+ DoubleRegister temp_double_reg) {
+ Label above_zero;
+ Label done;
+ Label in_bounds;
+
+ vmov(temp_double_reg, 0.0);
+ VFPCompareAndSetFlags(input_reg, temp_double_reg);
+ b(gt, &above_zero);
+
+ // Double value is less than zero, NaN or Inf, return 0.
+ mov(result_reg, Operand(0));
+ b(al, &done);
+
+ // Double value is >= 255, return 255.
+ bind(&above_zero);
+ vmov(temp_double_reg, 255.0);
+ VFPCompareAndSetFlags(input_reg, temp_double_reg);
+ b(le, &in_bounds);
+ mov(result_reg, Operand(255));
+ b(al, &done);
+
+ // In 0-255 range, round and truncate.
+ bind(&in_bounds);
+ vmov(temp_double_reg, 0.5);
+ vadd(temp_double_reg, input_reg, temp_double_reg);
+ vcvt_u32_f64(s0, temp_double_reg);
+ vmov(result_reg, s0);
+ bind(&done);
+}
+
+
CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),
instructions_(instructions),
Register result);
+ void ClampUint8(Register output_reg, Register input_reg);
+
+ void ClampDoubleToUint8(Register result_reg,
+ DoubleRegister input_reg,
+ DoubleRegister temp_double_reg);
+
+
private:
void CallCFunctionHelper(Register function,
ExternalReference function_reference,
const double DoubleConstant::min_int = kMinInt;
const double DoubleConstant::one_half = 0.5;
const double DoubleConstant::minus_zero = -0.0;
+const double DoubleConstant::uint8_max_value = 255;
+const double DoubleConstant::zero = 0.0;
const double DoubleConstant::nan = OS::nan_value();
const double DoubleConstant::negative_infinity = -V8_INFINITY;
const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
}
+ExternalReference ExternalReference::address_of_zero() {
+ return ExternalReference(reinterpret_cast<void*>(
+ const_cast<double*>(&DoubleConstant::zero)));
+}
+
+
+ExternalReference ExternalReference::address_of_uint8_max_value() {
+ return ExternalReference(reinterpret_cast<void*>(
+ const_cast<double*>(&DoubleConstant::uint8_max_value)));
+}
+
+
ExternalReference ExternalReference::address_of_negative_infinity() {
return ExternalReference(reinterpret_cast<void*>(
const_cast<double*>(&DoubleConstant::negative_infinity)));
static const double min_int;
static const double one_half;
static const double minus_zero;
+ static const double zero;
+ static const double uint8_max_value;
static const double negative_infinity;
static const double nan;
};
static ExternalReference address_of_min_int();
static ExternalReference address_of_one_half();
static ExternalReference address_of_minus_zero();
+ static ExternalReference address_of_zero();
+ static ExternalReference address_of_uint8_max_value();
static ExternalReference address_of_negative_infinity();
static ExternalReference address_of_nan();
void HValue::SetOperandAt(int index, HValue* value) {
- ASSERT(value == NULL || !value->representation().IsNone());
RegisterUse(index, value);
InternalSetOperandAt(index, value);
}
ASSERT(cur == other_operand);
}
} else {
+ // If the following assert fires, you may have forgotten an
+ // AddInstruction.
ASSERT(other_block->Dominates(cur_block));
}
}
V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClampToUint8) \
V(ClassOfTest) \
V(Compare) \
V(CompareJSObjectEq) \
Representation representation() const { return representation_; }
void ChangeRepresentation(Representation r) {
// Representation was already set and is allowed to be changed.
- ASSERT(!representation_.IsNone());
ASSERT(!r.IsNone());
ASSERT(CheckFlag(kFlexibleRepresentation));
RepresentationChanged(r);
};
+class HClampToUint8: public HUnaryOperation {
+ public:
+ explicit HClampToUint8(HValue* value)
+ : HUnaryOperation(value),
+ input_rep_(Representation::None()) {
+ SetFlag(kFlexibleRepresentation);
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return input_rep_;
+ }
+
+ virtual Representation InferredRepresentation() {
+ // TODO(danno): Inference on input types should happen separately from
+ // return representation.
+ Representation new_rep = value()->representation();
+ if (input_rep_.IsNone()) {
+ if (!new_rep.IsNone()) {
+ input_rep_ = new_rep;
+ return Representation::Integer32();
+ } else {
+ return Representation::None();
+ }
+ } else {
+ return Representation::Integer32();
+ }
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ Representation input_rep_;
+};
+
+
class HSimulate: public HInstruction {
public:
HSimulate(int ast_id, int pop_count)
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
+ if (expr->external_array_type() == kExternalPixelArray) {
+ HClampToUint8* clamp = new(zone()) HClampToUint8(val);
+ AddInstruction(clamp);
+ val = clamp;
+ }
return new(zone()) HStoreKeyedSpecializedArrayElement(
external_elements,
key,
} else {
Register value = ToRegister(instr->value());
switch (array_type) {
- case kExternalPixelArray: {
- // Clamp the value to [0..255].
- Register temp = ToRegister(instr->TempAt(0));
- // The dec_b below requires that the clamped value is in a byte
- // register. eax is an arbitrary choice to satisfy this requirement, we
- // hinted the register allocator to give us eax when building the
- // instruction.
- ASSERT(temp.is(eax));
- __ mov(temp, ToRegister(instr->value()));
- Label done;
- __ test(temp, Immediate(0xFFFFFF00));
- __ j(zero, &done, Label::kNear);
- __ setcc(negative, temp); // 1 if negative, 0 if positive.
- __ dec_b(temp); // 0 if negative, 255 if positive.
- __ bind(&done);
- __ mov_b(operand, temp);
- break;
- }
+ case kExternalPixelArray:
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ mov_b(operand, value);
}
+void LCodeGen::DoClampDoubleToUint8(LClampDoubleToUint8* instr) {
+ XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
+}
+
+
+void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+ ASSERT(instr->unclamped()->Equals(instr->result()));
+ Register value_reg = ToRegister(instr->result());
+ __ ClampUint8(value_reg);
+}
+
+
+void LCodeGen::DoClampTaggedToUint8(LClampTaggedToUint8* instr) {
+ ASSERT(instr->unclamped()->Equals(instr->result()));
+ Register input_reg = ToRegister(instr->unclamped());
+ Label is_smi, done, heap_number;
+
+ __ JumpIfSmi(input_reg, &is_smi);
+
+ // Check for heap number
+ __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ __ j(equal, &heap_number, Label::kNear);
+
+ // Check for undefined. Undefined is converted to zero for clamping
+ // conversions.
+ __ cmp(input_reg, factory()->undefined_value());
+ DeoptimizeIf(not_equal, instr->environment());
+ __ mov(input_reg, 0);
+ __ jmp(&done, Label::kNear);
+
+ // Heap number
+ __ bind(&heap_number);
+ __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+ __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
+ __ jmp(&done, Label::kNear);
+
+ // smi
+ __ bind(&is_smi);
+ __ SmiUntag(input_reg);
+ __ ClampUint8(input_reg);
+
+ __ bind(&done);
+}
+
+
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
}
+LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
+ HValue* value = instr->value();
+ Representation input_rep = value->representation();
+ if (input_rep.IsDouble()) {
+ LOperand* reg = UseRegister(value);
+ return DefineAsRegister(new LClampDoubleToUint8(reg));
+ } else if (input_rep.IsInteger32()) {
+ LOperand* reg = UseFixed(value, eax);
+ return DefineFixed(new LClampIToUint8(reg), eax);
+ } else {
+ ASSERT(input_rep.IsTagged());
+ LOperand* reg = UseFixed(value, eax);
+ // Register allocator doesn't (yet) support allocation of double
+ // temps. Reserve xmm1 explicitly.
+ LOperand* temp = FixedTemp(xmm1);
+ LClampTaggedToUint8* result = new LClampTaggedToUint8(reg, temp);
+ return AssignEnvironment(DefineFixed(result, eax));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
return new LReturn(UseFixed(instr->value(), eax));
}
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* temp = NULL;
-
- if (array_type == kExternalPixelArray) {
- // The generated code for pixel array stores requires that the clamped value
- // is in a byte register. eax is an arbitrary choice to satisfy this
- // requirement.
- temp = FixedTemp(eax);
- }
-
LOperand* val = NULL;
if (array_type == kExternalByteArray ||
array_type == kExternalUnsignedByteArray) {
V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClampDoubleToUint8) \
+ V(ClampIToUint8) \
+ V(ClampTaggedToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpID) \
};
+class LClampDoubleToUint8: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LClampDoubleToUint8(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampDoubleToUint8, "clamp-d-to-uint8")
+};
+
+
+class LClampIToUint8: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LClampIToUint8(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
+};
+
+
+class LClampTaggedToUint8: public LTemplateInstruction<1, 1, 1> {
+ public:
+ explicit LClampTaggedToUint8(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampTaggedToUint8, "clamp-t-to-uint8")
+};
+
+
class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckNonSmi(LOperand* value) {
}
+void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
+ XMMRegister scratch_reg,
+ Register result_reg) {
+ Label done;
+ ExternalReference zero_ref = ExternalReference::address_of_zero();
+ movdbl(scratch_reg, Operand::StaticVariable(zero_ref));
+ Set(result_reg, Immediate(0));
+ ucomisd(input_reg, scratch_reg);
+ j(below, &done, Label::kNear);
+ ExternalReference half_ref = ExternalReference::address_of_one_half();
+ movdbl(scratch_reg, Operand::StaticVariable(half_ref));
+ addsd(scratch_reg, input_reg);
+ cvttsd2si(result_reg, Operand(scratch_reg));
+ test(result_reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ Set(result_reg, Immediate(255));
+ bind(&done);
+}
+
+
+void MacroAssembler::ClampUint8(Register reg) {
+ Label done;
+ test(reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ setcc(negative, reg); // 1 if negative, 0 if positive.
+ dec_b(reg); // 0 if negative, 255 if positive.
+ bind(&done);
+}
+
+
void MacroAssembler::InNewSpace(Register object,
Register scratch,
Condition cc,
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp();
+ void ClampUint8(Register reg);
+
+ void ClampDoubleToUint8(XMMRegister input_reg,
+ XMMRegister scratch_reg,
+ Register result_reg);
+
+
// Smi tagging support.
void SmiTag(Register reg) {
ASSERT(kSmiTag == 0);
Register value(ToRegister(instr->value()));
switch (array_type) {
case kExternalPixelArray:
- { // Clamp the value to [0..255].
- Label done;
- __ testl(value, Immediate(0xFFFFFF00));
- __ j(zero, &done, Label::kNear);
- __ setcc(negative, value); // 1 if negative, 0 if positive.
- __ decb(value); // 0 if negative, 255 if positive.
- __ bind(&done);
- __ movb(operand, value);
- }
- break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
__ movb(operand, value);
}
+void LCodeGen::DoClampDoubleToUint8(LClampDoubleToUint8* instr) {
+ XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
+ Register result_reg = ToRegister(instr->result());
+ Register temp_reg = ToRegister(instr->TempAt(0));
+ __ ClampDoubleToUint8(value_reg, xmm0, result_reg, temp_reg);
+}
+
+
+void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+ ASSERT(instr->unclamped()->Equals(instr->result()));
+ Register value_reg = ToRegister(instr->result());
+ __ ClampUint8(value_reg);
+}
+
+
+void LCodeGen::DoClampTaggedToUint8(LClampTaggedToUint8* instr) {
+ ASSERT(instr->unclamped()->Equals(instr->result()));
+ Register input_reg = ToRegister(instr->unclamped());
+ Register temp_reg = ToRegister(instr->TempAt(0));
+ XMMRegister temp_xmm_reg = ToDoubleRegister(instr->TempAt(1));
+ Label is_smi, done, heap_number;
+
+ __ JumpIfSmi(input_reg, &is_smi);
+
+ // Check for heap number
+ __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ __ j(equal, &heap_number, Label::kNear);
+
+ // Check for undefined. Undefined is converted to zero for clamping
+ // conversions.
+ __ Cmp(input_reg, factory()->undefined_value());
+ DeoptimizeIf(not_equal, instr->environment());
+ __ movq(input_reg, Immediate(0));
+ __ jmp(&done, Label::kNear);
+
+ // Heap number
+ __ bind(&heap_number);
+ __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+ __ ClampDoubleToUint8(xmm0, temp_xmm_reg, input_reg, temp_reg);
+ __ jmp(&done, Label::kNear);
+
+ // smi
+ __ bind(&is_smi);
+ __ SmiToInteger32(input_reg, input_reg);
+ __ ClampUint8(input_reg);
+
+ __ bind(&done);
+}
+
+
void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
if (heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
}
+LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
+ HValue* value = instr->value();
+ Representation input_rep = value->representation();
+ LOperand* reg = UseRegister(value);
+ if (input_rep.IsDouble()) {
+ return DefineAsRegister(new LClampDoubleToUint8(reg,
+ TempRegister()));
+ } else if (input_rep.IsInteger32()) {
+ return DefineSameAsFirst(new LClampIToUint8(reg));
+ } else {
+ ASSERT(input_rep.IsTagged());
+ // Register allocator doesn't (yet) support allocation of double
+ // temps. Reserve xmm1 explicitly.
+ LClampTaggedToUint8* result = new LClampTaggedToUint8(reg,
+ TempRegister(),
+ FixedTemp(xmm1));
+ return AssignEnvironment(DefineSameAsFirst(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
return new LReturn(UseFixed(instr->value(), rax));
}
V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(ClampDoubleToUint8) \
+ V(ClampIToUint8) \
+ V(ClampTaggedToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpID) \
};
+class LClampDoubleToUint8: public LTemplateInstruction<1, 1, 1> {
+ public:
+ explicit LClampDoubleToUint8(LOperand* value, LOperand* temp) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampDoubleToUint8, "clamp-d-to-uint8")
+};
+
+
+class LClampIToUint8: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LClampIToUint8(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
+};
+
+
+class LClampTaggedToUint8: public LTemplateInstruction<1, 1, 2> {
+ public:
+ explicit LClampTaggedToUint8(LOperand* value,
+ LOperand* temp,
+ LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp;
+ temps_[1] = temp2;
+ }
+
+ LOperand* unclamped() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClampTaggedToUint8, "clamp-t-to-uint8")
+};
+
+
class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
public:
explicit LCheckNonSmi(LOperand* value) {
}
+void MacroAssembler::ClampUint8(Register reg) {
+ Label done;
+ testl(reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ setcc(negative, reg); // 1 if negative, 0 if positive.
+ decb(reg); // 0 if negative, 255 if positive.
+ bind(&done);
+}
+
+
+void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
+ XMMRegister temp_xmm_reg,
+ Register result_reg,
+ Register temp_reg) {
+ Label done;
+ Set(result_reg, 0);
+ xorps(temp_xmm_reg, temp_xmm_reg);
+ ucomisd(input_reg, temp_xmm_reg);
+ j(below, &done, Label::kNear);
+ uint64_t one_half = BitCast<uint64_t, double>(0.5);
+ Set(temp_reg, one_half);
+ movq(temp_xmm_reg, temp_reg);
+ addsd(temp_xmm_reg, input_reg);
+ cvttsd2si(result_reg, temp_xmm_reg);
+ testl(result_reg, Immediate(0xFFFFFF00));
+ j(zero, &done, Label::kNear);
+ Set(result_reg, 255);
+ bind(&done);
+}
+
+
void MacroAssembler::AbortIfNotNumber(Register object) {
Label ok;
Condition is_smi = CheckSmi(object);
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp();
+ void ClampUint8(Register reg);
+
+ void ClampDoubleToUint8(XMMRegister input_reg,
+ XMMRegister temp_xmm_reg,
+ Register result_reg,
+ Register temp_reg);
+
// Abort execution if argument is not a number. Used in debug code.
void AbortIfNotNumber(Register object);
function set(a, index, value) {
a[index] = value;
}
-
+function temp() {
var array = new Float64Array(2);
for (var i = 0; i < 5; i++) {
set(array, 0, 2.5);
%OptimizeFunctionOnNextCall(get);
assertEquals(2.5, get(array, 0));
assertEquals(3.5, get(array, 1));
+}
// Test loads and stores.
-types = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array,
+types = [Array, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array,
Uint32Array, PixelArray, Float32Array, Float64Array];
+test_result_nan = [NaN, 0, 0, 0, 0, 0, 0, 0, NaN, NaN];
+test_result_low_int = [-1, -1, 255, -1, 65535, -1, 0xFFFFFFFF, 0, -1, -1];
+test_result_middle = [253.75, -3, 253, 253, 253, 253, 253, 254, 253.75, 253.75];
+test_result_high_int = [256, 0, 0, 256, 256, 256, 256, 255, 256, 256];
+
const kElementCount = 40;
function test_load(array, sum) {
return sum;
}
-function run_test(test_func, array, expected_sum_per_run) {
+
+function test_store_middle_double(array, sum) {
+ array[0] = 253.75;
+ return array[0];
+}
+
+
+function test_store_high_double(array, sum) {
+ array[0] = 256.25;
+ return array[0];
+}
+
+function test_store_high_double(array, sum) {
+ array[0] = 256.25;
+ return array[0];
+}
+
+function test_store_low_int(array, sum) {
+ array[0] = -1;
+ return array[0];
+}
+
+function test_store_high_int(array, sum) {
+ array[0] = 256;
+ return array[0];
+}
+
+function test_store_nan(array, sum) {
+ array[0] = NaN;
+ return array[0];
+}
+
+const kRuns = 10;
+
+function run_test(test_func, array, expected_result) {
for (var i = 0; i < 5; i++) test_func(array, 0);
%OptimizeFunctionOnNextCall(test_func);
- const kRuns = 10;
var sum = 0;
for (var i = 0; i < kRuns; i++) {
sum = test_func(array, sum);
}
- assertEquals(sum, expected_sum_per_run * kRuns);
+ assertEquals(expected_result, sum);
%DeoptimizeFunction(test_func);
gc(); // Makes V8 forget about type information for test_func.
}
for (var t = 0; t < types.length; t++) {
var type = types[t];
+ print ("type = " + t);
var a = new type(kElementCount);
for (var i = 0; i < kElementCount; i++) {
a[i] = i;
}
-
+
// Run test functions defined above.
- run_test(test_load, a, 780);
- run_test(test_load_const_key, a, 3);
- run_test(test_store, a, 820);
- run_test(test_store_const_key, a, 6);
-
+ run_test(test_load, a, 780 * kRuns);
+ run_test(test_load_const_key, a, 3 * kRuns);
+ run_test(test_store, a, 820 * kRuns);
+ run_test(test_store_const_key, a, 6 * kRuns);
+ run_test(test_store_low_int, a, test_result_low_int[t]);
+ run_test(test_store_high_int, a, test_result_high_int[t]);
+ run_test(test_store_nan, a, test_result_nan[t]);
+ run_test(test_store_middle_double, a, test_result_middle[t]);
+
// Test the correct behavior of the |length| property (which is read-only).
- assertEquals(kElementCount, a.length);
- a.length = 2;
- assertEquals(kElementCount, a.length);
- assertTrue(delete a.length);
- a.length = 2
- assertEquals(2, a.length);
+ if (t != 0) {
+ assertEquals(kElementCount, a.length);
+ a.length = 2;
+ assertEquals(kElementCount, a.length);
+ assertTrue(delete a.length);
+ a.length = 2;
+ assertEquals(2, a.length);
+ }
}