Commit 0b7769e3 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

[builtins] Refactor StringTrim

This is follow-up of 289d25c1
Improve loop using Subslice, improve common-case check.

Bug: v8:8996
Change-Id: I59ba14b87e1b034fd2d41c92a506e142550363ce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2527608
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71666}
parent c73f5c21
...@@ -174,6 +174,9 @@ Convert<int32, uint8>(i: uint8): int32 { ...@@ -174,6 +174,9 @@ Convert<int32, uint8>(i: uint8): int32 {
Convert<int32, uint16>(i: uint16): int32 { Convert<int32, uint16>(i: uint16): int32 {
return Signed(Convert<uint32>(i)); return Signed(Convert<uint32>(i));
} }
Convert<int32, char16|char8>(i: char16|char8): int32 {
return Signed(Convert<uint32>(i));
}
Convert<int32, uint31>(i: uint31): int32 { Convert<int32, uint31>(i: uint31): int32 {
return Signed(Convert<uint32>(i)); return Signed(Convert<uint32>(i));
} }
......
...@@ -13,12 +13,17 @@ extern enum TrimMode extends uint31 constexpr 'String::TrimMode' { ...@@ -13,12 +13,17 @@ extern enum TrimMode extends uint31 constexpr 'String::TrimMode' {
} }
@export @export
macro IsWhiteSpaceOrLineTerminator(charCode: char16): bool { macro IsWhiteSpaceOrLineTerminator(charCode: char16|char8): bool {
// 0x0020 - SPACE (Intentionally out of order to fast path a commmon case) // 0x0020 - SPACE (Intentionally out of order to fast path a commmon case)
if (charCode == 0x0020) { if (charCode == 0x0020) {
return true; return true;
} }
// Common Non-whitespace characters from (0x000E, 0x00A0)
if (Unsigned(Convert<int32>(charCode) - 0x000E) < 0x0092) {
return false;
}
// 0x0009 - HORIZONTAL TAB // 0x0009 - HORIZONTAL TAB
if (charCode < 0x0009) { if (charCode < 0x0009) {
return false; return false;
...@@ -31,11 +36,6 @@ macro IsWhiteSpaceOrLineTerminator(charCode: char16): bool { ...@@ -31,11 +36,6 @@ macro IsWhiteSpaceOrLineTerminator(charCode: char16): bool {
return true; return true;
} }
// Common Non-whitespace characters
if (charCode < 0x00A0) {
return false;
}
// 0x00A0 - NO-BREAK SPACE // 0x00A0 - NO-BREAK SPACE
if (charCode == 0x00A0) { if (charCode == 0x00A0) {
return true; return true;
...@@ -92,49 +92,59 @@ macro IsWhiteSpaceOrLineTerminator(charCode: char16): bool { ...@@ -92,49 +92,59 @@ macro IsWhiteSpaceOrLineTerminator(charCode: char16): bool {
return false; return false;
} }
transitioning macro StringTrim(implicit context: Context)( transitioning macro StringTrimLoop<T: type>(implicit context: Context)(
receiver: JSAny, _arguments: Arguments, methodName: constexpr string, stringSlice: ConstSlice<T>, startIndex: intptr, endIndex: intptr,
variant: constexpr TrimMode): String { increment: intptr): intptr {
const receiverString: String = ToThisString(receiver, methodName); let index = startIndex;
const stringLength: intptr = receiverString.length_intptr; while (true) {
if (index == endIndex) {
return index;
}
const char: T = *stringSlice.AtIndex(index);
if (!IsWhiteSpaceOrLineTerminator(char)) {
return index;
}
index = index + increment;
}
unreachable;
}
const directString = Cast<DirectString>(receiverString) transitioning macro StringTrimBody<T: type>(implicit context: Context)(
otherwise return runtime::StringTrim( string: String, slice: ConstSlice<T>, variant: constexpr TrimMode): String {
receiverString, SmiTag<TrimMode>(variant)); const stringLength: intptr = string.length_intptr;
let startIndex: intptr = 0; let startIndex: intptr = 0;
let endIndex: intptr = stringLength - 1; let endIndex: intptr = stringLength - 1;
// TODO(duongn): It would probably be more efficient to turn StringTrim into a
// tempalate for the different string types and specialize the loop for them.
if (variant == TrimMode::kTrim || variant == TrimMode::kTrimStart) { if (variant == TrimMode::kTrim || variant == TrimMode::kTrimStart) {
while (true) { startIndex = StringTrimLoop(slice, startIndex, stringLength, 1);
if (startIndex == stringLength) { if (startIndex == stringLength) {
return EmptyStringConstant(); return kEmptyString;
}
if (!IsWhiteSpaceOrLineTerminator(
StringCharCodeAt(directString, Unsigned(startIndex)))) {
break;
}
startIndex++;
} }
} }
if (variant == TrimMode::kTrim || variant == TrimMode::kTrimEnd) { if (variant == TrimMode::kTrim || variant == TrimMode::kTrimEnd) {
while (true) { endIndex = StringTrimLoop(slice, endIndex, -1, -1);
if (endIndex == -1) { if (endIndex == -1) {
return EmptyStringConstant(); return kEmptyString;
}
if (!IsWhiteSpaceOrLineTerminator(
StringCharCodeAt(directString, Unsigned(endIndex)))) {
break;
}
endIndex--;
} }
} }
return SubString( return SubString(string, Unsigned(startIndex), Unsigned(endIndex + 1));
receiverString, Unsigned(startIndex), Unsigned(endIndex + 1)); }
transitioning macro StringTrim(implicit context: Context)(
receiver: JSAny, _arguments: Arguments, methodName: constexpr string,
variant: constexpr TrimMode): String {
const receiverString: String = ToThisString(receiver, methodName);
try {
GetStringData(receiverString) otherwise OneByte, TwoByte;
} label OneByte(slice: ConstSlice<char8>) {
return StringTrimBody(receiverString, slice, variant);
} label TwoByte(slice: ConstSlice<char16>) {
return StringTrimBody(receiverString, slice, variant);
}
} }
// ES6 #sec-string.prototype.trim // ES6 #sec-string.prototype.trim
...@@ -161,8 +171,3 @@ StringPrototypeTrimEnd( ...@@ -161,8 +171,3 @@ StringPrototypeTrimEnd(
return StringTrim(receiver, arguments, methodName, TrimMode::kTrimEnd); return StringTrim(receiver, arguments, methodName, TrimMode::kTrimEnd);
} }
} }
namespace runtime {
extern runtime StringTrim(implicit context: Context)(
String, SmiTagged<string::TrimMode>): String;
}
...@@ -335,7 +335,6 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) { ...@@ -335,7 +335,6 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(StringReplaceOneCharWithString) \ V(StringReplaceOneCharWithString) \
V(StringSubstring) \ V(StringSubstring) \
V(StringToNumber) \ V(StringToNumber) \
V(StringTrim) \
/* BigInts */ \ /* BigInts */ \
V(BigIntEqualToBigInt) \ V(BigIntEqualToBigInt) \
V(BigIntToBoolean) \ V(BigIntToBoolean) \
......
...@@ -411,32 +411,6 @@ void String::PrintUC16(StringStream* accumulator, int start, int end) { ...@@ -411,32 +411,6 @@ void String::PrintUC16(StringStream* accumulator, int start, int end) {
} }
} }
// static
Handle<String> String::Trim(Isolate* isolate, Handle<String> string,
TrimMode mode) {
string = String::Flatten(isolate, string);
int const length = string->length();
// Perform left trimming if requested.
int left = 0;
if (mode == kTrim || mode == kTrimStart) {
while (left < length && IsWhiteSpaceOrLineTerminator(string->Get(left))) {
left++;
}
}
// Perform right trimming if requested.
int right = length;
if (mode == kTrim || mode == kTrimEnd) {
while (right > left &&
IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
right--;
}
}
return isolate->factory()->NewSubString(string, left, right);
}
int32_t String::ToArrayIndex(Address addr) { int32_t String::ToArrayIndex(Address addr) {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
String key(addr); String key(addr);
......
...@@ -385,8 +385,6 @@ class String : public TorqueGeneratedString<String, Name> { ...@@ -385,8 +385,6 @@ class String : public TorqueGeneratedString<String, Name> {
// Trimming. // Trimming.
enum TrimMode { kTrim, kTrimStart, kTrimEnd }; enum TrimMode { kTrim, kTrimStart, kTrimEnd };
static Handle<String> Trim(Isolate* isolate, Handle<String> string,
TrimMode mode);
V8_EXPORT_PRIVATE void PrintOn(FILE* out); V8_EXPORT_PRIVATE void PrintOn(FILE* out);
......
...@@ -139,15 +139,6 @@ RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) { ...@@ -139,15 +139,6 @@ RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
return isolate->StackOverflow(); return isolate->StackOverflow();
} }
RUNTIME_FUNCTION(Runtime_StringTrim) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<String> string = args.at<String>(0);
CONVERT_SMI_ARG_CHECKED(mode, 1);
String::TrimMode trim_mode = static_cast<String::TrimMode>(mode);
return *String::Trim(isolate, string, trim_mode);
}
// ES6 #sec-string.prototype.includes // ES6 #sec-string.prototype.includes
// String.prototype.includes(searchString [, position]) // String.prototype.includes(searchString [, position])
RUNTIME_FUNCTION(Runtime_StringIncludes) { RUNTIME_FUNCTION(Runtime_StringIncludes) {
......
...@@ -440,8 +440,7 @@ namespace internal { ...@@ -440,8 +440,7 @@ namespace internal {
F(StringMaxLength, 0, 1) \ F(StringMaxLength, 0, 1) \
F(StringReplaceOneCharWithString, 3, 1) \ F(StringReplaceOneCharWithString, 3, 1) \
F(StringSubstring, 3, 1) \ F(StringSubstring, 3, 1) \
F(StringToArray, 2, 1) \ F(StringToArray, 2, 1)
F(StringTrim, 2, 1)
#define FOR_EACH_INTRINSIC_SYMBOL(F, I) \ #define FOR_EACH_INTRINSIC_SYMBOL(F, I) \
F(CreatePrivateNameSymbol, 1, 1) \ F(CreatePrivateNameSymbol, 1, 1) \
......
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