Commit 9718d079 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[CSA] Fix Array.prototype.reduceRight CAS_ASSERT

- Add typed IsHeapNumberPositive, IsNumberNonNegativeSafeInteger, IsInteger,
  IsSafeInteger and IsHeapNumberUint32 helpers on CodeStubAssembler
- Type NumberIsInteger and NumberIsSafeInteger builtin

Bug: chromium:847204, v8:6949
Change-Id: I27d3ab79bd17312c223209ed0b221c174024126e
Reviewed-on: https://chromium-review.googlesource.com/1087961
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53707}
parent 2aa166a6
...@@ -426,28 +426,34 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) { ...@@ -426,28 +426,34 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array); GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array);
merged_length = LoadJSArrayLength(CAST(o())); merged_length = LoadJSArrayLength(CAST(o()));
Goto(&has_length); Goto(&has_length);
BIND(&not_js_array); BIND(&not_js_array);
Node* len_property = {
GetProperty(context(), o(), isolate()->factory()->length_string()); Node* len_property =
merged_length = ToLength_Inline(context(), len_property); GetProperty(context(), o(), isolate()->factory()->length_string());
Goto(&has_length); merged_length = ToLength_Inline(context(), len_property);
Goto(&has_length);
}
BIND(&has_length); BIND(&has_length);
len_ = merged_length.value(); {
len_ = merged_length.value();
// 5. If IsCallable(callbackfn) is false, throw a TypeError exception. // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
Label type_exception(this, Label::kDeferred); Label type_exception(this, Label::kDeferred);
Label done(this); Label done(this);
GotoIf(TaggedIsSmi(callbackfn()), &type_exception); GotoIf(TaggedIsSmi(callbackfn()), &type_exception);
Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception); Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception);
BIND(&throw_null_undefined_exception); BIND(&throw_null_undefined_exception);
ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined, name); ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined,
name);
BIND(&type_exception); BIND(&type_exception);
ThrowTypeError(context(), MessageTemplate::kCalledNonCallable, ThrowTypeError(context(), MessageTemplate::kCalledNonCallable,
callbackfn()); callbackfn());
BIND(&done); BIND(&done);
}
// 6. If thisArg was supplied, let T be thisArg; else let T be undefined. // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
// [Already done by the arguments adapter] // [Already done by the arguments adapter]
...@@ -552,6 +558,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) { ...@@ -552,6 +558,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
} else { } else {
k_.Bind(NumberDec(len())); k_.Bind(NumberDec(len()));
} }
CSA_ASSERT(this, IsSafeInteger(k()));
Node* instance_type = LoadInstanceType(LoadElements(typed_array)); Node* instance_type = LoadInstanceType(LoadElements(typed_array));
Switch(instance_type, &unexpected_instance_type, instance_types.data(), Switch(instance_type, &unexpected_instance_type, instance_types.data(),
label_ptrs.data(), labels.size()); label_ptrs.data(), labels.size());
...@@ -593,10 +600,9 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) { ...@@ -593,10 +600,9 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
Label done_element(this, &to_); Label done_element(this, &to_);
// a. Let Pk be ToString(k). // a. Let Pk be ToString(k).
// We never have to perform a ToString conversion as the above guards // k() is guaranteed to be a positive integer, hence ToString is
// guarantee that we have a positive {k} which also is a valid array // side-effect free and HasProperty/GetProperty do the conversion inline.
// index in the range [0, 2^32-1). CSA_ASSERT(this, IsSafeInteger(k()));
CSA_ASSERT(this, IsNumberArrayIndex(k()));
if (missing_property_mode == MissingPropertyMode::kSkip) { if (missing_property_mode == MissingPropertyMode::kSkip) {
// b. Let kPresent be HasProperty(O, Pk). // b. Let kPresent be HasProperty(O, Pk).
......
...@@ -85,7 +85,7 @@ class ArrayBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler { ...@@ -85,7 +85,7 @@ class ArrayBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
TNode<Number> len() { return len_; } TNode<Number> len() { return len_; }
Node* callbackfn() { return callbackfn_; } Node* callbackfn() { return callbackfn_; }
Node* this_arg() { return this_arg_; } Node* this_arg() { return this_arg_; }
Node* k() { return k_.value(); } TNode<Number> k() { return CAST(k_.value()); }
Node* a() { return a_.value(); } Node* a() { return a_.value(); }
void ReturnFromBuiltin(Node* value); void ReturnFromBuiltin(Node* value);
......
...@@ -101,31 +101,8 @@ TF_BUILTIN(AllocateHeapNumber, CodeStubAssembler) { ...@@ -101,31 +101,8 @@ TF_BUILTIN(AllocateHeapNumber, CodeStubAssembler) {
// ES6 #sec-number.isinteger // ES6 #sec-number.isinteger
TF_BUILTIN(NumberIsInteger, CodeStubAssembler) { TF_BUILTIN(NumberIsInteger, CodeStubAssembler) {
Node* number = Parameter(Descriptor::kNumber); TNode<Object> number = CAST(Parameter(Descriptor::kNumber));
Return(SelectBooleanConstant(IsInteger(number)));
Label return_true(this), return_false(this);
// Check if {number} is a Smi.
GotoIf(TaggedIsSmi(number), &return_true);
// Check if {number} is a HeapNumber.
GotoIfNot(IsHeapNumber(number), &return_false);
// Load the actual value of {number}.
Node* number_value = LoadHeapNumberValue(number);
// Truncate the value of {number} to an integer (or an infinity).
Node* integer = Float64Trunc(number_value);
// Check if {number}s value matches the integer (ruling out the infinities).
Branch(Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)),
&return_true, &return_false);
BIND(&return_true);
Return(TrueConstant());
BIND(&return_false);
Return(FalseConstant());
} }
// ES6 #sec-number.isnan // ES6 #sec-number.isnan
...@@ -153,37 +130,8 @@ TF_BUILTIN(NumberIsNaN, CodeStubAssembler) { ...@@ -153,37 +130,8 @@ TF_BUILTIN(NumberIsNaN, CodeStubAssembler) {
// ES6 #sec-number.issafeinteger // ES6 #sec-number.issafeinteger
TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) { TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) {
Node* number = Parameter(Descriptor::kNumber); TNode<Object> number = CAST(Parameter(Descriptor::kNumber));
Return(SelectBooleanConstant(IsSafeInteger(number)));
Label return_true(this), return_false(this);
// Check if {number} is a Smi.
GotoIf(TaggedIsSmi(number), &return_true);
// Check if {number} is a HeapNumber.
GotoIfNot(IsHeapNumber(number), &return_false);
// Load the actual value of {number}.
Node* number_value = LoadHeapNumberValue(number);
// Truncate the value of {number} to an integer (or an infinity).
Node* integer = Float64Trunc(number_value);
// Check if {number}s value matches the integer (ruling out the infinities).
GotoIfNot(
Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)),
&return_false);
// Check if the {integer} value is in safe integer range.
Branch(Float64LessThanOrEqual(Float64Abs(integer),
Float64Constant(kMaxSafeInteger)),
&return_true, &return_false);
BIND(&return_true);
Return(TrueConstant());
BIND(&return_false);
Return(FalseConstant());
} }
// ES6 #sec-number.parsefloat // ES6 #sec-number.parsefloat
......
...@@ -5415,43 +5415,95 @@ TNode<BoolT> CodeStubAssembler::IsNumberNormalized(SloppyTNode<Number> number) { ...@@ -5415,43 +5415,95 @@ TNode<BoolT> CodeStubAssembler::IsNumberNormalized(SloppyTNode<Number> number) {
} }
TNode<BoolT> CodeStubAssembler::IsNumberPositive(SloppyTNode<Number> number) { TNode<BoolT> CodeStubAssembler::IsNumberPositive(SloppyTNode<Number> number) {
TNode<Float64T> float_zero = Float64Constant(0.);
return Select<BoolT>(TaggedIsSmi(number), return Select<BoolT>(TaggedIsSmi(number),
[=] { return TaggedIsPositiveSmi(number); }, [=] { return TaggedIsPositiveSmi(number); },
[=] { [=] { return IsHeapNumberPositive(CAST(number)); });
TNode<Float64T> v = LoadHeapNumberValue(CAST(number));
return Float64GreaterThanOrEqual(v, float_zero);
});
} }
TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(SloppyTNode<Number> number) { // TODO(cbruni): Use TNode<HeapNumber> instead of custom name.
TVARIABLE(BoolT, var_result, Int32TrueConstant()); TNode<BoolT> CodeStubAssembler::IsHeapNumberPositive(TNode<HeapNumber> number) {
TNode<Float64T> value = LoadHeapNumberValue(number);
TNode<Float64T> float_zero = Float64Constant(0.);
return Float64GreaterThanOrEqual(value, float_zero);
}
Label check_upper_bound(this), check_is_integer(this), out(this), TNode<BoolT> CodeStubAssembler::IsNumberNonNegativeSafeInteger(
return_false(this); TNode<Number> number) {
return Select<BoolT>(
// TODO(cbruni): Introduce TaggedIsNonNegateSmi to avoid confusion.
TaggedIsSmi(number), [=] { return TaggedIsPositiveSmi(number); },
[=] {
TNode<HeapNumber> heap_number = CAST(number);
return Select<BoolT>(IsInteger(heap_number),
[=] { return IsHeapNumberPositive(heap_number); },
[=] { return Int32FalseConstant(); });
});
}
GotoIfNumberGreaterThanOrEqual(number, NumberConstant(0), &check_upper_bound); TNode<BoolT> CodeStubAssembler::IsSafeInteger(TNode<Object> number) {
Goto(&return_false); return Select<BoolT>(
TaggedIsSmi(number), [=] { return Int32TrueConstant(); },
[=] {
return Select<BoolT>(
IsHeapNumber(CAST(number)),
[=] { return IsSafeInteger(UncheckedCast<HeapNumber>(number)); },
[=] { return Int32FalseConstant(); });
});
}
BIND(&check_upper_bound); TNode<BoolT> CodeStubAssembler::IsSafeInteger(TNode<HeapNumber> number) {
GotoIfNumberGreaterThanOrEqual(number, NumberConstant(kMaxUInt32), // Load the actual value of {number}.
&return_false); TNode<Float64T> number_value = LoadHeapNumberValue(number);
Goto(&check_is_integer); // Truncate the value of {number} to an integer (or an infinity).
TNode<Float64T> integer = Float64Trunc(number_value);
BIND(&check_is_integer); return Select<BoolT>(
GotoIf(TaggedIsSmi(number), &out); // Check if {number}s value matches the integer (ruling out the
// Check that the HeapNumber is a valid uint32 // infinities).
TNode<Float64T> value = LoadHeapNumberValue(CAST(number)); Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)),
TNode<Uint32T> int_value = ChangeFloat64ToUint32(value); [=] {
GotoIf(Float64Equal(value, ChangeUint32ToFloat64(int_value)), &out); // Check if the {integer} value is in safe integer range.
Goto(&return_false); return Float64LessThanOrEqual(Float64Abs(integer),
Float64Constant(kMaxSafeInteger));
},
[=] { return Int32FalseConstant(); });
}
BIND(&return_false); TNode<BoolT> CodeStubAssembler::IsInteger(TNode<Object> number) {
var_result = Int32FalseConstant(); return Select<BoolT>(
Goto(&out); TaggedIsSmi(number), [=] { return Int32TrueConstant(); },
[=] {
return Select<BoolT>(
IsHeapNumber(CAST(number)),
[=] { return IsInteger(UncheckedCast<HeapNumber>(number)); },
[=] { return Int32FalseConstant(); });
});
}
BIND(&out); TNode<BoolT> CodeStubAssembler::IsInteger(TNode<HeapNumber> number) {
return var_result.value(); TNode<Float64T> number_value = LoadHeapNumberValue(number);
// Truncate the value of {number} to an integer (or an infinity).
TNode<Float64T> integer = Float64Trunc(number_value);
// Check if {number}s value matches the integer (ruling out the infinities).
return Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0));
}
TNode<BoolT> CodeStubAssembler::IsHeapNumberUint32(TNode<HeapNumber> number) {
// Check that the HeapNumber is a valid uint32
return Select<BoolT>(
IsHeapNumberPositive(number),
[=] {
TNode<Float64T> value = LoadHeapNumberValue(number);
TNode<Uint32T> int_value = ChangeFloat64ToUint32(value);
return Float64Equal(value, ChangeUint32ToFloat64(int_value));
},
[=] { return Int32FalseConstant(); });
}
TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) {
return Select<BoolT>(TaggedIsSmi(number),
[=] { return TaggedIsPositiveSmi(number); },
[=] { return IsHeapNumberUint32(CAST(number)); });
} }
Node* CodeStubAssembler::FixedArraySizeDoesntFitInNewSpace(Node* element_count, Node* CodeStubAssembler::FixedArraySizeDoesntFitInNewSpace(Node* element_count,
......
...@@ -1693,9 +1693,25 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1693,9 +1693,25 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// within Smi range. // within Smi range.
TNode<BoolT> IsNumberNormalized(SloppyTNode<Number> number); TNode<BoolT> IsNumberNormalized(SloppyTNode<Number> number);
TNode<BoolT> IsNumberPositive(SloppyTNode<Number> number); TNode<BoolT> IsNumberPositive(SloppyTNode<Number> number);
TNode<BoolT> IsHeapNumberPositive(TNode<HeapNumber> number);
// True iff {number} is non-negative and less or equal than 2**53-1.
TNode<BoolT> IsNumberNonNegativeSafeInteger(TNode<Number> number);
// True iff {number} represents an integer value.
TNode<BoolT> IsInteger(TNode<Object> number);
TNode<BoolT> IsInteger(TNode<HeapNumber> number);
// True iff abs({number}) <= 2**53 -1
TNode<BoolT> IsSafeInteger(TNode<Object> number);
TNode<BoolT> IsSafeInteger(TNode<HeapNumber> number);
// True iff {number} represents a valid uint32t value.
TNode<BoolT> IsHeapNumberUint32(TNode<HeapNumber> number);
// True iff {number} is a positive number and a valid array index in the range // True iff {number} is a positive number and a valid array index in the range
// [0, 2^32-1). // [0, 2^32-1).
TNode<BoolT> IsNumberArrayIndex(SloppyTNode<Number> number); TNode<BoolT> IsNumberArrayIndex(TNode<Number> number);
Node* FixedArraySizeDoesntFitInNewSpace( Node* FixedArraySizeDoesntFitInNewSpace(
Node* element_count, int base_size = FixedArray::kHeaderSize, Node* element_count, int base_size = FixedArray::kHeaderSize,
......
...@@ -2922,8 +2922,9 @@ TEST(IsNumberArrayIndex) { ...@@ -2922,8 +2922,9 @@ TEST(IsNumberArrayIndex) {
CodeAssemblerTester asm_tester(isolate, kNumParams); CodeAssemblerTester asm_tester(isolate, kNumParams);
{ {
CodeStubAssembler m(asm_tester.state()); CodeStubAssembler m(asm_tester.state());
m.Return(m.SmiFromInt32( TNode<Number> number = m.CAST(m.Parameter(0));
m.UncheckedCast<Int32T>(m.IsNumberArrayIndex(m.Parameter(0))))); m.Return(
m.SmiFromInt32(m.UncheckedCast<Int32T>(m.IsNumberArrayIndex(number))));
} }
FunctionTester ft(asm_tester.GenerateCode(), kNumParams); FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment