Commit 1c1465f1 authored by cbruni's avatar cbruni Committed by Commit bot

[runtime] Add PositiveNumberToUint32 helper to avoid double to uint roundtrip

BUG=

Review-Url: https://codereview.chromium.org/2577143002
Cr-Commit-Position: refs/heads/master@{#41801}
parent 8ac9e55a
...@@ -801,9 +801,7 @@ BUILTIN(StringPrototypeEndsWith) { ...@@ -801,9 +801,7 @@ BUILTIN(StringPrototypeEndsWith) {
} else { } else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position)); Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0); end = str->ToValidIndex(*position);
index = std::min(index, static_cast<double>(str->length()));
end = static_cast<uint32_t>(index);
} }
int start = end - search_string->length(); int start = end - search_string->length();
...@@ -863,11 +861,8 @@ BUILTIN(StringPrototypeIncludes) { ...@@ -863,11 +861,8 @@ BUILTIN(StringPrototypeIncludes) {
isolate, position, isolate, position,
Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
double index = std::max(position->Number(), 0.0); uint32_t index = str->ToValidIndex(*position);
index = std::min(index, static_cast<double>(str->length())); int index_in_str = String::IndexOf(isolate, str, search_string, index);
int index_in_str = String::IndexOf(isolate, str, search_string,
static_cast<uint32_t>(index));
return *isolate->factory()->ToBoolean(index_in_str != -1); return *isolate->factory()->ToBoolean(index_in_str != -1);
} }
...@@ -1360,9 +1355,7 @@ BUILTIN(StringPrototypeStartsWith) { ...@@ -1360,9 +1355,7 @@ BUILTIN(StringPrototypeStartsWith) {
} else { } else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position)); Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0); start = str->ToValidIndex(*position);
index = std::min(index, static_cast<double>(str->length()));
start = static_cast<uint32_t>(index);
} }
if (start + search_string->length() > str->length()) { if (start + search_string->length() > str->length()) {
......
...@@ -128,12 +128,26 @@ int32_t NumberToInt32(Object* number) { ...@@ -128,12 +128,26 @@ int32_t NumberToInt32(Object* number) {
return DoubleToInt32(number->Number()); return DoubleToInt32(number->Number());
} }
uint32_t NumberToUint32(Object* number) { uint32_t NumberToUint32(Object* number) {
if (number->IsSmi()) return Smi::cast(number)->value(); if (number->IsSmi()) return Smi::cast(number)->value();
return DoubleToUint32(number->Number()); return DoubleToUint32(number->Number());
} }
uint32_t PositiveNumberToUint32(Object* number) {
if (number->IsSmi()) {
int value = Smi::cast(number)->value();
if (value <= 0) return 0;
return value;
}
DCHECK(number->IsHeapNumber());
double value = number->Number();
// Catch all values smaller than 1 and use the double-negation trick for NANs.
if (!(value >= 1)) return 0;
uint32_t max = std::numeric_limits<uint32_t>::max();
if (value < max) return static_cast<uint32_t>(value);
return max;
}
int64_t NumberToInt64(Object* number) { int64_t NumberToInt64(Object* number) {
if (number->IsSmi()) return Smi::cast(number)->value(); if (number->IsSmi()) return Smi::cast(number)->value();
return static_cast<int64_t>(number->Number()); return static_cast<int64_t>(number->Number());
......
...@@ -168,6 +168,7 @@ inline bool IsInt32Double(double value); ...@@ -168,6 +168,7 @@ inline bool IsInt32Double(double value);
inline bool IsUint32Double(double value); inline bool IsUint32Double(double value);
// Convert from Number object to C integer. // Convert from Number object to C integer.
inline uint32_t PositiveNumberToUint32(Object* number);
inline int32_t NumberToInt32(Object* number); inline int32_t NumberToInt32(Object* number);
inline uint32_t NumberToUint32(Object* number); inline uint32_t NumberToUint32(Object* number);
inline int64_t NumberToInt64(Object* number); inline int64_t NumberToInt64(Object* number);
......
...@@ -3878,6 +3878,12 @@ inline Vector<const uc16> String::GetCharVector() { ...@@ -3878,6 +3878,12 @@ inline Vector<const uc16> String::GetCharVector() {
return flat.ToUC16Vector(); return flat.ToUC16Vector();
} }
uint32_t String::ToValidIndex(Object* number) {
uint32_t index = PositiveNumberToUint32(number);
uint32_t length_value = static_cast<uint32_t>(length());
if (index > length_value) return length_value;
return index;
}
uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { uint16_t SeqOneByteString::SeqOneByteStringGet(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
......
...@@ -11747,11 +11747,9 @@ Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver, ...@@ -11747,11 +11747,9 @@ Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position)); Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0); uint32_t index = receiver_string->ToValidIndex(*position);
index = std::min(index, static_cast<double>(receiver_string->length())); return Smi::FromInt(
String::IndexOf(isolate, receiver_string, search_string, index));
return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
static_cast<uint32_t>(index)));
} }
namespace { namespace {
...@@ -11957,11 +11955,7 @@ Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver, ...@@ -11957,11 +11955,7 @@ Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
} else { } else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position)); Object::ToInteger(isolate, position));
start_index = receiver_string->ToValidIndex(*position);
double position_number = std::max(position->Number(), 0.0);
position_number = std::min(position_number,
static_cast<double>(receiver_string->length()));
start_index = static_cast<uint32_t>(position_number);
} }
uint32_t pattern_length = search_string->length(); uint32_t pattern_length = search_string->length();
......
...@@ -10015,6 +10015,7 @@ class String: public Name { ...@@ -10015,6 +10015,7 @@ class String: public Name {
// Conversion. // Conversion.
inline bool AsArrayIndex(uint32_t* index); inline bool AsArrayIndex(uint32_t* index);
uint32_t inline ToValidIndex(Object* number);
// Trimming. // Trimming.
enum TrimMode { kTrim, kTrimLeft, kTrimRight }; enum TrimMode { kTrim, kTrimLeft, kTrimRight };
......
...@@ -1390,7 +1390,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) { ...@@ -1390,7 +1390,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
uint32_t limit; uint32_t limit;
RETURN_FAILURE_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit)); RETURN_FAILURE_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit));
const int length = string->length(); const uint32_t length = string->length();
if (limit == 0) return *factory->NewJSArray(0); if (limit == 0) return *factory->NewJSArray(0);
...@@ -1411,8 +1411,8 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) { ...@@ -1411,8 +1411,8 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize); Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize);
int num_elems = 0; int num_elems = 0;
int string_index = 0; uint32_t string_index = 0;
int prev_string_index = 0; uint32_t prev_string_index = 0;
while (string_index < length) { while (string_index < length) {
RETURN_FAILURE_ON_EXCEPTION( RETURN_FAILURE_ON_EXCEPTION(
isolate, RegExpUtils::SetLastIndex(isolate, splitter, string_index)); isolate, RegExpUtils::SetLastIndex(isolate, splitter, string_index));
...@@ -1434,9 +1434,9 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) { ...@@ -1434,9 +1434,9 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, last_index_obj, Object::ToLength(isolate, last_index_obj)); isolate, last_index_obj, Object::ToLength(isolate, last_index_obj));
const int last_index = Handle<Smi>::cast(last_index_obj)->value();
const int end = std::min(last_index, length); const uint32_t end =
std::min(PositiveNumberToUint32(*last_index_obj), length);
if (end == prev_string_index) { if (end == prev_string_index) {
string_index = RegExpUtils::AdvanceStringIndex(isolate, string, string_index = RegExpUtils::AdvanceStringIndex(isolate, string,
string_index, unicode); string_index, unicode);
...@@ -1461,8 +1461,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) { ...@@ -1461,8 +1461,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num_captures_obj, Object::ToLength(isolate, num_captures_obj)); isolate, num_captures_obj, Object::ToLength(isolate, num_captures_obj));
const int num_captures = const int num_captures = PositiveNumberToUint32(*num_captures_obj);
std::max(Handle<Smi>::cast(num_captures_obj)->value(), 0);
for (int i = 1; i < num_captures; i++) { for (int i = 1; i < num_captures; i++) {
Handle<Object> capture; Handle<Object> capture;
...@@ -1508,7 +1507,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { ...@@ -1508,7 +1507,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
replace_obj)); replace_obj));
} }
const int length = string->length(); const uint32_t length = string->length();
const bool functional_replace = replace_obj->IsCallable(); const bool functional_replace = replace_obj->IsCallable();
Handle<String> replace; Handle<String> replace;
...@@ -1565,7 +1564,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { ...@@ -1565,7 +1564,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
// TODO(jgruber): Look into ReplacementStringBuilder instead. // TODO(jgruber): Look into ReplacementStringBuilder instead.
IncrementalStringBuilder builder(isolate); IncrementalStringBuilder builder(isolate);
int next_source_position = 0; uint32_t next_source_position = 0;
for (const auto& result : results) { for (const auto& result : results) {
Handle<Object> captures_length_obj; Handle<Object> captures_length_obj;
...@@ -1576,8 +1575,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { ...@@ -1576,8 +1575,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, captures_length_obj, isolate, captures_length_obj,
Object::ToLength(isolate, captures_length_obj)); Object::ToLength(isolate, captures_length_obj));
const int captures_length = const int captures_length = PositiveNumberToUint32(*captures_length_obj);
std::max(Handle<Smi>::cast(captures_length_obj)->value(), 0);
Handle<Object> match_obj; Handle<Object> match_obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj, ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj,
...@@ -1598,8 +1596,8 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) { ...@@ -1598,8 +1596,8 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
// 2^53 - 1 (at least for ToLength), we might actually need uint64_t here? // 2^53 - 1 (at least for ToLength), we might actually need uint64_t here?
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, position_obj, Object::ToInteger(isolate, position_obj)); isolate, position_obj, Object::ToInteger(isolate, position_obj));
const int position = const uint32_t position =
std::max(std::min(Handle<Smi>::cast(position_obj)->value(), length), 0); std::min(PositiveNumberToUint32(*position_obj), length);
ZoneVector<Handle<Object>> captures(&zone); ZoneVector<Handle<Object>> captures(&zone);
for (int n = 0; n < captures_length; n++) { for (int n = 0; n < captures_length; n++) {
......
...@@ -456,3 +456,49 @@ TEST(TryNumberToSizeWithMaxSizePlusOne) { ...@@ -456,3 +456,49 @@ TEST(TryNumberToSizeWithMaxSizePlusOne) {
CHECK(!TryNumberToSize(*heap_number, &result)); CHECK(!TryNumberToSize(*heap_number, &result));
} }
} }
TEST(PositiveNumberToUint32) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
uint32_t max = std::numeric_limits<uint32_t>::max();
HandleScope scope(isolate);
// Test Smi conversions.
Handle<Object> number = handle(Smi::FromInt(0), isolate);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = handle(Smi::FromInt(-1), isolate);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = handle(Smi::FromInt(-1), isolate);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = handle(Smi::FromInt(Smi::kMinValue), isolate);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = handle(Smi::FromInt(Smi::kMaxValue), isolate);
CHECK_EQ(PositiveNumberToUint32(*number),
static_cast<uint32_t>(Smi::kMaxValue));
// Test Double conversions.
number = factory->NewHeapNumber(0.0);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = factory->NewHeapNumber(0.999);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = factory->NewHeapNumber(1.999);
CHECK_EQ(PositiveNumberToUint32(*number), 1u);
number = factory->NewHeapNumber(-12.0);
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = factory->NewHeapNumber(12000.0);
CHECK_EQ(PositiveNumberToUint32(*number), 12000u);
number = factory->NewHeapNumber(static_cast<double>(Smi::kMaxValue) + 1);
CHECK_EQ(PositiveNumberToUint32(*number),
static_cast<uint32_t>(Smi::kMaxValue) + 1);
number = factory->NewHeapNumber(max);
CHECK_EQ(PositiveNumberToUint32(*number), max);
number = factory->NewHeapNumber(static_cast<double>(max) * 1000);
CHECK_EQ(PositiveNumberToUint32(*number), max);
number = factory->NewHeapNumber(std::numeric_limits<double>::max());
CHECK_EQ(PositiveNumberToUint32(*number), max);
number = factory->NewHeapNumber(std::numeric_limits<double>::infinity());
CHECK_EQ(PositiveNumberToUint32(*number), max);
number =
factory->NewHeapNumber(-1.0 * std::numeric_limits<double>::infinity());
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
number = factory->NewHeapNumber(std::nan(""));
CHECK_EQ(PositiveNumberToUint32(*number), 0u);
}
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
assertFalse("abc".startsWith("a", Infinity));
assertEquals(1, String.prototype.startsWith.length); assertEquals(1, String.prototype.startsWith.length);
......
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