Commit 350af13c authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Fix Array.p.join overflow detection

Additionally, introduce IntPtrDiv to CodeAssembler.

Change-Id: I9396f77b90a2fadb0179028d44475e616be3d081
Reviewed-on: https://chromium-review.googlesource.com/c/1285400
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56776}
parent 4d0a85ee
...@@ -159,7 +159,7 @@ module array { ...@@ -159,7 +159,7 @@ module array {
} }
macro BufferAdd(implicit context: Context)( macro BufferAdd(implicit context: Context)(
initialBuffer: Buffer, str: String, nofSeparators: uintptr, initialBuffer: Buffer, str: String, nofSeparators: intptr,
separatorLength: intptr): Buffer { separatorLength: intptr): Buffer {
let buffer: Buffer = initialBuffer; let buffer: Buffer = initialBuffer;
// Add separators if necessary (at the beginning or more than one) // Add separators if necessary (at the beginning or more than one)
...@@ -178,14 +178,15 @@ module array { ...@@ -178,14 +178,15 @@ module array {
} }
macro BufferAddSeparators(implicit context: Context)( macro BufferAddSeparators(implicit context: Context)(
buffer: Buffer, nofSeparators: uintptr, separatorLength: intptr, buffer: Buffer, nofSeparators: intptr, separatorLength: intptr,
write: bool): Buffer { write: bool): Buffer {
if (nofSeparators == 0 || separatorLength == 0) return buffer; if (nofSeparators == 0 || separatorLength == 0) return buffer;
const nofSeparatorsInt: intptr = Signed(nofSeparators); const nofSeparatorsInt: intptr = nofSeparators;
const sepsLen: intptr = separatorLength * nofSeparatorsInt; const sepsLen: intptr = separatorLength * nofSeparatorsInt;
// Detect integer overflow // Detect integer overflow
if (nofSeparatorsInt <= 0 || sepsLen <= 0) deferred { // TODO(tebbi): Replace with overflow-checked multiplication.
if (sepsLen / separatorLength != nofSeparatorsInt) deferred {
ThrowRangeError(context, kInvalidStringLength); ThrowRangeError(context, kInvalidStringLength);
} }
...@@ -225,14 +226,14 @@ module array { ...@@ -225,14 +226,14 @@ module array {
const initialMap: Map = receiver.map; const initialMap: Map = receiver.map;
const len: uintptr = Convert<uintptr>(lengthNumber); const len: uintptr = Convert<uintptr>(lengthNumber);
const separatorLength: intptr = sep.length; const separatorLength: intptr = sep.length;
let nofSeparators: uintptr = 0; let nofSeparators: intptr = 0;
let loadJoinElements: LoadJoinElementFn = initialLoadJoinElement; let loadJoinElements: LoadJoinElementFn = initialLoadJoinElement;
let buffer: Buffer = BufferInit(estimatedNonHoleyElements, sep); let buffer: Buffer = BufferInit(estimatedNonHoleyElements, sep);
// 6. Let k be 0.
let k: uintptr = 0;
if (estimatedNonHoleyElements != 0) { if (estimatedNonHoleyElements != 0) {
// 6. Let k be 0.
let k: uintptr = 0;
// 7. Repeat, while k < len // 7. Repeat, while k < len
while (k < len) { while (k < len) {
if (k > 0) { if (k > 0) {
...@@ -288,8 +289,7 @@ module array { ...@@ -288,8 +289,7 @@ module array {
nofSeparators = 0; nofSeparators = 0;
} }
} else { } else {
assert(len > k); nofSeparators = Signed(len - 1);
nofSeparators = len - k - 1;
} }
// Add any separators at the end. // Add any separators at the end.
......
...@@ -355,6 +355,7 @@ extern operator '<<' macro SmiShl(Smi, constexpr int31): Smi; ...@@ -355,6 +355,7 @@ extern operator '<<' macro SmiShl(Smi, constexpr int31): Smi;
extern operator '+' macro IntPtrAdd(intptr, intptr): intptr; extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
extern operator '-' macro IntPtrSub(intptr, intptr): intptr; extern operator '-' macro IntPtrSub(intptr, intptr): intptr;
extern operator '*' macro IntPtrMul(intptr, intptr): intptr; extern operator '*' macro IntPtrMul(intptr, intptr): intptr;
extern operator '/' macro IntPtrDiv(intptr, intptr): intptr;
extern operator '<<' macro WordShl(intptr, intptr): intptr; extern operator '<<' macro WordShl(intptr, intptr): intptr;
extern operator '&' macro WordAnd(intptr, intptr): intptr; extern operator '&' macro WordAnd(intptr, intptr): intptr;
extern operator '|' macro WordOr(intptr, intptr): intptr; extern operator '|' macro WordOr(intptr, intptr): intptr;
......
...@@ -514,6 +514,23 @@ TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left, ...@@ -514,6 +514,23 @@ TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left,
return UncheckedCast<WordT>(raw_assembler()->IntPtrAdd(left, right)); return UncheckedCast<WordT>(raw_assembler()->IntPtrAdd(left, right));
} }
TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left,
TNode<IntPtrT> right) {
intptr_t left_constant;
bool is_left_constant = ToIntPtrConstant(left, left_constant);
intptr_t right_constant;
bool is_right_constant = ToIntPtrConstant(right, right_constant);
if (is_right_constant) {
if (is_left_constant) {
return IntPtrConstant(left_constant / right_constant);
}
if (base::bits::IsPowerOfTwo(right_constant)) {
return WordSar(left, WhichPowerOf2(right_constant));
}
}
return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrDiv(left, right));
}
TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left, TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) { SloppyTNode<WordT> right) {
intptr_t left_constant; intptr_t left_constant;
......
...@@ -884,6 +884,10 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -884,6 +884,10 @@ class V8_EXPORT_PRIVATE CodeAssembler {
return UncheckedCast<IntPtrT>( return UncheckedCast<IntPtrT>(
WordShr(static_cast<Node*>(left), static_cast<Node*>(right))); WordShr(static_cast<Node*>(left), static_cast<Node*>(right)));
} }
TNode<IntPtrT> WordSar(TNode<IntPtrT> left, TNode<IntegralT> right) {
return UncheckedCast<IntPtrT>(
WordSar(static_cast<Node*>(left), static_cast<Node*>(right)));
}
TNode<IntPtrT> WordAnd(TNode<IntPtrT> left, TNode<IntPtrT> right) { TNode<IntPtrT> WordAnd(TNode<IntPtrT> left, TNode<IntPtrT> right) {
return UncheckedCast<IntPtrT>( return UncheckedCast<IntPtrT>(
...@@ -946,6 +950,7 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -946,6 +950,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
} }
TNode<WordT> IntPtrAdd(SloppyTNode<WordT> left, SloppyTNode<WordT> right); TNode<WordT> IntPtrAdd(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<IntPtrT> IntPtrDiv(TNode<IntPtrT> left, TNode<IntPtrT> right);
TNode<WordT> IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right); TNode<WordT> IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<WordT> IntPtrMul(SloppyTNode<WordT> left, SloppyTNode<WordT> right); TNode<WordT> IntPtrMul(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<IntPtrT> IntPtrAdd(TNode<IntPtrT> left, TNode<IntPtrT> right) { TNode<IntPtrT> IntPtrAdd(TNode<IntPtrT> left, TNode<IntPtrT> right) {
...@@ -975,6 +980,9 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -975,6 +980,9 @@ class V8_EXPORT_PRIVATE CodeAssembler {
TNode<IntPtrT> WordShr(TNode<IntPtrT> value, int shift) { TNode<IntPtrT> WordShr(TNode<IntPtrT> value, int shift) {
return UncheckedCast<IntPtrT>(WordShr(static_cast<Node*>(value), shift)); return UncheckedCast<IntPtrT>(WordShr(static_cast<Node*>(value), shift));
} }
TNode<IntPtrT> WordSar(TNode<IntPtrT> value, int shift) {
return UncheckedCast<IntPtrT>(WordSar(static_cast<Node*>(value), shift));
}
TNode<Word32T> Word32Shr(SloppyTNode<Word32T> value, int shift); TNode<Word32T> Word32Shr(SloppyTNode<Word32T> value, int shift);
TNode<WordT> WordOr(SloppyTNode<WordT> left, SloppyTNode<WordT> right); TNode<WordT> WordOr(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
......
...@@ -126,6 +126,44 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrMul) { ...@@ -126,6 +126,44 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrMul) {
} }
} }
TARGET_TEST_F(CodeAssemblerTest, IntPtrDiv) {
CodeAssemblerTestState state(this);
CodeAssemblerForTest m(&state);
{
TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0));
TNode<IntPtrT> b = m.IntPtrConstant(100);
TNode<IntPtrT> div = m.IntPtrDiv(a, b);
EXPECT_THAT(div, IsIntPtrDiv(Matcher<Node*>(a), Matcher<Node*>(b)));
}
// x / 1 => x
{
TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0));
TNode<IntPtrT> b = m.IntPtrConstant(1);
TNode<IntPtrT> div = m.IntPtrDiv(a, b);
EXPECT_THAT(div, a);
}
// CONST_a / CONST_b => CONST_c
{
TNode<IntPtrT> a = m.IntPtrConstant(100);
TNode<IntPtrT> b = m.IntPtrConstant(5);
TNode<IntPtrT> div = m.IntPtrDiv(a, b);
EXPECT_THAT(div, IsIntPtrConstant(20));
}
{
TNode<IntPtrT> a = m.IntPtrConstant(100);
TNode<IntPtrT> b = m.IntPtrConstant(5);
TNode<IntPtrT> div = m.IntPtrDiv(a, b);
EXPECT_THAT(div, IsIntPtrConstant(20));
}
// x / 2^CONST => x >> CONST
{
TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0));
TNode<IntPtrT> b = m.IntPtrConstant(1 << 3);
TNode<IntPtrT> div = m.IntPtrDiv(a, b);
EXPECT_THAT(div, IsWordSar(Matcher<Node*>(a), IsIntPtrConstant(3)));
}
}
TARGET_TEST_F(CodeAssemblerTest, WordShl) { TARGET_TEST_F(CodeAssemblerTest, WordShl) {
CodeAssemblerTestState state(this); CodeAssemblerTestState state(this);
CodeAssemblerForTest m(&state); CodeAssemblerForTest m(&state);
......
...@@ -2152,6 +2152,7 @@ IS_BINOP_MATCHER(Word64Equal) ...@@ -2152,6 +2152,7 @@ IS_BINOP_MATCHER(Word64Equal)
IS_BINOP_MATCHER(Int32AddWithOverflow) IS_BINOP_MATCHER(Int32AddWithOverflow)
IS_BINOP_MATCHER(Int32SubWithOverflow) IS_BINOP_MATCHER(Int32SubWithOverflow)
IS_BINOP_MATCHER(Int32Add) IS_BINOP_MATCHER(Int32Add)
IS_BINOP_MATCHER(Int32Div)
IS_BINOP_MATCHER(Int32Sub) IS_BINOP_MATCHER(Int32Sub)
IS_BINOP_MATCHER(Int32Mul) IS_BINOP_MATCHER(Int32Mul)
IS_BINOP_MATCHER(Int32MulHigh) IS_BINOP_MATCHER(Int32MulHigh)
...@@ -2159,6 +2160,7 @@ IS_BINOP_MATCHER(Int32LessThan) ...@@ -2159,6 +2160,7 @@ IS_BINOP_MATCHER(Int32LessThan)
IS_BINOP_MATCHER(Uint32LessThan) IS_BINOP_MATCHER(Uint32LessThan)
IS_BINOP_MATCHER(Uint32LessThanOrEqual) IS_BINOP_MATCHER(Uint32LessThanOrEqual)
IS_BINOP_MATCHER(Int64Add) IS_BINOP_MATCHER(Int64Add)
IS_BINOP_MATCHER(Int64Div)
IS_BINOP_MATCHER(Int64Sub) IS_BINOP_MATCHER(Int64Sub)
IS_BINOP_MATCHER(Int64Mul) IS_BINOP_MATCHER(Int64Mul)
IS_BINOP_MATCHER(JSAdd) IS_BINOP_MATCHER(JSAdd)
......
...@@ -387,6 +387,8 @@ Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher, ...@@ -387,6 +387,8 @@ Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt32Div(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher,
...@@ -403,6 +405,8 @@ Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher, ...@@ -403,6 +405,8 @@ Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt64Mul(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsInt64Mul(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt64Div(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsJSParseInt(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsJSParseInt(const Matcher<Node*>& lhs_matcher,
...@@ -517,6 +521,12 @@ static inline Matcher<Node*> IsIntPtrMul(const Matcher<Node*>& lhs_matcher, ...@@ -517,6 +521,12 @@ static inline Matcher<Node*> IsIntPtrMul(const Matcher<Node*>& lhs_matcher,
: IsInt32Mul(lhs_matcher, rhs_matcher); : IsInt32Mul(lhs_matcher, rhs_matcher);
} }
static inline Matcher<Node*> IsIntPtrDiv(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Div(lhs_matcher, rhs_matcher)
: IsInt32Div(lhs_matcher, rhs_matcher);
}
static inline Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, static inline Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) { const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
......
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