Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 6d4ce690ff97f01062099ea524a4ea1c767f1cef..0d071d969042dba7272e415729e5f4ece4e1c939 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -258,6 +258,37 @@ Node* CodeStubAssembler::Float64Floor(Node* x) { |
return var_x.value(); |
} |
+Node* CodeStubAssembler::Float64RoundToEven(Node* x) { |
+ if (IsFloat64RoundTiesEvenSupported()) { |
+ return Float64RoundTiesEven(x); |
+ } |
+ // See ES#sec-touint8clamp for details. |
+ Node* f = Float64Floor(x); |
+ Node* f_and_half = Float64Add(f, Float64Constant(0.5)); |
+ |
+ Variable var_result(this, MachineRepresentation::kFloat64); |
+ Label return_f(this), return_f_plus_one(this), done(this); |
+ |
+ GotoIf(Float64LessThan(f_and_half, x), &return_f_plus_one); |
+ GotoIf(Float64LessThan(x, f_and_half), &return_f); |
+ { |
+ Node* f_mod_2 = Float64Mod(f, Float64Constant(2.0)); |
+ Branch(Float64Equal(f_mod_2, Float64Constant(0.0)), &return_f, |
+ &return_f_plus_one); |
+ } |
+ |
+ Bind(&return_f); |
+ var_result.Bind(f); |
+ Goto(&done); |
+ |
+ Bind(&return_f_plus_one); |
+ var_result.Bind(Float64Add(f, Float64Constant(1.0))); |
+ Goto(&done); |
+ |
+ Bind(&done); |
+ return var_result.value(); |
+} |
+ |
Node* CodeStubAssembler::Float64Trunc(Node* x) { |
if (IsFloat64RoundTruncateSupported()) { |
return Float64RoundTruncate(x); |
@@ -5401,21 +5432,6 @@ Node* CodeStubAssembler::LoadScriptContext(Node* context, int context_index) { |
IntPtrConstant(offset)); |
} |
-Node* CodeStubAssembler::ClampedToUint8(Node* int32_value) { |
- Label done(this); |
- Node* int32_zero = Int32Constant(0); |
- Node* int32_255 = Int32Constant(255); |
- Variable var_value(this, MachineRepresentation::kWord32); |
- var_value.Bind(int32_value); |
- GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); |
- var_value.Bind(int32_zero); |
- GotoIf(Int32LessThan(int32_value, int32_zero), &done); |
- var_value.Bind(int32_255); |
- Goto(&done); |
- Bind(&done); |
- return var_value.value(); |
-} |
- |
namespace { |
// Converts typed array elements kind to a machine representations. |
@@ -5448,7 +5464,8 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, |
ParameterMode mode) { |
if (IsFixedTypedArrayElementsKind(kind)) { |
if (kind == UINT8_CLAMPED_ELEMENTS) { |
- value = ClampedToUint8(value); |
+ CSA_ASSERT(this, |
+ Word32Equal(value, Word32And(Int32Constant(0xff), value))); |
} |
Node* offset = ElementOffsetFromIndex(index, kind, mode, 0); |
MachineRepresentation rep = ElementsKindToMachineRepresentation(kind); |
@@ -5467,6 +5484,106 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, |
} |
} |
+Node* CodeStubAssembler::Int32ToUint8Clamped(Node* int32_value) { |
+ Label done(this); |
+ Node* int32_zero = Int32Constant(0); |
+ Node* int32_255 = Int32Constant(255); |
+ Variable var_value(this, MachineRepresentation::kWord32); |
+ var_value.Bind(int32_value); |
+ GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); |
+ var_value.Bind(int32_zero); |
+ GotoIf(Int32LessThan(int32_value, int32_zero), &done); |
+ var_value.Bind(int32_255); |
+ Goto(&done); |
+ Bind(&done); |
+ return var_value.value(); |
+} |
+ |
+Node* CodeStubAssembler::Float64ToUint8Clamped(Node* float64_value) { |
+ Label done(this); |
+ Variable var_value(this, MachineRepresentation::kWord32); |
+ var_value.Bind(Int32Constant(0)); |
+ GotoIf(Float64LessThanOrEqual(float64_value, Float64Constant(0.0)), &done); |
+ var_value.Bind(Int32Constant(255)); |
+ GotoIf(Float64LessThanOrEqual(Float64Constant(255.0), float64_value), &done); |
+ { |
+ Node* rounded_value = Float64RoundToEven(float64_value); |
+ var_value.Bind(TruncateFloat64ToWord32(rounded_value)); |
+ Goto(&done); |
+ } |
+ Bind(&done); |
+ return var_value.value(); |
+} |
+ |
+Node* CodeStubAssembler::PrepareValueForWriteToTypedArray( |
+ Node* input, ElementsKind elements_kind, Label* bailout) { |
+ DCHECK(IsFixedTypedArrayElementsKind(elements_kind)); |
+ |
+ MachineRepresentation rep; |
+ switch (elements_kind) { |
+ case UINT8_ELEMENTS: |
+ case INT8_ELEMENTS: |
+ case UINT16_ELEMENTS: |
+ case INT16_ELEMENTS: |
+ case UINT32_ELEMENTS: |
+ case INT32_ELEMENTS: |
+ case UINT8_CLAMPED_ELEMENTS: |
+ rep = MachineRepresentation::kWord32; |
+ break; |
+ case FLOAT32_ELEMENTS: |
+ rep = MachineRepresentation::kFloat32; |
+ break; |
+ case FLOAT64_ELEMENTS: |
+ rep = MachineRepresentation::kFloat64; |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ return nullptr; |
+ } |
+ |
+ Variable var_result(this, rep); |
+ Label done(this, &var_result), if_smi(this); |
+ GotoIf(TaggedIsSmi(input), &if_smi); |
+ // Try to convert a heap number to a Smi. |
+ GotoUnless(IsHeapNumberMap(LoadMap(input)), bailout); |
+ { |
+ Node* value = LoadHeapNumberValue(input); |
+ if (rep == MachineRepresentation::kWord32) { |
+ if (elements_kind == UINT8_CLAMPED_ELEMENTS) { |
+ value = Float64ToUint8Clamped(value); |
+ } else { |
+ value = TruncateFloat64ToWord32(value); |
+ } |
+ } else if (rep == MachineRepresentation::kFloat32) { |
+ value = TruncateFloat64ToFloat32(value); |
+ } else { |
+ DCHECK_EQ(MachineRepresentation::kFloat64, rep); |
+ } |
+ var_result.Bind(value); |
+ Goto(&done); |
+ } |
+ |
+ Bind(&if_smi); |
+ { |
+ Node* value = SmiToWord32(input); |
+ if (rep == MachineRepresentation::kFloat32) { |
+ value = RoundInt32ToFloat32(value); |
+ } else if (rep == MachineRepresentation::kFloat64) { |
+ value = ChangeInt32ToFloat64(value); |
+ } else { |
+ DCHECK_EQ(MachineRepresentation::kWord32, rep); |
+ if (elements_kind == UINT8_CLAMPED_ELEMENTS) { |
+ value = Int32ToUint8Clamped(value); |
+ } |
+ } |
+ var_result.Bind(value); |
+ Goto(&done); |
+ } |
+ |
+ Bind(&done); |
+ return var_result.value(); |
+} |
+ |
void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, |
bool is_jsarray, |
ElementsKind elements_kind, |
@@ -5489,16 +5606,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, |
// TODO(ishell): call ToNumber() on value and don't bailout but be careful |
// to call it only once if we decide to bailout because of bounds checks. |
- if (IsFixedFloatElementsKind(elements_kind)) { |
- // TODO(ishell): move float32 truncation into PrepareValueForWrite. |
- value = PrepareValueForWrite(value, Representation::Double(), bailout); |
- if (elements_kind == FLOAT32_ELEMENTS) { |
- value = TruncateFloat64ToFloat32(value); |
- } |
- } else { |
- // TODO(ishell): It's fine for word8/16/32 to truncate the result. |
- value = TryToIntptr(value, bailout); |
- } |
+ value = PrepareValueForWriteToTypedArray(value, elements_kind, bailout); |
// There must be no allocations between the buffer load and |
// and the actual store to backing store, because GC may decide that |
@@ -5552,7 +5660,7 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value, |
if (IsFastSmiElementsKind(elements_kind)) { |
GotoUnless(TaggedIsSmi(value), bailout); |
} else if (IsFastDoubleElementsKind(elements_kind)) { |
- value = PrepareValueForWrite(value, Representation::Double(), bailout); |
+ value = TryTaggedToFloat64(value, bailout); |
} |
if (IsGrowStoreMode(store_mode)) { |