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) {
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0);
index = std::min(index, static_cast<double>(str->length()));
end = static_cast<uint32_t>(index);
end = str->ToValidIndex(*position);
}
int start = end - search_string->length();
......@@ -863,11 +861,8 @@ BUILTIN(StringPrototypeIncludes) {
isolate, position,
Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
double index = std::max(position->Number(), 0.0);
index = std::min(index, static_cast<double>(str->length()));
int index_in_str = String::IndexOf(isolate, str, search_string,
static_cast<uint32_t>(index));
uint32_t index = str->ToValidIndex(*position);
int index_in_str = String::IndexOf(isolate, str, search_string, index);
return *isolate->factory()->ToBoolean(index_in_str != -1);
}
......@@ -1360,9 +1355,7 @@ BUILTIN(StringPrototypeStartsWith) {
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0);
index = std::min(index, static_cast<double>(str->length()));
start = static_cast<uint32_t>(index);
start = str->ToValidIndex(*position);
}
if (start + search_string->length() > str->length()) {
......
......@@ -128,12 +128,26 @@ int32_t NumberToInt32(Object* number) {
return DoubleToInt32(number->Number());
}
uint32_t NumberToUint32(Object* number) {
if (number->IsSmi()) return Smi::cast(number)->value();
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) {
if (number->IsSmi()) return Smi::cast(number)->value();
return static_cast<int64_t>(number->Number());
......
......@@ -168,6 +168,7 @@ inline bool IsInt32Double(double value);
inline bool IsUint32Double(double value);
// Convert from Number object to C integer.
inline uint32_t PositiveNumberToUint32(Object* number);
inline int32_t NumberToInt32(Object* number);
inline uint32_t NumberToUint32(Object* number);
inline int64_t NumberToInt64(Object* number);
......
......@@ -3878,6 +3878,12 @@ inline Vector<const uc16> String::GetCharVector() {
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) {
DCHECK(index >= 0 && index < length());
......
......@@ -11747,11 +11747,9 @@ Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position));
double index = std::max(position->Number(), 0.0);
index = std::min(index, static_cast<double>(receiver_string->length()));
return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
static_cast<uint32_t>(index)));
uint32_t index = receiver_string->ToValidIndex(*position);
return Smi::FromInt(
String::IndexOf(isolate, receiver_string, search_string, index));
}
namespace {
......@@ -11957,11 +11955,7 @@ Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, 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);
start_index = receiver_string->ToValidIndex(*position);
}
uint32_t pattern_length = search_string->length();
......
......@@ -10015,6 +10015,7 @@ class String: public Name {
// Conversion.
inline bool AsArrayIndex(uint32_t* index);
uint32_t inline ToValidIndex(Object* number);
// Trimming.
enum TrimMode { kTrim, kTrimLeft, kTrimRight };
......
......@@ -1390,7 +1390,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
uint32_t 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);
......@@ -1411,8 +1411,8 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
Handle<FixedArray> elems = factory->NewFixedArrayWithHoles(kInitialArraySize);
int num_elems = 0;
int string_index = 0;
int prev_string_index = 0;
uint32_t string_index = 0;
uint32_t prev_string_index = 0;
while (string_index < length) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, RegExpUtils::SetLastIndex(isolate, splitter, string_index));
......@@ -1434,9 +1434,9 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
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) {
string_index = RegExpUtils::AdvanceStringIndex(isolate, string,
string_index, unicode);
......@@ -1461,8 +1461,7 @@ RUNTIME_FUNCTION(Runtime_RegExpSplit) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num_captures_obj, Object::ToLength(isolate, num_captures_obj));
const int num_captures =
std::max(Handle<Smi>::cast(num_captures_obj)->value(), 0);
const int num_captures = PositiveNumberToUint32(*num_captures_obj);
for (int i = 1; i < num_captures; i++) {
Handle<Object> capture;
......@@ -1508,7 +1507,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
replace_obj));
}
const int length = string->length();
const uint32_t length = string->length();
const bool functional_replace = replace_obj->IsCallable();
Handle<String> replace;
......@@ -1565,7 +1564,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
// TODO(jgruber): Look into ReplacementStringBuilder instead.
IncrementalStringBuilder builder(isolate);
int next_source_position = 0;
uint32_t next_source_position = 0;
for (const auto& result : results) {
Handle<Object> captures_length_obj;
......@@ -1576,8 +1575,7 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, captures_length_obj,
Object::ToLength(isolate, captures_length_obj));
const int captures_length =
std::max(Handle<Smi>::cast(captures_length_obj)->value(), 0);
const int captures_length = PositiveNumberToUint32(*captures_length_obj);
Handle<Object> match_obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj,
......@@ -1598,8 +1596,8 @@ RUNTIME_FUNCTION(Runtime_RegExpReplace) {
// 2^53 - 1 (at least for ToLength), we might actually need uint64_t here?
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, position_obj, Object::ToInteger(isolate, position_obj));
const int position =
std::max(std::min(Handle<Smi>::cast(position_obj)->value(), length), 0);
const uint32_t position =
std::min(PositiveNumberToUint32(*position_obj), length);
ZoneVector<Handle<Object>> captures(&zone);
for (int n = 0; n < captures_length; n++) {
......
......@@ -456,3 +456,49 @@ TEST(TryNumberToSizeWithMaxSizePlusOne) {
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 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
assertFalse("abc".startsWith("a", Infinity));
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