| Index: src/builtins/builtins-string.cc
|
| diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc
|
| index 629b7ebb7f59780bb5ab348ddfbbc8edc909ef4d..f2b784cf053b409f5a7982329d3839582afa9d27 100644
|
| --- a/src/builtins/builtins-string.cc
|
| +++ b/src/builtins/builtins-string.cc
|
| @@ -60,6 +60,10 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
|
|
| Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index,
|
| UnicodeEncoding encoding);
|
| +
|
| + void StringIndexOf(Node* receiver, Node* instance_type, Node* search_string,
|
| + Node* search_string_instance_type, Node* position,
|
| + std::function<void(Node*)> f_return);
|
| };
|
|
|
| void StringBuiltinsAssembler::GenerateStringEqual(ResultMode mode) {
|
| @@ -785,7 +789,93 @@ BUILTIN(StringPrototypeIncludes) {
|
| return *isolate->factory()->ToBoolean(index_in_str != -1);
|
| }
|
|
|
| -// ES6 #sec-string.prototype.indexof
|
| +void StringBuiltinsAssembler::StringIndexOf(
|
| + Node* receiver, Node* instance_type, Node* search_string,
|
| + Node* search_string_instance_type, Node* position,
|
| + std::function<void(Node*)> f_return) {
|
| + CSA_ASSERT(this, IsString(receiver));
|
| + CSA_ASSERT(this, IsString(search_string));
|
| + CSA_ASSERT(this, TaggedIsSmi(position));
|
| +
|
| + Label zero_length_needle(this), call_runtime_unchecked(this),
|
| + return_minus_1(this), check_search_string(this), continue_fast_path(this);
|
| +
|
| + Node* needle_length = SmiUntag(LoadStringLength(search_string));
|
| + // Use faster/complex runtime fallback for long search strings.
|
| + GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length),
|
| + &call_runtime_unchecked);
|
| + Node* string_length = SmiUntag(LoadStringLength(receiver));
|
| + Node* start_position = SmiUntag(position);
|
| +
|
| + GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
|
| + // Check that the needle fits in the start position.
|
| + GotoUnless(IntPtrLessThanOrEqual(needle_length,
|
| + IntPtrSub(string_length, start_position)),
|
| + &return_minus_1);
|
| + // Only support one-byte strings on the fast path.
|
| + BranchIfSimpleOneByteStringInstanceType(instance_type, &check_search_string,
|
| + &call_runtime_unchecked);
|
| + Bind(&check_search_string);
|
| + BranchIfSimpleOneByteStringInstanceType(search_string_instance_type,
|
| + &continue_fast_path,
|
| + &call_runtime_unchecked);
|
| + Bind(&continue_fast_path);
|
| + {
|
| + Node* needle_byte =
|
| + ChangeInt32ToIntPtr(LoadOneByteChar(search_string, IntPtrConstant(0)));
|
| + Node* start_address = OneByteCharAddress(receiver, start_position);
|
| + Node* search_length = IntPtrSub(string_length, start_position);
|
| + // Call out to the highly optimized memchr to perform the actual byte
|
| + // search.
|
| + Node* memchr =
|
| + ExternalConstant(ExternalReference::libc_memchr_function(isolate()));
|
| + Node* result_address =
|
| + CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
|
| + MachineType::IntPtr(), MachineType::UintPtr(), memchr,
|
| + start_address, needle_byte, search_length);
|
| + GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1);
|
| + Node* result_index =
|
| + IntPtrAdd(IntPtrSub(result_address, start_address), start_position);
|
| + f_return(SmiTag(result_index));
|
| + }
|
| + Bind(&return_minus_1);
|
| + { f_return(SmiConstant(-1)); }
|
| + Bind(&zero_length_needle);
|
| + {
|
| + Comment("0-length search_string");
|
| + f_return(SmiTag(IntPtrMin(string_length, start_position)));
|
| + }
|
| + Bind(&call_runtime_unchecked);
|
| + {
|
| + // Simplified version of the runtime call where the types of the arguments
|
| + // are already known due to type checks in this stub.
|
| + Comment("Call Runtime Unchecked");
|
| + Node* result = CallRuntime(Runtime::kStringIndexOfUnchecked, SmiConstant(0),
|
| + receiver, search_string, position);
|
| + f_return(result);
|
| + }
|
| +}
|
| +
|
| +// ES6 String.prototype.indexOf(searchString [, position])
|
| +// #sec-string.prototype.indexof
|
| +// Unchecked helper for builtins lowering.
|
| +TF_BUILTIN(StringIndexOf, StringBuiltinsAssembler) {
|
| + Node* receiver = Parameter(0);
|
| + Node* search_string = Parameter(1);
|
| + Node* position = Parameter(2);
|
| +
|
| + Label call_runtime(this);
|
| +
|
| + Node* instance_type = LoadInstanceType(receiver);
|
| + Node* search_string_instance_type = LoadInstanceType(search_string);
|
| +
|
| + StringIndexOf(receiver, instance_type, search_string,
|
| + search_string_instance_type, position,
|
| + [this](Node* result) { this->Return(result); });
|
| +}
|
| +
|
| +// ES6 String.prototype.indexOf(searchString [, position])
|
| +// #sec-string.prototype.indexof
|
| TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
|
| Variable search_string(this, MachineRepresentation::kTagged),
|
| position(this, MachineRepresentation::kTagged);
|
| @@ -832,67 +922,21 @@ TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
|
| Bind(&fast_path);
|
| {
|
| Comment("Fast Path");
|
| - Label zero_length_needle(this);
|
| GotoIf(TaggedIsSmi(receiver), &call_runtime);
|
| Node* needle = search_string.value();
|
| GotoIf(TaggedIsSmi(needle), &call_runtime);
|
| +
|
| Node* instance_type = LoadInstanceType(receiver);
|
| GotoUnless(IsStringInstanceType(instance_type), &call_runtime);
|
|
|
| Node* needle_instance_type = LoadInstanceType(needle);
|
| GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime);
|
|
|
| - // At this point we know that the receiver and the needle are Strings and
|
| - // that position is a Smi.
|
| -
|
| - Node* needle_length = SmiUntag(LoadStringLength(needle));
|
| - // Use possibly faster runtime fallback for long search strings.
|
| - GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length),
|
| - &call_runtime_unchecked);
|
| - Node* string_length = SmiUntag(LoadStringLength(receiver));
|
| - Node* start_position = SmiUntag(position.value());
|
| -
|
| - GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
|
| - // Check that the needle fits in the start position.
|
| - GotoUnless(IntPtrLessThanOrEqual(needle_length,
|
| - IntPtrSub(string_length, start_position)),
|
| - &return_minus_1);
|
| - // Only support one-byte strings on the fast path.
|
| - Label check_needle(this), continue_fast_path(this);
|
| - BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle,
|
| - &call_runtime_unchecked);
|
| - Bind(&check_needle);
|
| - BranchIfSimpleOneByteStringInstanceType(
|
| - needle_instance_type, &continue_fast_path, &call_runtime_unchecked);
|
| - Bind(&continue_fast_path);
|
| - {
|
| - Node* needle_byte =
|
| - ChangeInt32ToIntPtr(LoadOneByteChar(needle, IntPtrConstant(0)));
|
| - Node* start_address = OneByteCharAddress(receiver, start_position);
|
| - Node* search_length = IntPtrSub(string_length, start_position);
|
| - // Call out to the highly optimized memchr to perform the actual byte
|
| - // search.
|
| - Node* memchr =
|
| - ExternalConstant(ExternalReference::libc_memchr_function(isolate()));
|
| - Node* result_address =
|
| - CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
|
| - MachineType::IntPtr(), MachineType::UintPtr(), memchr,
|
| - start_address, needle_byte, search_length);
|
| - GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1);
|
| - Node* result_index =
|
| - IntPtrAdd(IntPtrSub(result_address, start_address), start_position);
|
| - arguments.PopAndReturn(SmiTag(result_index));
|
| - }
|
| - Bind(&zero_length_needle);
|
| - {
|
| - Comment("0-length needle");
|
| - arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position)));
|
| - }
|
| + StringIndexOf(
|
| + receiver, instance_type, needle, needle_instance_type, position.value(),
|
| + [&arguments](Node* result) { arguments.PopAndReturn(result); });
|
| }
|
|
|
| - Bind(&return_minus_1);
|
| - { arguments.PopAndReturn(SmiConstant(-1)); }
|
| -
|
| Bind(&call_runtime);
|
| {
|
| Comment("Call Runtime");
|
| @@ -900,17 +944,6 @@ TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
|
| search_string.value(), position.value());
|
| arguments.PopAndReturn(result);
|
| }
|
| -
|
| - Bind(&call_runtime_unchecked);
|
| - {
|
| - // Simplified version of the runtime call where the types of the arguments
|
| - // are already known due to type checks in this stub.
|
| - Comment("Call Runtime Unchecked");
|
| - Node* result =
|
| - CallRuntime(Runtime::kStringIndexOfUnchecked, context, receiver,
|
| - search_string.value(), position.value());
|
| - arguments.PopAndReturn(result);
|
| - }
|
| }
|
|
|
| // ES6 section 21.1.3.9
|
|
|