| Index: src/builtins/builtins-string.cc
|
| diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc
|
| index d3fae3764f8165f0936e23468224f4fd5add66d6..4ca3594db74f1c105bb206438e181f3a056621c1 100644
|
| --- a/src/builtins/builtins-string.cc
|
| +++ b/src/builtins/builtins-string.cc
|
| @@ -64,7 +64,7 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
|
|
| Node* OneByteCharAddress(Node* string, Node* index) {
|
| Node* offset = OneByteCharOffset(index);
|
| - return IntPtrAdd(BitcastTaggedToWord(string), offset);
|
| + return IntPtrAdd(string, offset);
|
| }
|
|
|
| Node* OneByteCharOffset(Node* index) {
|
| @@ -81,14 +81,25 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
| return offset;
|
| }
|
|
|
| - void BranchIfSimpleOneByteStringInstanceType(Node* instance_type,
|
| - Label* if_true,
|
| - Label* if_false) {
|
| + void DispatchOnStringInstanceType(Node* const instance_type,
|
| + Label* if_onebyte_sequential,
|
| + Label* if_onebyte_external,
|
| + Label* if_otherwise) {
|
| const int kMask = kStringRepresentationMask | kStringEncodingMask;
|
| - const int kType = kOneByteStringTag | kSeqStringTag;
|
| - Branch(Word32Equal(Word32And(instance_type, Int32Constant(kMask)),
|
| - Int32Constant(kType)),
|
| - if_true, if_false);
|
| + Node* const encoding_and_representation =
|
| + Word32And(instance_type, Int32Constant(kMask));
|
| +
|
| + int32_t values[] = {
|
| + kOneByteStringTag | kSeqStringTag,
|
| + kOneByteStringTag | kExternalStringTag,
|
| + };
|
| + Label* labels[] = {
|
| + if_onebyte_sequential, if_onebyte_external,
|
| + };
|
| + STATIC_ASSERT(arraysize(values) == arraysize(labels));
|
| +
|
| + Switch(encoding_and_representation, if_otherwise, values, labels,
|
| + arraysize(values));
|
| }
|
|
|
| void GenerateStringEqual(ResultMode mode);
|
| @@ -861,33 +872,85 @@ void StringBuiltinsAssembler::StringIndexOf(
|
| 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);
|
| + Label zero_length_needle(this),
|
| + call_runtime_unchecked(this, Label::kDeferred), return_minus_1(this),
|
| + check_search_string(this), continue_fast_path(this);
|
| +
|
| + Node* const int_zero = IntPtrConstant(0);
|
| + Variable var_needle_byte(this, MachineType::PointerRepresentation(),
|
| + int_zero);
|
| + Variable var_string_addr(this, MachineType::PointerRepresentation(),
|
| + int_zero);
|
|
|
| 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 = IntPtrMax(SmiUntag(position), IntPtrConstant(0));
|
| + Node* start_position = IntPtrMax(SmiUntag(position), int_zero);
|
|
|
| - GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
|
| + GotoIf(IntPtrEqual(int_zero, needle_length), &zero_length_needle);
|
| // Check that the needle fits in the start position.
|
| GotoIfNot(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);
|
| +
|
| + // Load the string address.
|
| + {
|
| + Label if_onebyte_sequential(this);
|
| + Label if_onebyte_external(this, Label::kDeferred);
|
| +
|
| + // Only support one-byte strings on the fast path.
|
| + DispatchOnStringInstanceType(instance_type, &if_onebyte_sequential,
|
| + &if_onebyte_external, &call_runtime_unchecked);
|
| +
|
| + Bind(&if_onebyte_sequential);
|
| + {
|
| + var_string_addr.Bind(
|
| + OneByteCharAddress(BitcastTaggedToWord(receiver), start_position));
|
| + Goto(&check_search_string);
|
| + }
|
| +
|
| + Bind(&if_onebyte_external);
|
| + {
|
| + Node* const unpacked = TryDerefExternalString(receiver, instance_type,
|
| + &call_runtime_unchecked);
|
| + var_string_addr.Bind(OneByteCharAddress(unpacked, start_position));
|
| + Goto(&check_search_string);
|
| + }
|
| + }
|
| +
|
| + // Load the needle character.
|
| Bind(&check_search_string);
|
| - BranchIfSimpleOneByteStringInstanceType(search_string_instance_type,
|
| - &continue_fast_path,
|
| - &call_runtime_unchecked);
|
| + {
|
| + Label if_onebyte_sequential(this);
|
| + Label if_onebyte_external(this, Label::kDeferred);
|
| +
|
| + DispatchOnStringInstanceType(search_string_instance_type,
|
| + &if_onebyte_sequential, &if_onebyte_external,
|
| + &call_runtime_unchecked);
|
| +
|
| + Bind(&if_onebyte_sequential);
|
| + {
|
| + var_needle_byte.Bind(
|
| + ChangeInt32ToIntPtr(LoadOneByteChar(search_string, int_zero)));
|
| + Goto(&continue_fast_path);
|
| + }
|
| +
|
| + Bind(&if_onebyte_external);
|
| + {
|
| + Node* const unpacked = TryDerefExternalString(
|
| + search_string, search_string_instance_type, &call_runtime_unchecked);
|
| + var_needle_byte.Bind(
|
| + ChangeInt32ToIntPtr(LoadOneByteChar(unpacked, int_zero)));
|
| + Goto(&continue_fast_path);
|
| + }
|
| + }
|
| +
|
| Bind(&continue_fast_path);
|
| {
|
| - Node* needle_byte =
|
| - ChangeInt32ToIntPtr(LoadOneByteChar(search_string, IntPtrConstant(0)));
|
| - Node* start_address = OneByteCharAddress(receiver, start_position);
|
| + Node* needle_byte = var_needle_byte.value();
|
| + Node* string_addr = var_string_addr.value();
|
| Node* search_length = IntPtrSub(string_length, start_position);
|
| // Call out to the highly optimized memchr to perform the actual byte
|
| // search.
|
| @@ -896,19 +959,22 @@ void StringBuiltinsAssembler::StringIndexOf(
|
| 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);
|
| + string_addr, needle_byte, search_length);
|
| + GotoIf(WordEqual(result_address, int_zero), &return_minus_1);
|
| Node* result_index =
|
| - IntPtrAdd(IntPtrSub(result_address, start_address), start_position);
|
| + IntPtrAdd(IntPtrSub(result_address, string_addr), start_position);
|
| f_return(SmiTag(result_index));
|
| }
|
| +
|
| Bind(&return_minus_1);
|
| - { f_return(SmiConstant(-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
|
|
|