[cleanup] Move string functions out of CSA
Moves the following functions from CodeStubAssembler to BuiltinsStringAssembler: SubString CopyStringCharacters AllocAndCopyStringCharacters Bug: v8:9396 Change-Id: Ieb534b7fa7e72db9b05cdc2a34bd88b7a52ee985 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1822040 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Dan Elphick <delphick@chromium.org> Auto-Submit: Dan Elphick <delphick@chromium.org> Cr-Commit-Position: refs/heads/master@{#63959}
This commit is contained in:
parent
d3253633b2
commit
0f15403a04
@ -806,7 +806,7 @@ TF_BUILTIN(StringFromCodePointAt, StringBuiltinsAssembler) {
|
||||
// ES6 section 21.1 String Objects
|
||||
|
||||
// ES6 #sec-string.fromcharcode
|
||||
TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
|
||||
TF_BUILTIN(StringFromCharCode, StringBuiltinsAssembler) {
|
||||
// TODO(ishell): use constants from Descriptor once the JSFunction linkage
|
||||
// arguments are reordered.
|
||||
TNode<Int32T> argc =
|
||||
@ -1864,7 +1864,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(StringSubstring, CodeStubAssembler) {
|
||||
TF_BUILTIN(StringSubstring, StringBuiltinsAssembler) {
|
||||
TNode<String> string = CAST(Parameter(Descriptor::kString));
|
||||
TNode<IntPtrT> from = UncheckedCast<IntPtrT>(Parameter(Descriptor::kFrom));
|
||||
TNode<IntPtrT> to = UncheckedCast<IntPtrT>(Parameter(Descriptor::kTo));
|
||||
@ -2124,5 +2124,244 @@ void StringBuiltinsAssembler::BranchIfStringPrimitiveWithNoCustomIteration(
|
||||
if_true, if_false);
|
||||
}
|
||||
|
||||
void StringBuiltinsAssembler::CopyStringCharacters(
|
||||
Node* from_string, Node* to_string, TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> to_index, TNode<IntPtrT> character_count,
|
||||
String::Encoding from_encoding, String::Encoding to_encoding) {
|
||||
// Cannot assert IsString(from_string) and IsString(to_string) here because
|
||||
// SubString can pass in faked sequential strings when handling external
|
||||
// subject strings.
|
||||
bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING;
|
||||
bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING;
|
||||
DCHECK_IMPLIES(to_one_byte, from_one_byte);
|
||||
Comment("CopyStringCharacters ",
|
||||
from_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING", " -> ",
|
||||
to_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING");
|
||||
|
||||
ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
|
||||
ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
|
||||
STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
||||
int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag;
|
||||
TNode<IntPtrT> from_offset =
|
||||
ElementOffsetFromIndex(from_index, from_kind, header_size);
|
||||
TNode<IntPtrT> to_offset =
|
||||
ElementOffsetFromIndex(to_index, to_kind, header_size);
|
||||
TNode<IntPtrT> byte_count =
|
||||
ElementOffsetFromIndex(character_count, from_kind);
|
||||
TNode<IntPtrT> limit_offset = IntPtrAdd(from_offset, byte_count);
|
||||
|
||||
// Prepare the fast loop
|
||||
MachineType type =
|
||||
from_one_byte ? MachineType::Uint8() : MachineType::Uint16();
|
||||
MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8
|
||||
: MachineRepresentation::kWord16;
|
||||
int from_increment = 1 << ElementsKindToShiftSize(from_kind);
|
||||
int to_increment = 1 << ElementsKindToShiftSize(to_kind);
|
||||
|
||||
TVARIABLE(IntPtrT, current_to_offset, to_offset);
|
||||
VariableList vars({¤t_to_offset}, zone());
|
||||
int to_index_constant = 0, from_index_constant = 0;
|
||||
bool index_same = (from_encoding == to_encoding) &&
|
||||
(from_index == to_index ||
|
||||
(ToInt32Constant(from_index, &from_index_constant) &&
|
||||
ToInt32Constant(to_index, &to_index_constant) &&
|
||||
from_index_constant == to_index_constant));
|
||||
BuildFastLoop<IntPtrT>(
|
||||
vars, from_offset, limit_offset,
|
||||
[&](TNode<IntPtrT> offset) {
|
||||
Node* value = Load(type, from_string, offset);
|
||||
StoreNoWriteBarrier(rep, to_string,
|
||||
index_same ? offset : current_to_offset.value(),
|
||||
value);
|
||||
if (!index_same) {
|
||||
Increment(¤t_to_offset, to_increment);
|
||||
}
|
||||
},
|
||||
from_increment, IndexAdvanceMode::kPost);
|
||||
}
|
||||
|
||||
// A wrapper around CopyStringCharacters which determines the correct string
|
||||
// encoding, allocates a corresponding sequential string, and then copies the
|
||||
// given character range using CopyStringCharacters.
|
||||
// |from_string| must be a sequential string.
|
||||
// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length.
|
||||
TNode<String> StringBuiltinsAssembler::AllocAndCopyStringCharacters(
|
||||
Node* from, Node* from_instance_type, TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> character_count) {
|
||||
Label end(this), one_byte_sequential(this), two_byte_sequential(this);
|
||||
TVARIABLE(String, var_result);
|
||||
|
||||
Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential,
|
||||
&two_byte_sequential);
|
||||
|
||||
// The subject string is a sequential one-byte string.
|
||||
BIND(&one_byte_sequential);
|
||||
{
|
||||
TNode<String> result = AllocateSeqOneByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(character_count)));
|
||||
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
|
||||
character_count, String::ONE_BYTE_ENCODING,
|
||||
String::ONE_BYTE_ENCODING);
|
||||
var_result = result;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// The subject string is a sequential two-byte string.
|
||||
BIND(&two_byte_sequential);
|
||||
{
|
||||
TNode<String> result = AllocateSeqTwoByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(character_count)));
|
||||
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
|
||||
character_count, String::TWO_BYTE_ENCODING,
|
||||
String::TWO_BYTE_ENCODING);
|
||||
var_result = result;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<String> StringBuiltinsAssembler::SubString(TNode<String> string,
|
||||
TNode<IntPtrT> from,
|
||||
TNode<IntPtrT> to) {
|
||||
TVARIABLE(String, var_result);
|
||||
ToDirectStringAssembler to_direct(state(), string);
|
||||
Label end(this), runtime(this);
|
||||
|
||||
TNode<IntPtrT> const substr_length = IntPtrSub(to, from);
|
||||
TNode<IntPtrT> const string_length = LoadStringLengthAsWord(string);
|
||||
|
||||
// Begin dispatching based on substring length.
|
||||
|
||||
Label original_string_or_invalid_length(this);
|
||||
GotoIf(UintPtrGreaterThanOrEqual(substr_length, string_length),
|
||||
&original_string_or_invalid_length);
|
||||
|
||||
// A real substring (substr_length < string_length).
|
||||
Label empty(this);
|
||||
GotoIf(IntPtrEqual(substr_length, IntPtrConstant(0)), &empty);
|
||||
|
||||
Label single_char(this);
|
||||
GotoIf(IntPtrEqual(substr_length, IntPtrConstant(1)), &single_char);
|
||||
|
||||
// Deal with different string types: update the index if necessary
|
||||
// and extract the underlying string.
|
||||
|
||||
TNode<String> direct_string = to_direct.TryToDirect(&runtime);
|
||||
TNode<IntPtrT> offset = IntPtrAdd(from, to_direct.offset());
|
||||
TNode<Int32T> const instance_type = to_direct.instance_type();
|
||||
|
||||
// The subject string can only be external or sequential string of either
|
||||
// encoding at this point.
|
||||
Label external_string(this);
|
||||
{
|
||||
if (FLAG_string_slices) {
|
||||
Label next(this);
|
||||
|
||||
// Short slice. Copy instead of slicing.
|
||||
GotoIf(IntPtrLessThan(substr_length,
|
||||
IntPtrConstant(SlicedString::kMinLength)),
|
||||
&next);
|
||||
|
||||
// Allocate new sliced string.
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Label one_byte_slice(this), two_byte_slice(this);
|
||||
Branch(IsOneByteStringInstanceType(to_direct.instance_type()),
|
||||
&one_byte_slice, &two_byte_slice);
|
||||
|
||||
BIND(&one_byte_slice);
|
||||
{
|
||||
var_result = AllocateSlicedOneByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
|
||||
SmiTag(offset));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&two_byte_slice);
|
||||
{
|
||||
var_result = AllocateSlicedTwoByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
|
||||
SmiTag(offset));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
// The subject string can only be external or sequential string of either
|
||||
// encoding at this point.
|
||||
GotoIf(to_direct.is_external(), &external_string);
|
||||
|
||||
var_result = AllocAndCopyStringCharacters(direct_string, instance_type,
|
||||
offset, substr_length);
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Handle external string.
|
||||
BIND(&external_string);
|
||||
{
|
||||
TNode<RawPtrT> const fake_sequential_string =
|
||||
to_direct.PointerToString(&runtime);
|
||||
|
||||
var_result = AllocAndCopyStringCharacters(
|
||||
fake_sequential_string, instance_type, offset, substr_length);
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&empty);
|
||||
{
|
||||
var_result = EmptyStringConstant();
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Substrings of length 1 are generated through CharCodeAt and FromCharCode.
|
||||
BIND(&single_char);
|
||||
{
|
||||
TNode<Int32T> char_code = StringCharCodeAt(string, from);
|
||||
var_result = StringFromSingleCharCode(char_code);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&original_string_or_invalid_length);
|
||||
{
|
||||
CSA_ASSERT(this, IntPtrEqual(substr_length, string_length));
|
||||
|
||||
// Equal length - check if {from, to} == {0, str.length}.
|
||||
GotoIf(UintPtrGreaterThan(from, IntPtrConstant(0)), &runtime);
|
||||
|
||||
// Return the original string (substr_length == string_length).
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
var_result = string;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Fall back to a runtime call.
|
||||
BIND(&runtime);
|
||||
{
|
||||
var_result =
|
||||
CAST(CallRuntime(Runtime::kStringSubstring, NoContextConstant(), string,
|
||||
SmiTag(from), SmiTag(to)));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -35,6 +35,23 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
|
||||
TNode<String> StringFromSingleUTF16EncodedCodePoint(TNode<Int32T> codepoint);
|
||||
|
||||
// Return a new string object which holds a substring containing the range
|
||||
// [from,to[ of string.
|
||||
TNode<String> SubString(TNode<String> string, TNode<IntPtrT> from,
|
||||
TNode<IntPtrT> to);
|
||||
|
||||
// Copies |character_count| elements from |from_string| to |to_string|
|
||||
// starting at the |from_index|'th character. |from_string| and |to_string|
|
||||
// can either be one-byte strings or two-byte strings, although if
|
||||
// |from_string| is two-byte, then |to_string| must be two-byte.
|
||||
// |from_index|, |to_index| and |character_count| must be intptr_ts s.t. 0 <=
|
||||
// |from_index| <= |from_index| + |character_count| <= from_string.length and
|
||||
// 0 <= |to_index| <= |to_index| + |character_count| <= to_string.length.
|
||||
V8_EXPORT_PRIVATE void CopyStringCharacters(
|
||||
Node* from_string, Node* to_string, TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> to_index, TNode<IntPtrT> character_count,
|
||||
String::Encoding from_encoding, String::Encoding to_encoding);
|
||||
|
||||
protected:
|
||||
void StringEqual_Loop(Node* lhs, Node* lhs_instance_type,
|
||||
MachineType lhs_type, Node* rhs,
|
||||
@ -137,6 +154,12 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
Handle<Symbol> symbol,
|
||||
DescriptorIndexNameValue additional_property_to_check,
|
||||
const NodeFunction0& regexp_call, const NodeFunction1& generic_call);
|
||||
|
||||
private:
|
||||
TNode<String> AllocAndCopyStringCharacters(Node* from,
|
||||
Node* from_instance_type,
|
||||
TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> character_count);
|
||||
};
|
||||
|
||||
class StringIncludesIndexOfAssembler : public StringBuiltinsAssembler {
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
namespace string_slice {
|
||||
|
||||
extern macro SubString(String, intptr, intptr): String;
|
||||
extern macro StringBuiltinsAssembler::SubString(String, intptr, intptr):
|
||||
String;
|
||||
|
||||
// ES6 #sec-string.prototype.slice ( start, end )
|
||||
// https://tc39.github.io/ecma262/#sec-string.prototype.slice
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
namespace string_substring {
|
||||
|
||||
extern macro SubString(String, intptr, intptr): String;
|
||||
extern macro StringBuiltinsAssembler::SubString(String, intptr, intptr):
|
||||
String;
|
||||
|
||||
transitioning macro ToSmiBetweenZeroAnd(implicit context: Context)(
|
||||
value: JSAny, limit: Smi): Smi {
|
||||
|
@ -5266,64 +5266,6 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
|
||||
Comment("] CopyPropertyArrayValues");
|
||||
}
|
||||
|
||||
void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string,
|
||||
TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> to_index,
|
||||
TNode<IntPtrT> character_count,
|
||||
String::Encoding from_encoding,
|
||||
String::Encoding to_encoding) {
|
||||
// Cannot assert IsString(from_string) and IsString(to_string) here because
|
||||
// CSA::SubString can pass in faked sequential strings when handling external
|
||||
// subject strings.
|
||||
bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING;
|
||||
bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING;
|
||||
DCHECK_IMPLIES(to_one_byte, from_one_byte);
|
||||
Comment("CopyStringCharacters ",
|
||||
from_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING", " -> ",
|
||||
to_one_byte ? "ONE_BYTE_ENCODING" : "TWO_BYTE_ENCODING");
|
||||
|
||||
ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
|
||||
ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
|
||||
STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
|
||||
int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag;
|
||||
TNode<IntPtrT> from_offset =
|
||||
ElementOffsetFromIndex(from_index, from_kind, header_size);
|
||||
TNode<IntPtrT> to_offset =
|
||||
ElementOffsetFromIndex(to_index, to_kind, header_size);
|
||||
TNode<IntPtrT> byte_count =
|
||||
ElementOffsetFromIndex(character_count, from_kind);
|
||||
TNode<IntPtrT> limit_offset = IntPtrAdd(from_offset, byte_count);
|
||||
|
||||
// Prepare the fast loop
|
||||
MachineType type =
|
||||
from_one_byte ? MachineType::Uint8() : MachineType::Uint16();
|
||||
MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8
|
||||
: MachineRepresentation::kWord16;
|
||||
int from_increment = 1 << ElementsKindToShiftSize(from_kind);
|
||||
int to_increment = 1 << ElementsKindToShiftSize(to_kind);
|
||||
|
||||
TVARIABLE(IntPtrT, current_to_offset, to_offset);
|
||||
VariableList vars({¤t_to_offset}, zone());
|
||||
int to_index_constant = 0, from_index_constant = 0;
|
||||
bool index_same = (from_encoding == to_encoding) &&
|
||||
(from_index == to_index ||
|
||||
(ToInt32Constant(from_index, &from_index_constant) &&
|
||||
ToInt32Constant(to_index, &to_index_constant) &&
|
||||
from_index_constant == to_index_constant));
|
||||
BuildFastLoop<IntPtrT>(
|
||||
vars, from_offset, limit_offset,
|
||||
[&](TNode<IntPtrT> offset) {
|
||||
Node* value = Load(type, from_string, offset);
|
||||
StoreNoWriteBarrier(rep, to_string,
|
||||
index_same ? offset : current_to_offset.value(),
|
||||
value);
|
||||
if (!index_same) {
|
||||
Increment(¤t_to_offset, to_increment);
|
||||
}
|
||||
},
|
||||
from_increment, IndexAdvanceMode::kPost);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
|
||||
Node* offset,
|
||||
ElementsKind from_kind,
|
||||
@ -6966,189 +6908,6 @@ TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) {
|
||||
return CAST(var_result.value());
|
||||
}
|
||||
|
||||
// A wrapper around CopyStringCharacters which determines the correct string
|
||||
// encoding, allocates a corresponding sequential string, and then copies the
|
||||
// given character range using CopyStringCharacters.
|
||||
// |from_string| must be a sequential string.
|
||||
// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length.
|
||||
TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters(
|
||||
Node* from, Node* from_instance_type, TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> character_count) {
|
||||
Label end(this), one_byte_sequential(this), two_byte_sequential(this);
|
||||
TVARIABLE(String, var_result);
|
||||
|
||||
Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential,
|
||||
&two_byte_sequential);
|
||||
|
||||
// The subject string is a sequential one-byte string.
|
||||
BIND(&one_byte_sequential);
|
||||
{
|
||||
TNode<String> result = AllocateSeqOneByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(character_count)));
|
||||
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
|
||||
character_count, String::ONE_BYTE_ENCODING,
|
||||
String::ONE_BYTE_ENCODING);
|
||||
var_result = result;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// The subject string is a sequential two-byte string.
|
||||
BIND(&two_byte_sequential);
|
||||
{
|
||||
TNode<String> result = AllocateSeqTwoByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(character_count)));
|
||||
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
|
||||
character_count, String::TWO_BYTE_ENCODING,
|
||||
String::TWO_BYTE_ENCODING);
|
||||
var_result = result;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<String> CodeStubAssembler::SubString(TNode<String> string,
|
||||
TNode<IntPtrT> from,
|
||||
TNode<IntPtrT> to) {
|
||||
TVARIABLE(String, var_result);
|
||||
ToDirectStringAssembler to_direct(state(), string);
|
||||
Label end(this), runtime(this);
|
||||
|
||||
TNode<IntPtrT> const substr_length = IntPtrSub(to, from);
|
||||
TNode<IntPtrT> const string_length = LoadStringLengthAsWord(string);
|
||||
|
||||
// Begin dispatching based on substring length.
|
||||
|
||||
Label original_string_or_invalid_length(this);
|
||||
GotoIf(UintPtrGreaterThanOrEqual(substr_length, string_length),
|
||||
&original_string_or_invalid_length);
|
||||
|
||||
// A real substring (substr_length < string_length).
|
||||
Label empty(this);
|
||||
GotoIf(IntPtrEqual(substr_length, IntPtrConstant(0)), &empty);
|
||||
|
||||
Label single_char(this);
|
||||
GotoIf(IntPtrEqual(substr_length, IntPtrConstant(1)), &single_char);
|
||||
|
||||
// Deal with different string types: update the index if necessary
|
||||
// and extract the underlying string.
|
||||
|
||||
TNode<String> direct_string = to_direct.TryToDirect(&runtime);
|
||||
TNode<IntPtrT> offset = IntPtrAdd(from, to_direct.offset());
|
||||
TNode<Int32T> const instance_type = to_direct.instance_type();
|
||||
|
||||
// The subject string can only be external or sequential string of either
|
||||
// encoding at this point.
|
||||
Label external_string(this);
|
||||
{
|
||||
if (FLAG_string_slices) {
|
||||
Label next(this);
|
||||
|
||||
// Short slice. Copy instead of slicing.
|
||||
GotoIf(IntPtrLessThan(substr_length,
|
||||
IntPtrConstant(SlicedString::kMinLength)),
|
||||
&next);
|
||||
|
||||
// Allocate new sliced string.
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Label one_byte_slice(this), two_byte_slice(this);
|
||||
Branch(IsOneByteStringInstanceType(to_direct.instance_type()),
|
||||
&one_byte_slice, &two_byte_slice);
|
||||
|
||||
BIND(&one_byte_slice);
|
||||
{
|
||||
var_result = AllocateSlicedOneByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
|
||||
SmiTag(offset));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&two_byte_slice);
|
||||
{
|
||||
var_result = AllocateSlicedTwoByteString(
|
||||
Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
|
||||
SmiTag(offset));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
// The subject string can only be external or sequential string of either
|
||||
// encoding at this point.
|
||||
GotoIf(to_direct.is_external(), &external_string);
|
||||
|
||||
var_result = AllocAndCopyStringCharacters(direct_string, instance_type,
|
||||
offset, substr_length);
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Handle external string.
|
||||
BIND(&external_string);
|
||||
{
|
||||
TNode<RawPtrT> const fake_sequential_string =
|
||||
to_direct.PointerToString(&runtime);
|
||||
|
||||
var_result = AllocAndCopyStringCharacters(
|
||||
fake_sequential_string, instance_type, offset, substr_length);
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&empty);
|
||||
{
|
||||
var_result = EmptyStringConstant();
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Substrings of length 1 are generated through CharCodeAt and FromCharCode.
|
||||
BIND(&single_char);
|
||||
{
|
||||
TNode<Int32T> char_code = StringCharCodeAt(string, from);
|
||||
var_result = StringFromSingleCharCode(char_code);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&original_string_or_invalid_length);
|
||||
{
|
||||
CSA_ASSERT(this, IntPtrEqual(substr_length, string_length));
|
||||
|
||||
// Equal length - check if {from, to} == {0, str.length}.
|
||||
GotoIf(UintPtrGreaterThan(from, IntPtrConstant(0)), &runtime);
|
||||
|
||||
// Return the original string (substr_length == string_length).
|
||||
|
||||
Counters* counters = isolate()->counters();
|
||||
IncrementCounter(counters->sub_string_native(), 1);
|
||||
|
||||
var_result = string;
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
// Fall back to a runtime call.
|
||||
BIND(&runtime);
|
||||
{
|
||||
var_result =
|
||||
CAST(CallRuntime(Runtime::kStringSubstring, NoContextConstant(), string,
|
||||
SmiTag(from), SmiTag(to)));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
ToDirectStringAssembler::ToDirectStringAssembler(
|
||||
compiler::CodeAssemblerState* state, TNode<String> string, Flags flags)
|
||||
: CodeStubAssembler(state),
|
||||
|
@ -2210,19 +2210,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
nullptr, flags, mode);
|
||||
}
|
||||
|
||||
// Copies |character_count| elements from |from_string| to |to_string|
|
||||
// starting at the |from_index|'th character. |from_string| and |to_string|
|
||||
// can either be one-byte strings or two-byte strings, although if
|
||||
// |from_string| is two-byte, then |to_string| must be two-byte.
|
||||
// |from_index|, |to_index| and |character_count| must be intptr_ts s.t. 0 <=
|
||||
// |from_index| <= |from_index| + |character_count| <= from_string.length and
|
||||
// 0 <= |to_index| <= |to_index| + |character_count| <= to_string.length.
|
||||
void CopyStringCharacters(Node* from_string, Node* to_string,
|
||||
TNode<IntPtrT> from_index, TNode<IntPtrT> to_index,
|
||||
TNode<IntPtrT> character_count,
|
||||
String::Encoding from_encoding,
|
||||
String::Encoding to_encoding);
|
||||
|
||||
// Loads an element from |array| of |from_kind| elements by given |offset|
|
||||
// (NOTE: not index!), does a hole check if |if_hole| is provided and
|
||||
// converts the value so that it becomes ready for storing to array of
|
||||
@ -2592,11 +2579,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
// Return the single character string with only {code}.
|
||||
TNode<String> StringFromSingleCharCode(TNode<Int32T> code);
|
||||
|
||||
// Return a new string object which holds a substring containing the range
|
||||
// [from,to[ of string.
|
||||
TNode<String> SubString(TNode<String> string, TNode<IntPtrT> from,
|
||||
TNode<IntPtrT> to);
|
||||
|
||||
// Type conversion helpers.
|
||||
enum class BigIntHandling { kConvertToNumber, kThrow };
|
||||
// Convert a String to a Number.
|
||||
@ -3739,10 +3721,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
void GenerateEqual_Same(SloppyTNode<Object> value, Label* if_equal,
|
||||
Label* if_notequal,
|
||||
Variable* var_type_feedback = nullptr);
|
||||
TNode<String> AllocAndCopyStringCharacters(Node* from,
|
||||
Node* from_instance_type,
|
||||
TNode<IntPtrT> from_index,
|
||||
TNode<IntPtrT> character_count);
|
||||
|
||||
static const int kElementLoopUnrollThreshold = 8;
|
||||
|
||||
|
@ -1865,7 +1865,7 @@ TEST(OneToTwoByteStringCopy) {
|
||||
|
||||
const int kNumParams = 2;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
StringBuiltinsAssembler m(asm_tester.state());
|
||||
|
||||
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), m.IntPtrConstant(0),
|
||||
m.IntPtrConstant(0), m.IntPtrConstant(5),
|
||||
@ -1897,7 +1897,7 @@ TEST(OneToOneByteStringCopy) {
|
||||
|
||||
const int kNumParams = 2;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
StringBuiltinsAssembler m(asm_tester.state());
|
||||
|
||||
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), m.IntPtrConstant(0),
|
||||
m.IntPtrConstant(0), m.IntPtrConstant(5),
|
||||
@ -1929,7 +1929,7 @@ TEST(OneToOneByteStringCopyNonZeroStart) {
|
||||
|
||||
const int kNumParams = 2;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
StringBuiltinsAssembler m(asm_tester.state());
|
||||
|
||||
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), m.IntPtrConstant(0),
|
||||
m.IntPtrConstant(3), m.IntPtrConstant(2),
|
||||
@ -1958,7 +1958,7 @@ TEST(TwoToTwoByteStringCopy) {
|
||||
|
||||
const int kNumParams = 2;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
StringBuiltinsAssembler m(asm_tester.state());
|
||||
|
||||
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), m.IntPtrConstant(0),
|
||||
m.IntPtrConstant(0), m.IntPtrConstant(5),
|
||||
|
Loading…
Reference in New Issue
Block a user