Commit 6246a1f9 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[csa] Add some types to some string/regexp-related functions.

E.g. SubString and StringAdd.

Bug: v8:7310
Change-Id: I352044f88fe79c5b576c5423d6feae3bcb7d725a
Reviewed-on: https://chromium-review.googlesource.com/934284Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51504}
parent 0b9b48b5
...@@ -136,10 +136,9 @@ void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp, ...@@ -136,10 +136,9 @@ void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp,
Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
Node* const context, Node* const regexp, Node* const match_info, Node* const context, Node* const regexp, Node* const match_info,
Node* const string) { TNode<String> const string) {
CSA_ASSERT(this, IsFixedArrayMap(LoadMap(match_info))); CSA_ASSERT(this, IsFixedArrayMap(LoadMap(match_info)));
CSA_ASSERT(this, IsJSRegExp(regexp)); CSA_ASSERT(this, IsJSRegExp(regexp));
CSA_ASSERT(this, IsString(string));
Label named_captures(this), out(this); Label named_captures(this), out(this);
...@@ -153,7 +152,7 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( ...@@ -153,7 +152,7 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// Calculate the substring of the first match before creating the result array // Calculate the substring of the first match before creating the result array
// to avoid an unnecessary write barrier storing the first result. // to avoid an unnecessary write barrier storing the first result.
Node* const first = SubString(string, start, end); TNode<String> const first = SubString(string, start, end);
Node* const result = Node* const result =
AllocateRegExpResult(context, num_results, start, string); AllocateRegExpResult(context, num_results, start, string);
...@@ -189,7 +188,7 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo( ...@@ -189,7 +188,7 @@ Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1)); Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1));
Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1); Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1);
Node* const capture = SubString(string, start, end); TNode<String> const capture = SubString(string, start, end);
StoreFixedArrayElement(result_elements, to_cursor, capture); StoreFixedArrayElement(result_elements, to_cursor, capture);
Goto(&next_iter); Goto(&next_iter);
...@@ -760,10 +759,9 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( ...@@ -760,10 +759,9 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
// ES#sec-regexp.prototype.exec // ES#sec-regexp.prototype.exec
// RegExp.prototype.exec ( string ) // RegExp.prototype.exec ( string )
Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(Node* const context, Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(
Node* const regexp, Node* const context, Node* const regexp, TNode<String> const string,
Node* const string, const bool is_fastpath) {
const bool is_fastpath) {
VARIABLE(var_result, MachineRepresentation::kTagged); VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_didnotmatch(this), out(this); Label if_didnotmatch(this), out(this);
...@@ -938,7 +936,7 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context, ...@@ -938,7 +936,7 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context,
// Slow path stub for RegExpPrototypeExec to decrease code size. // Slow path stub for RegExpPrototypeExec to decrease code size.
TF_BUILTIN(RegExpPrototypeExecSlow, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpPrototypeExecSlow, RegExpBuiltinsAssembler) {
Node* const regexp = Parameter(Descriptor::kReceiver); Node* const regexp = Parameter(Descriptor::kReceiver);
Node* const string = Parameter(Descriptor::kString); TNode<String> const string = CAST(Parameter(Descriptor::kString));
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Return(RegExpPrototypeExecBody(context, regexp, string, false)); Return(RegExpPrototypeExecBody(context, regexp, string, false));
...@@ -1024,7 +1022,7 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { ...@@ -1024,7 +1022,7 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
Label if_isfastpath(this), if_isslowpath(this); Label if_isfastpath(this), if_isslowpath(this);
Branch(IsFastRegExpNoPrototype(context, receiver), &if_isfastpath, Branch(IsFastRegExpNoPrototype(context, receiver), &if_isfastpath,
...@@ -1687,7 +1685,7 @@ TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { ...@@ -1687,7 +1685,7 @@ TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
...@@ -1777,14 +1775,12 @@ Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string, ...@@ -1777,14 +1775,12 @@ Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string,
void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
Node* const regexp, Node* const regexp,
Node* const string, TNode<String> string,
const bool is_fastpath) { const bool is_fastpath) {
CSA_ASSERT(this, IsString(string));
if (is_fastpath) CSA_ASSERT(this, IsFastRegExp(context, regexp)); if (is_fastpath) CSA_ASSERT(this, IsFastRegExp(context, regexp));
Node* const int_zero = IntPtrConstant(0); Node* const int_zero = IntPtrConstant(0);
Node* const smi_zero = SmiConstant(0); Node* const smi_zero = SmiConstant(0);
Node* const is_global = Node* const is_global =
FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath); FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath);
...@@ -1834,9 +1830,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, ...@@ -1834,9 +1830,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
Node* const match_to = LoadFixedArrayElement( Node* const match_to = LoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
Node* match = SubString(string, match_from, match_to); var_match.Bind(SubString(string, match_from, match_to));
var_match.Bind(match);
Goto(&if_didmatch); Goto(&if_didmatch);
} else { } else {
DCHECK(!is_fastpath); DCHECK(!is_fastpath);
...@@ -1940,7 +1934,7 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { ...@@ -1940,7 +1934,7 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
...@@ -1959,7 +1953,7 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { ...@@ -1959,7 +1953,7 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
// 2) pattern is a string // 2) pattern is a string
TF_BUILTIN(RegExpMatchFast, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpMatchFast, RegExpBuiltinsAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver); Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const string = Parameter(Descriptor::kPattern); TNode<String> const string = CAST(Parameter(Descriptor::kPattern));
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
RegExpPrototypeMatchBody(context, receiver, string, true); RegExpPrototypeMatchBody(context, receiver, string, true);
...@@ -2081,7 +2075,7 @@ TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) { ...@@ -2081,7 +2075,7 @@ TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
...@@ -2110,12 +2104,11 @@ TF_BUILTIN(RegExpSearchFast, RegExpBuiltinsAssembler) { ...@@ -2110,12 +2104,11 @@ TF_BUILTIN(RegExpSearchFast, RegExpBuiltinsAssembler) {
// JSRegExp, {string} is a String, and {limit} is a Smi. // JSRegExp, {string} is a String, and {limit} is a Smi.
void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
Node* const regexp, Node* const regexp,
Node* const string, TNode<String> string,
Node* const limit) { Node* const limit) {
CSA_ASSERT(this, IsFastRegExp(context, regexp)); CSA_ASSERT(this, IsFastRegExp(context, regexp));
CSA_ASSERT(this, Word32BinaryNot(FastFlagGetter(regexp, JSRegExp::kSticky))); CSA_ASSERT(this, Word32BinaryNot(FastFlagGetter(regexp, JSRegExp::kSticky)));
CSA_ASSERT(this, TaggedIsSmi(limit)); CSA_ASSERT(this, TaggedIsSmi(limit));
CSA_ASSERT(this, IsString(string));
TNode<Smi> const smi_zero = SmiConstant(0); TNode<Smi> const smi_zero = SmiConstant(0);
TNode<IntPtrT> const int_zero = IntPtrConstant(0); TNode<IntPtrT> const int_zero = IntPtrConstant(0);
...@@ -2255,10 +2248,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, ...@@ -2255,10 +2248,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
{ {
Node* const from = last_matched_until; Node* const from = last_matched_until;
Node* const to = match_from; Node* const to = match_from;
array.Push(SubString(string, from, to));
TNode<String> const substr = CAST(SubString(string, from, to));
array.Push(substr);
GotoIf(WordEqual(array.length(), int_limit), &out); GotoIf(WordEqual(array.length(), int_limit), &out);
} }
...@@ -2295,15 +2285,13 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, ...@@ -2295,15 +2285,13 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&select_capture); BIND(&select_capture);
{ {
Node* const substr = SubString(string, from, to); var_value.Bind(SubString(string, from, to));
var_value.Bind(substr);
Goto(&store_value); Goto(&store_value);
} }
BIND(&select_undefined); BIND(&select_undefined);
{ {
Node* const undefined = UndefinedConstant(); var_value.Bind(UndefinedConstant());
var_value.Bind(undefined);
Goto(&store_value); Goto(&store_value);
} }
...@@ -2332,10 +2320,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, ...@@ -2332,10 +2320,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
{ {
Node* const from = var_last_matched_until.value(); Node* const from = var_last_matched_until.value();
Node* const to = string_length; Node* const to = string_length;
array.Push(SubString(string, from, to));
TNode<String> const substr = CAST(SubString(string, from, to));
array.Push(substr);
Goto(&out); Goto(&out);
} }
...@@ -2358,12 +2343,11 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, ...@@ -2358,12 +2343,11 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
// Helper that skips a few initial checks. // Helper that skips a few initial checks.
TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) {
Node* const regexp = Parameter(Descriptor::kRegExp); Node* const regexp = Parameter(Descriptor::kRegExp);
Node* const string = Parameter(Descriptor::kString); TNode<String> const string = CAST(Parameter(Descriptor::kString));
Node* const maybe_limit = Parameter(Descriptor::kLimit); Node* const maybe_limit = Parameter(Descriptor::kLimit);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
CSA_ASSERT(this, IsFastRegExp(context, regexp)); CSA_ASSERT(this, IsFastRegExp(context, regexp));
CSA_ASSERT(this, IsString(string));
// TODO(jgruber): Even if map checks send us to the fast path, we still need // TODO(jgruber): Even if map checks send us to the fast path, we still need
// to verify the constructor property and jump to the slow path if it has // to verify the constructor property and jump to the slow path if it has
...@@ -2433,7 +2417,7 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { ...@@ -2433,7 +2417,7 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
Label stub(this), runtime(this, Label::kDeferred); Label stub(this), runtime(this, Label::kDeferred);
BranchIfFastRegExp(context, receiver, &stub, &runtime); BranchIfFastRegExp(context, receiver, &stub, &runtime);
...@@ -2579,7 +2563,8 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( ...@@ -2579,7 +2563,8 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
CallJS(call_callable, context, replace_callable, undefined, elem, CallJS(call_callable, context, replace_callable, undefined, elem,
match_start, string); match_start, string);
Node* const replacement_str = ToString_Inline(context, replacement_obj); TNode<String> const replacement_str =
ToString_Inline(context, replacement_obj);
StoreFixedArrayElement(res_elems, var_i.value(), replacement_str); StoreFixedArrayElement(res_elems, var_i.value(), replacement_str);
TNode<Smi> const elem_length = LoadStringLengthAsSmi(elem); TNode<Smi> const elem_length = LoadStringLengthAsSmi(elem);
...@@ -2629,7 +2614,7 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( ...@@ -2629,7 +2614,7 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
// Overwrite the i'th element in the results with the string // Overwrite the i'th element in the results with the string
// we got back from the callback function. // we got back from the callback function.
Node* const replacement_str = TNode<String> const replacement_str =
ToString_Inline(context, replacement_obj); ToString_Inline(context, replacement_obj);
StoreFixedArrayElement(res_elems, index, replacement_str); StoreFixedArrayElement(res_elems, index, replacement_str);
...@@ -2655,20 +2640,19 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( ...@@ -2655,20 +2640,19 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
} }
Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath( Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
Node* context, Node* regexp, Node* string, Node* replace_string) { Node* context, Node* regexp, TNode<String> string,
TNode<String> replace_string) {
// The fast path is reached only if {receiver} is an unmodified // The fast path is reached only if {receiver} is an unmodified
// JSRegExp instance, {replace_value} is non-callable, and // JSRegExp instance, {replace_value} is non-callable, and
// ToString({replace_value}) does not contain '$', i.e. we're doing a simple // ToString({replace_value}) does not contain '$', i.e. we're doing a simple
// string replacement. // string replacement.
CSA_ASSERT(this, IsFastRegExp(context, regexp));
Node* const smi_zero = SmiConstant(0); Node* const smi_zero = SmiConstant(0);
const bool kIsFastPath = true; const bool kIsFastPath = true;
CSA_ASSERT(this, IsFastRegExp(context, regexp)); TVARIABLE(String, var_result, EmptyStringConstant());
CSA_ASSERT(this, IsString(replace_string));
CSA_ASSERT(this, IsString(string));
VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant());
VARIABLE(var_match_indices, MachineRepresentation::kTagged); VARIABLE(var_match_indices, MachineRepresentation::kTagged);
VARIABLE(var_last_match_end, MachineRepresentation::kTagged, smi_zero); VARIABLE(var_last_match_end, MachineRepresentation::kTagged, smi_zero);
VARIABLE(var_is_unicode, MachineRepresentation::kWord32, Int32Constant(0)); VARIABLE(var_is_unicode, MachineRepresentation::kWord32, Int32Constant(0));
...@@ -2705,22 +2689,19 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath( ...@@ -2705,22 +2689,19 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
{ {
// TODO(jgruber): We could skip many of the checks that using SubString // TODO(jgruber): We could skip many of the checks that using SubString
// here entails. // here entails.
Node* const first_part = TNode<String> const first_part =
SubString(string, var_last_match_end.value(), match_start); SubString(string, var_last_match_end.value(), match_start);
var_result = StringAdd(context, var_result.value(), first_part);
Node* const result = StringAdd(context, var_result.value(), first_part);
var_result.Bind(result);
Goto(&loop_end); Goto(&loop_end);
} }
BIND(&if_replaceisnotempty); BIND(&if_replaceisnotempty);
{ {
Node* const first_part = TNode<String> const first_part =
SubString(string, var_last_match_end.value(), match_start); SubString(string, var_last_match_end.value(), match_start);
TNode<String> result =
Node* result = StringAdd(context, var_result.value(), first_part); StringAdd(context, var_result.value(), first_part);
result = StringAdd(context, result, replace_string); var_result = StringAdd(context, result, replace_string);
var_result.Bind(result);
Goto(&loop_end); Goto(&loop_end);
} }
...@@ -2744,10 +2725,9 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath( ...@@ -2744,10 +2725,9 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
BIND(&if_nofurthermatches); BIND(&if_nofurthermatches);
{ {
TNode<Smi> const string_length = LoadStringLengthAsSmi(string); TNode<Smi> const string_length = LoadStringLengthAsSmi(string);
Node* const last_part = TNode<String> const last_part =
SubString(string, var_last_match_end.value(), string_length); SubString(string, var_last_match_end.value(), string_length);
Node* const result = StringAdd(context, var_result.value(), last_part); var_result = StringAdd(context, var_result.value(), last_part);
var_result.Bind(result);
Goto(&out); Goto(&out);
} }
...@@ -2758,12 +2738,11 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath( ...@@ -2758,12 +2738,11 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
// Helper that skips a few initial checks. // Helper that skips a few initial checks.
TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
Node* const regexp = Parameter(Descriptor::kRegExp); Node* const regexp = Parameter(Descriptor::kRegExp);
Node* const string = Parameter(Descriptor::kString); TNode<String> const string = CAST(Parameter(Descriptor::kString));
Node* const replace_value = Parameter(Descriptor::kReplaceValue); Node* const replace_value = Parameter(Descriptor::kReplaceValue);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
CSA_ASSERT(this, IsFastRegExp(context, regexp)); CSA_ASSERT(this, IsFastRegExp(context, regexp));
CSA_ASSERT(this, IsString(string));
Label checkreplacestring(this), if_iscallable(this), Label checkreplacestring(this), if_iscallable(this),
runtime(this, Label::kDeferred); runtime(this, Label::kDeferred);
...@@ -2776,7 +2755,8 @@ TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) { ...@@ -2776,7 +2755,8 @@ TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
// 3. Does ToString({replace_value}) contain '$'? // 3. Does ToString({replace_value}) contain '$'?
BIND(&checkreplacestring); BIND(&checkreplacestring);
{ {
Node* const replace_string = ToString_Inline(context, replace_value); TNode<String> const replace_string =
ToString_Inline(context, replace_value);
// ToString(replaceValue) could potentially change the shape of the RegExp // ToString(replaceValue) could potentially change the shape of the RegExp
// object. Recheck that we are still on the fast path and bail to runtime // object. Recheck that we are still on the fast path and bail to runtime
...@@ -2862,7 +2842,7 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { ...@@ -2862,7 +2842,7 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString_Inline(context, maybe_string); TNode<String> const string = ToString_Inline(context, maybe_string);
// Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
Label stub(this), runtime(this, Label::kDeferred); Label stub(this), runtime(this, Label::kDeferred);
...@@ -2880,27 +2860,19 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { ...@@ -2880,27 +2860,19 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
// Simple string matching functionality for internal use which does not modify // Simple string matching functionality for internal use which does not modify
// the last match info. // the last match info.
TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
Node* const regexp = Parameter(Descriptor::kRegExp); TNode<JSRegExp> const regexp = CAST(Parameter(Descriptor::kRegExp));
Node* const string = Parameter(Descriptor::kString); TNode<String> const string = CAST(Parameter(Descriptor::kString));
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const smi_zero = SmiConstant(0); Node* const smi_zero = SmiConstant(0);
CSA_ASSERT(this, IsJSRegExp(regexp));
CSA_ASSERT(this, IsString(string));
Node* const native_context = LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const internal_match_info = LoadContextElement( Node* const internal_match_info = LoadContextElement(
native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX);
Node* const match_indices = RegExpExecInternal(context, regexp, string, Node* const match_indices = RegExpExecInternal(context, regexp, string,
smi_zero, internal_match_info); smi_zero, internal_match_info);
Node* const null = NullConstant(); Node* const null = NullConstant();
Label if_matched(this), if_didnotmatch(this); Label if_matched(this);
Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); GotoIfNot(WordEqual(match_indices, null), &if_matched);
BIND(&if_didnotmatch);
Return(null); Return(null);
BIND(&if_matched); BIND(&if_matched);
......
...@@ -50,7 +50,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -50,7 +50,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* ConstructNewResultFromMatchInfo(Node* const context, Node* const regexp, Node* ConstructNewResultFromMatchInfo(Node* const context, Node* const regexp,
Node* const match_info, Node* const match_info,
Node* const string); TNode<String> const string);
Node* RegExpPrototypeExecBodyWithoutResult(Node* const context, Node* RegExpPrototypeExecBodyWithoutResult(Node* const context,
Node* const regexp, Node* const regexp,
...@@ -58,7 +58,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -58,7 +58,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Label* if_didnotmatch, Label* if_didnotmatch,
const bool is_fastpath); const bool is_fastpath);
Node* RegExpPrototypeExecBody(Node* const context, Node* const regexp, Node* RegExpPrototypeExecBody(Node* const context, Node* const regexp,
Node* const string, const bool is_fastpath); TNode<String> string, const bool is_fastpath);
Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver, Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
MessageTemplate::Template msg_template, MessageTemplate::Template msg_template,
...@@ -100,7 +100,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -100,7 +100,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* const is_unicode, bool is_fastpath); Node* const is_unicode, bool is_fastpath);
void RegExpPrototypeMatchBody(Node* const context, Node* const regexp, void RegExpPrototypeMatchBody(Node* const context, Node* const regexp,
Node* const string, const bool is_fastpath); TNode<String> const string,
const bool is_fastpath);
void RegExpPrototypeSearchBodyFast(Node* const context, Node* const regexp, void RegExpPrototypeSearchBodyFast(Node* const context, Node* const regexp,
Node* const string); Node* const string);
...@@ -108,12 +109,13 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -108,12 +109,13 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* const string); Node* const string);
void RegExpPrototypeSplitBody(Node* const context, Node* const regexp, void RegExpPrototypeSplitBody(Node* const context, Node* const regexp,
Node* const string, Node* const limit); TNode<String> const string, Node* const limit);
Node* ReplaceGlobalCallableFastPath(Node* context, Node* regexp, Node* string, Node* ReplaceGlobalCallableFastPath(Node* context, Node* regexp, Node* string,
Node* replace_callable); Node* replace_callable);
Node* ReplaceSimpleStringFastPath(Node* context, Node* regexp, Node* string, Node* ReplaceSimpleStringFastPath(Node* context, Node* regexp,
Node* replace_string); TNode<String> string,
TNode<String> replace_string);
}; };
} // namespace internal } // namespace internal
......
...@@ -1666,8 +1666,8 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) { ...@@ -1666,8 +1666,8 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
RequireObjectCoercible(context, receiver, "String.prototype.slice"); RequireObjectCoercible(context, receiver, "String.prototype.slice");
// 2. Let S be ? ToString(O). // 2. Let S be ? ToString(O).
Node* const subject_string = TNode<String> const subject_string =
CallBuiltin(Builtins::kToString, context, receiver); CAST(CallBuiltin(Builtins::kToString, context, receiver));
// 3. Let len be the number of elements in S. // 3. Let len be the number of elements in S.
TNode<Smi> const length = LoadStringLengthAsSmi(subject_string); TNode<Smi> const length = LoadStringLengthAsSmi(subject_string);
...@@ -1688,7 +1688,7 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) { ...@@ -1688,7 +1688,7 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
{ {
GotoIf(SmiLessThanOrEqual(var_end.value(), var_start.value()), GotoIf(SmiLessThanOrEqual(var_end.value(), var_start.value()),
&return_emptystring); &return_emptystring);
Node* const result = TNode<String> const result =
SubString(subject_string, var_start.value(), var_end.value()); SubString(subject_string, var_start.value(), var_end.value());
args.PopAndReturn(result); args.PopAndReturn(result);
} }
...@@ -1819,7 +1819,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) { ...@@ -1819,7 +1819,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
TNode<Smi> const zero = SmiConstant(0); TNode<Smi> const zero = SmiConstant(0);
// Check that {receiver} is coercible to Object and convert it to a String. // Check that {receiver} is coercible to Object and convert it to a String.
Node* const string = TNode<String> const string =
ToThisString(context, receiver, "String.prototype.substr"); ToThisString(context, receiver, "String.prototype.substr");
TNode<Smi> const string_length = LoadStringLengthAsSmi(string); TNode<Smi> const string_length = LoadStringLengthAsSmi(string);
...@@ -1888,8 +1888,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) { ...@@ -1888,8 +1888,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
BIND(&out); BIND(&out);
{ {
TNode<Smi> const end = SmiAdd(var_start.value(), var_result_length.value()); TNode<Smi> const end = SmiAdd(var_start.value(), var_result_length.value());
Node* const result = SubString(string, var_start.value(), end); args.PopAndReturn(SubString(string, var_start.value(), end));
args.PopAndReturn(result);
} }
} }
...@@ -1943,7 +1942,7 @@ TNode<Smi> StringBuiltinsAssembler::ToSmiBetweenZeroAnd( ...@@ -1943,7 +1942,7 @@ TNode<Smi> StringBuiltinsAssembler::ToSmiBetweenZeroAnd(
} }
TF_BUILTIN(SubString, CodeStubAssembler) { TF_BUILTIN(SubString, CodeStubAssembler) {
Node* string = Parameter(Descriptor::kString); TNode<String> string = CAST(Parameter(Descriptor::kString));
Node* from = Parameter(Descriptor::kFrom); Node* from = Parameter(Descriptor::kFrom);
Node* to = Parameter(Descriptor::kTo); Node* to = Parameter(Descriptor::kTo);
...@@ -1970,7 +1969,7 @@ TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) { ...@@ -1970,7 +1969,7 @@ TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) {
VARIABLE(var_end, MachineRepresentation::kTagged); VARIABLE(var_end, MachineRepresentation::kTagged);
// Check that {receiver} is coercible to Object and convert it to a String. // Check that {receiver} is coercible to Object and convert it to a String.
Node* const string = TNode<String> const string =
ToThisString(context, receiver, "String.prototype.substring"); ToThisString(context, receiver, "String.prototype.substring");
Node* const length = LoadStringLengthAsSmi(string); Node* const length = LoadStringLengthAsSmi(string);
...@@ -1999,10 +1998,7 @@ TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) { ...@@ -1999,10 +1998,7 @@ TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) {
} }
BIND(&out); BIND(&out);
{ { args.PopAndReturn(SubString(string, var_start.value(), var_end.value())); }
Node* result = SubString(string, var_start.value(), var_end.value());
args.PopAndReturn(result);
}
} }
// ES6 #sec-string.prototype.trim // ES6 #sec-string.prototype.trim
...@@ -2030,7 +2026,7 @@ void StringTrimAssembler::Generate(String::TrimMode mode, ...@@ -2030,7 +2026,7 @@ void StringTrimAssembler::Generate(String::TrimMode mode,
Node* const receiver = arguments.GetReceiver(); Node* const receiver = arguments.GetReceiver();
// Check that {receiver} is coercible to Object and convert it to a String. // Check that {receiver} is coercible to Object and convert it to a String.
Node* const string = ToThisString(context, receiver, method_name); TNode<String> const string = ToThisString(context, receiver, method_name);
TNode<IntPtrT> const string_length = LoadStringLengthAsWord(string); TNode<IntPtrT> const string_length = LoadStringLengthAsWord(string);
ToDirectStringAssembler to_direct(state(), string); ToDirectStringAssembler to_direct(state(), string);
......
...@@ -2430,11 +2430,11 @@ TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint, ...@@ -2430,11 +2430,11 @@ TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint,
MachineType::UintPtr())); MachineType::UintPtr()));
} }
Node* CodeStubAssembler::AllocateSeqOneByteString(int length, TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
AllocationFlags flags) { int length, AllocationFlags flags) {
Comment("AllocateSeqOneByteString"); Comment("AllocateSeqOneByteString");
if (length == 0) { if (length == 0) {
return LoadRoot(Heap::kempty_stringRootIndex); return CAST(LoadRoot(Heap::kempty_stringRootIndex));
} }
Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); Node* result = Allocate(SeqOneByteString::SizeFor(length), flags);
DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex));
...@@ -2445,7 +2445,7 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length, ...@@ -2445,7 +2445,7 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length,
StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot,
IntPtrConstant(String::kEmptyHashField), IntPtrConstant(String::kEmptyHashField),
MachineType::PointerRepresentation()); MachineType::PointerRepresentation());
return result; return CAST(result);
} }
Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) { Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) {
...@@ -2462,9 +2462,8 @@ Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) { ...@@ -2462,9 +2462,8 @@ Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) {
return var_result.value(); return var_result.value();
} }
Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
TNode<Smi> length, Node* context, TNode<Smi> length, AllocationFlags flags) {
AllocationFlags flags) {
Comment("AllocateSeqOneByteString"); Comment("AllocateSeqOneByteString");
CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context)); CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context));
VARIABLE(var_result, MachineRepresentation::kTagged); VARIABLE(var_result, MachineRepresentation::kTagged);
...@@ -2512,14 +2511,14 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, ...@@ -2512,14 +2511,14 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context,
} }
BIND(&if_join); BIND(&if_join);
return var_result.value(); return CAST(var_result.value());
} }
Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
AllocationFlags flags) { int length, AllocationFlags flags) {
Comment("AllocateSeqTwoByteString"); Comment("AllocateSeqTwoByteString");
if (length == 0) { if (length == 0) {
return LoadRoot(Heap::kempty_stringRootIndex); return CAST(LoadRoot(Heap::kempty_stringRootIndex));
} }
Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags);
DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex));
...@@ -2530,12 +2529,11 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, ...@@ -2530,12 +2529,11 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(int length,
StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot,
IntPtrConstant(String::kEmptyHashField), IntPtrConstant(String::kEmptyHashField),
MachineType::PointerRepresentation()); MachineType::PointerRepresentation());
return result; return CAST(result);
} }
Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
TNode<Smi> length, Node* context, TNode<Smi> length, AllocationFlags flags) {
AllocationFlags flags) {
CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context)); CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context));
Comment("AllocateSeqTwoByteString"); Comment("AllocateSeqTwoByteString");
VARIABLE(var_result, MachineRepresentation::kTagged); VARIABLE(var_result, MachineRepresentation::kTagged);
...@@ -2583,12 +2581,14 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, ...@@ -2583,12 +2581,14 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context,
} }
BIND(&if_join); BIND(&if_join);
return var_result.value(); return CAST(var_result.value());
} }
Node* CodeStubAssembler::AllocateSlicedString( TNode<String> CodeStubAssembler::AllocateSlicedString(
Heap::RootListIndex map_root_index, TNode<Smi> length, Node* parent, Heap::RootListIndex map_root_index, TNode<Smi> length, Node* parent,
Node* offset) { Node* offset) {
DCHECK(map_root_index == Heap::kSlicedOneByteStringMapRootIndex ||
map_root_index == Heap::kSlicedStringMapRootIndex);
CSA_ASSERT(this, IsString(parent)); CSA_ASSERT(this, IsString(parent));
CSA_ASSERT(this, TaggedIsSmi(offset)); CSA_ASSERT(this, TaggedIsSmi(offset));
Node* result = Allocate(SlicedString::kSize); Node* result = Allocate(SlicedString::kSize);
...@@ -2603,29 +2603,28 @@ Node* CodeStubAssembler::AllocateSlicedString( ...@@ -2603,29 +2603,28 @@ Node* CodeStubAssembler::AllocateSlicedString(
MachineRepresentation::kTagged); MachineRepresentation::kTagged);
StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset,
MachineRepresentation::kTagged); MachineRepresentation::kTagged);
return result; return CAST(result);
} }
Node* CodeStubAssembler::AllocateSlicedOneByteString(TNode<Smi> length, TNode<String> CodeStubAssembler::AllocateSlicedOneByteString(TNode<Smi> length,
Node* parent, Node* parent,
Node* offset) { Node* offset) {
return AllocateSlicedString(Heap::kSlicedOneByteStringMapRootIndex, length, return AllocateSlicedString(Heap::kSlicedOneByteStringMapRootIndex, length,
parent, offset); parent, offset);
} }
Node* CodeStubAssembler::AllocateSlicedTwoByteString(TNode<Smi> length, TNode<String> CodeStubAssembler::AllocateSlicedTwoByteString(TNode<Smi> length,
Node* parent, Node* parent,
Node* offset) { Node* offset) {
return AllocateSlicedString(Heap::kSlicedStringMapRootIndex, length, parent, return AllocateSlicedString(Heap::kSlicedStringMapRootIndex, length, parent,
offset); offset);
} }
Node* CodeStubAssembler::AllocateConsString(Heap::RootListIndex map_root_index, TNode<String> CodeStubAssembler::AllocateConsString(
TNode<Smi> length, Node* first, Heap::RootListIndex map_root_index, TNode<Smi> length, TNode<String> first,
Node* second, TNode<String> second, AllocationFlags flags) {
AllocationFlags flags) { DCHECK(map_root_index == Heap::kConsOneByteStringMapRootIndex ||
CSA_ASSERT(this, IsString(first)); map_root_index == Heap::kConsStringMapRootIndex);
CSA_ASSERT(this, IsString(second));
Node* result = Allocate(ConsString::kSize, flags); Node* result = Allocate(ConsString::kSize, flags);
DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); DCHECK(Heap::RootIsImmortalImmovable(map_root_index));
StoreMapNoWriteBarrier(result, map_root_index); StoreMapNoWriteBarrier(result, map_root_index);
...@@ -2644,29 +2643,28 @@ Node* CodeStubAssembler::AllocateConsString(Heap::RootListIndex map_root_index, ...@@ -2644,29 +2643,28 @@ Node* CodeStubAssembler::AllocateConsString(Heap::RootListIndex map_root_index,
StoreObjectField(result, ConsString::kFirstOffset, first); StoreObjectField(result, ConsString::kFirstOffset, first);
StoreObjectField(result, ConsString::kSecondOffset, second); StoreObjectField(result, ConsString::kSecondOffset, second);
} }
return result; return CAST(result);
} }
Node* CodeStubAssembler::AllocateOneByteConsString(TNode<Smi> length, TNode<String> CodeStubAssembler::AllocateOneByteConsString(
Node* first, Node* second, TNode<Smi> length, TNode<String> first, TNode<String> second,
AllocationFlags flags) { AllocationFlags flags) {
return AllocateConsString(Heap::kConsOneByteStringMapRootIndex, length, first, return AllocateConsString(Heap::kConsOneByteStringMapRootIndex, length, first,
second, flags); second, flags);
} }
Node* CodeStubAssembler::AllocateTwoByteConsString(TNode<Smi> length, TNode<String> CodeStubAssembler::AllocateTwoByteConsString(
Node* first, Node* second, TNode<Smi> length, TNode<String> first, TNode<String> second,
AllocationFlags flags) { AllocationFlags flags) {
return AllocateConsString(Heap::kConsStringMapRootIndex, length, first, return AllocateConsString(Heap::kConsStringMapRootIndex, length, first,
second, flags); second, flags);
} }
Node* CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length, TNode<String> CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length,
Node* left, Node* right, TNode<String> left,
AllocationFlags flags) { TNode<String> right,
AllocationFlags flags) {
CSA_ASSERT(this, IsFixedArray(context)); CSA_ASSERT(this, IsFixedArray(context));
CSA_ASSERT(this, IsString(left));
CSA_ASSERT(this, IsString(right));
// Added string can be a cons string. // Added string can be a cons string.
Comment("Allocating ConsString"); Comment("Allocating ConsString");
Node* left_instance_type = LoadInstanceType(left); Node* left_instance_type = LoadInstanceType(left);
...@@ -2691,7 +2689,7 @@ Node* CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length, ...@@ -2691,7 +2689,7 @@ Node* CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length,
STATIC_ASSERT(kOneByteDataHintTag != 0); STATIC_ASSERT(kOneByteDataHintTag != 0);
Label one_byte_map(this); Label one_byte_map(this);
Label two_byte_map(this); Label two_byte_map(this);
VARIABLE(result, MachineRepresentation::kTagged); TVARIABLE(String, result);
Label done(this, &result); Label done(this, &result);
GotoIf(IsSetWord32(anded_instance_types, GotoIf(IsSetWord32(anded_instance_types,
kStringEncodingMask | kOneByteDataHintTag), kStringEncodingMask | kOneByteDataHintTag),
...@@ -2704,12 +2702,12 @@ Node* CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length, ...@@ -2704,12 +2702,12 @@ Node* CodeStubAssembler::NewConsString(Node* context, TNode<Smi> length,
BIND(&one_byte_map); BIND(&one_byte_map);
Comment("One-byte ConsString"); Comment("One-byte ConsString");
result.Bind(AllocateOneByteConsString(length, left, right, flags)); result = AllocateOneByteConsString(length, left, right, flags);
Goto(&done); Goto(&done);
BIND(&two_byte_map); BIND(&two_byte_map);
Comment("Two-byte ConsString"); Comment("Two-byte ConsString");
result.Bind(AllocateTwoByteConsString(length, left, right, flags)); result = AllocateTwoByteConsString(length, left, right, flags);
Goto(&done); Goto(&done);
BIND(&done); BIND(&done);
...@@ -4959,11 +4957,11 @@ TNode<String> CodeStubAssembler::StringFromCharCode(TNode<Int32T> code) { ...@@ -4959,11 +4957,11 @@ TNode<String> CodeStubAssembler::StringFromCharCode(TNode<Int32T> code) {
// given character range using CopyStringCharacters. // given character range using CopyStringCharacters.
// |from_string| must be a sequential string. // |from_string| must be a sequential string.
// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length.
Node* CodeStubAssembler::AllocAndCopyStringCharacters( TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters(
Node* from, Node* from_instance_type, TNode<IntPtrT> from_index, Node* from, Node* from_instance_type, TNode<IntPtrT> from_index,
TNode<Smi> character_count) { TNode<Smi> character_count) {
Label end(this), one_byte_sequential(this), two_byte_sequential(this); Label end(this), one_byte_sequential(this), two_byte_sequential(this);
Variable var_result(this, MachineRepresentation::kTagged); TVARIABLE(String, var_result);
Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential, Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential,
&two_byte_sequential); &two_byte_sequential);
...@@ -4971,26 +4969,24 @@ Node* CodeStubAssembler::AllocAndCopyStringCharacters( ...@@ -4971,26 +4969,24 @@ Node* CodeStubAssembler::AllocAndCopyStringCharacters(
// The subject string is a sequential one-byte string. // The subject string is a sequential one-byte string.
BIND(&one_byte_sequential); BIND(&one_byte_sequential);
{ {
Node* result = TNode<String> result =
AllocateSeqOneByteString(NoContextConstant(), character_count); AllocateSeqOneByteString(NoContextConstant(), character_count);
CopyStringCharacters(from, result, from_index, IntPtrConstant(0), CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
SmiUntag(character_count), String::ONE_BYTE_ENCODING, SmiUntag(character_count), String::ONE_BYTE_ENCODING,
String::ONE_BYTE_ENCODING); String::ONE_BYTE_ENCODING);
var_result.Bind(result); var_result = result;
Goto(&end); Goto(&end);
} }
// The subject string is a sequential two-byte string. // The subject string is a sequential two-byte string.
BIND(&two_byte_sequential); BIND(&two_byte_sequential);
{ {
Node* result = TNode<String> result =
AllocateSeqTwoByteString(NoContextConstant(), character_count); AllocateSeqTwoByteString(NoContextConstant(), character_count);
CopyStringCharacters(from, result, from_index, IntPtrConstant(0), CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
SmiUntag(character_count), String::TWO_BYTE_ENCODING, SmiUntag(character_count), String::TWO_BYTE_ENCODING,
String::TWO_BYTE_ENCODING); String::TWO_BYTE_ENCODING);
var_result.Bind(result); var_result = result;
Goto(&end); Goto(&end);
} }
...@@ -4998,15 +4994,13 @@ Node* CodeStubAssembler::AllocAndCopyStringCharacters( ...@@ -4998,15 +4994,13 @@ Node* CodeStubAssembler::AllocAndCopyStringCharacters(
return var_result.value(); return var_result.value();
} }
Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { TNode<String> CodeStubAssembler::SubString(TNode<String> string,
VARIABLE(var_result, MachineRepresentation::kTagged); SloppyTNode<Smi> from,
SloppyTNode<Smi> to) {
TVARIABLE(String, var_result);
ToDirectStringAssembler to_direct(state(), string); ToDirectStringAssembler to_direct(state(), string);
Label end(this), runtime(this); Label end(this), runtime(this);
// Make sure first argument is a string.
CSA_ASSERT(this, TaggedIsNotSmi(string));
CSA_ASSERT(this, IsString(string));
// Make sure that both from and to are non-negative smis. // Make sure that both from and to are non-negative smis.
CSA_ASSERT(this, TaggedIsPositiveSmi(from)); CSA_ASSERT(this, TaggedIsPositiveSmi(from));
CSA_ASSERT(this, TaggedIsPositiveSmi(to)); CSA_ASSERT(this, TaggedIsPositiveSmi(to));
...@@ -5056,15 +5050,15 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { ...@@ -5056,15 +5050,15 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) {
BIND(&one_byte_slice); BIND(&one_byte_slice);
{ {
var_result.Bind( var_result =
AllocateSlicedOneByteString(substr_length, direct_string, offset)); AllocateSlicedOneByteString(substr_length, direct_string, offset);
Goto(&end); Goto(&end);
} }
BIND(&two_byte_slice); BIND(&two_byte_slice);
{ {
var_result.Bind( var_result =
AllocateSlicedTwoByteString(substr_length, direct_string, offset)); AllocateSlicedTwoByteString(substr_length, direct_string, offset);
Goto(&end); Goto(&end);
} }
...@@ -5075,8 +5069,8 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { ...@@ -5075,8 +5069,8 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) {
// encoding at this point. // encoding at this point.
GotoIf(to_direct.is_external(), &external_string); GotoIf(to_direct.is_external(), &external_string);
var_result.Bind(AllocAndCopyStringCharacters( var_result = AllocAndCopyStringCharacters(direct_string, instance_type,
direct_string, instance_type, SmiUntag(offset), substr_length)); SmiUntag(offset), substr_length);
Counters* counters = isolate()->counters(); Counters* counters = isolate()->counters();
IncrementCounter(counters->sub_string_native(), 1); IncrementCounter(counters->sub_string_native(), 1);
...@@ -5089,9 +5083,8 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { ...@@ -5089,9 +5083,8 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) {
{ {
Node* const fake_sequential_string = to_direct.PointerToString(&runtime); Node* const fake_sequential_string = to_direct.PointerToString(&runtime);
var_result.Bind( var_result = AllocAndCopyStringCharacters(
AllocAndCopyStringCharacters(fake_sequential_string, instance_type, fake_sequential_string, instance_type, SmiUntag(offset), substr_length);
SmiUntag(offset), substr_length));
Counters* counters = isolate()->counters(); Counters* counters = isolate()->counters();
IncrementCounter(counters->sub_string_native(), 1); IncrementCounter(counters->sub_string_native(), 1);
...@@ -5103,7 +5096,7 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { ...@@ -5103,7 +5096,7 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) {
BIND(&single_char); BIND(&single_char);
{ {
TNode<Int32T> char_code = StringCharCodeAt(string, SmiUntag(from)); TNode<Int32T> char_code = StringCharCodeAt(string, SmiUntag(from));
var_result.Bind(StringFromCharCode(char_code)); var_result = StringFromCharCode(char_code);
Goto(&end); Goto(&end);
} }
...@@ -5119,20 +5112,19 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) { ...@@ -5119,20 +5112,19 @@ Node* CodeStubAssembler::SubString(Node* string, Node* from, Node* to) {
Counters* counters = isolate()->counters(); Counters* counters = isolate()->counters();
IncrementCounter(counters->sub_string_native(), 1); IncrementCounter(counters->sub_string_native(), 1);
var_result.Bind(string); var_result = string;
Goto(&end); Goto(&end);
} }
// Fall back to a runtime call. // Fall back to a runtime call.
BIND(&runtime); BIND(&runtime);
{ {
var_result.Bind(CallRuntime(Runtime::kSubString, NoContextConstant(), var_result = CAST(CallRuntime(Runtime::kSubString, NoContextConstant(),
string, from, to)); string, from, to));
Goto(&end); Goto(&end);
} }
BIND(&end); BIND(&end);
CSA_ASSERT(this, IsString(var_result.value()));
return var_result.value(); return var_result.value();
} }
...@@ -5354,22 +5346,23 @@ void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left, ...@@ -5354,22 +5346,23 @@ void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left,
// Fall through if neither string was an indirect string. // Fall through if neither string was an indirect string.
} }
Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
AllocationFlags flags) { TNode<String> right,
VARIABLE(result, MachineRepresentation::kTagged); AllocationFlags flags) {
TVARIABLE(String, result);
Label check_right(this), runtime(this, Label::kDeferred), cons(this), Label check_right(this), runtime(this, Label::kDeferred), cons(this),
done(this, &result), done_native(this, &result); done(this, &result), done_native(this, &result);
Counters* counters = isolate()->counters(); Counters* counters = isolate()->counters();
TNode<Smi> left_length = LoadStringLengthAsSmi(left); TNode<Smi> left_length = LoadStringLengthAsSmi(left);
GotoIf(SmiNotEqual(SmiConstant(0), left_length), &check_right); GotoIf(SmiNotEqual(SmiConstant(0), left_length), &check_right);
result.Bind(right); result = right;
Goto(&done_native); Goto(&done_native);
BIND(&check_right); BIND(&check_right);
TNode<Smi> right_length = LoadStringLengthAsSmi(right); TNode<Smi> right_length = LoadStringLengthAsSmi(right);
GotoIf(SmiNotEqual(SmiConstant(0), right_length), &cons); GotoIf(SmiNotEqual(SmiConstant(0), right_length), &cons);
result.Bind(left); result = left;
Goto(&done_native); Goto(&done_native);
BIND(&cons); BIND(&cons);
...@@ -5382,16 +5375,16 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, ...@@ -5382,16 +5375,16 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right,
GotoIf(SmiGreaterThan(new_length, SmiConstant(String::kMaxLength)), GotoIf(SmiGreaterThan(new_length, SmiConstant(String::kMaxLength)),
&runtime); &runtime);
VARIABLE(var_left, MachineRepresentation::kTagged, left); TVARIABLE(String, var_left, left);
VARIABLE(var_right, MachineRepresentation::kTagged, right); TVARIABLE(String, var_right, right);
Variable* input_vars[2] = {&var_left, &var_right}; Variable* input_vars[2] = {&var_left, &var_right};
Label non_cons(this, 2, input_vars); Label non_cons(this, 2, input_vars);
Label slow(this, Label::kDeferred); Label slow(this, Label::kDeferred);
GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)), GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)),
&non_cons); &non_cons);
result.Bind(NewConsString(context, new_length, var_left.value(), result = NewConsString(context, new_length, var_left.value(),
var_right.value(), flags)); var_right.value(), flags);
Goto(&done_native); Goto(&done_native);
BIND(&non_cons); BIND(&non_cons);
...@@ -5419,29 +5412,27 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, ...@@ -5419,29 +5412,27 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right,
Int32Constant(kTwoByteStringTag)), Int32Constant(kTwoByteStringTag)),
&two_byte); &two_byte);
// One-byte sequential string case // One-byte sequential string case
Node* new_string = AllocateSeqOneByteString(context, new_length); result = AllocateSeqOneByteString(context, new_length);
CopyStringCharacters(var_left.value(), new_string, IntPtrConstant(0), CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
IntPtrConstant(0), word_left_length, IntPtrConstant(0), word_left_length,
String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING); String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING);
CopyStringCharacters(var_right.value(), new_string, IntPtrConstant(0), CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0),
word_left_length, word_right_length, word_left_length, word_right_length,
String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING); String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING);
result.Bind(new_string);
Goto(&done_native); Goto(&done_native);
BIND(&two_byte); BIND(&two_byte);
{ {
// Two-byte sequential string case // Two-byte sequential string case
new_string = AllocateSeqTwoByteString(context, new_length); result = AllocateSeqTwoByteString(context, new_length);
CopyStringCharacters(var_left.value(), new_string, IntPtrConstant(0), CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
IntPtrConstant(0), word_left_length, IntPtrConstant(0), word_left_length,
String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING,
String::TWO_BYTE_ENCODING); String::TWO_BYTE_ENCODING);
CopyStringCharacters(var_right.value(), new_string, IntPtrConstant(0), CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0),
word_left_length, word_right_length, word_left_length, word_right_length,
String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING,
String::TWO_BYTE_ENCODING); String::TWO_BYTE_ENCODING);
result.Bind(new_string);
Goto(&done_native); Goto(&done_native);
} }
...@@ -5455,7 +5446,7 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, ...@@ -5455,7 +5446,7 @@ Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right,
} }
BIND(&runtime); BIND(&runtime);
{ {
result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right)); result = CAST(CallRuntime(Runtime::kStringAdd, context, left, right));
Goto(&done); Goto(&done);
} }
......
...@@ -765,38 +765,45 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -765,38 +765,45 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<WordT> LoadBigIntBitfield(TNode<BigInt> bigint); TNode<WordT> LoadBigIntBitfield(TNode<BigInt> bigint);
TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, int digit_index); TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, int digit_index);
// Allocate a SeqOneByteString with the given length. // Allocate a SeqOneByteString with the given length.
Node* AllocateSeqOneByteString(int length, AllocationFlags flags = kNone); TNode<String> AllocateSeqOneByteString(int length,
Node* AllocateSeqOneByteString(Node* context, TNode<Smi> length, AllocationFlags flags = kNone);
AllocationFlags flags = kNone); TNode<String> AllocateSeqOneByteString(Node* context, TNode<Smi> length,
AllocationFlags flags = kNone);
// Allocate a SeqTwoByteString with the given length. // Allocate a SeqTwoByteString with the given length.
Node* AllocateSeqTwoByteString(int length, AllocationFlags flags = kNone); TNode<String> AllocateSeqTwoByteString(int length,
Node* AllocateSeqTwoByteString(Node* context, TNode<Smi> length, AllocationFlags flags = kNone);
AllocationFlags flags = kNone); TNode<String> AllocateSeqTwoByteString(Node* context, TNode<Smi> length,
AllocationFlags flags = kNone);
// Allocate a SlicedOneByteString with the given length, parent and offset. // Allocate a SlicedOneByteString with the given length, parent and offset.
// |length| and |offset| are expected to be tagged. // |length| and |offset| are expected to be tagged.
Node* AllocateSlicedOneByteString(TNode<Smi> length, Node* parent, TNode<String> AllocateSlicedOneByteString(TNode<Smi> length, Node* parent,
Node* offset); Node* offset);
// Allocate a SlicedTwoByteString with the given length, parent and offset. // Allocate a SlicedTwoByteString with the given length, parent and offset.
// |length| and |offset| are expected to be tagged. // |length| and |offset| are expected to be tagged.
Node* AllocateSlicedTwoByteString(TNode<Smi> length, Node* parent, TNode<String> AllocateSlicedTwoByteString(TNode<Smi> length, Node* parent,
Node* offset); Node* offset);
// Allocate a one-byte ConsString with the given length, first and second // Allocate a one-byte ConsString with the given length, first and second
// parts. |length| is expected to be tagged, and |first| and |second| are // parts. |length| is expected to be tagged, and |first| and |second| are
// expected to be one-byte strings. // expected to be one-byte strings.
Node* AllocateOneByteConsString(TNode<Smi> length, Node* first, Node* second, TNode<String> AllocateOneByteConsString(TNode<Smi> length,
AllocationFlags flags = kNone); TNode<String> first,
TNode<String> second,
AllocationFlags flags = kNone);
// Allocate a two-byte ConsString with the given length, first and second // Allocate a two-byte ConsString with the given length, first and second
// parts. |length| is expected to be tagged, and |first| and |second| are // parts. |length| is expected to be tagged, and |first| and |second| are
// expected to be two-byte strings. // expected to be two-byte strings.
Node* AllocateTwoByteConsString(TNode<Smi> length, Node* first, Node* second, TNode<String> AllocateTwoByteConsString(TNode<Smi> length,
AllocationFlags flags = kNone); TNode<String> first,
TNode<String> second,
AllocationFlags flags = kNone);
// Allocate an appropriate one- or two-byte ConsString with the first and // Allocate an appropriate one- or two-byte ConsString with the first and
// second parts specified by |left| and |right|. // second parts specified by |left| and |right|.
Node* NewConsString(Node* context, TNode<Smi> length, Node* left, Node* right, TNode<String> NewConsString(Node* context, TNode<Smi> length,
AllocationFlags flags = kNone); TNode<String> left, TNode<String> right,
AllocationFlags flags = kNone);
Node* AllocateNameDictionary(int at_least_space_for); Node* AllocateNameDictionary(int at_least_space_for);
Node* AllocateNameDictionary(Node* at_least_space_for); Node* AllocateNameDictionary(Node* at_least_space_for);
...@@ -1216,11 +1223,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1216,11 +1223,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// Return a new string object which holds a substring containing the range // Return a new string object which holds a substring containing the range
// [from,to[ of string. |from| and |to| are expected to be tagged. // [from,to[ of string. |from| and |to| are expected to be tagged.
Node* SubString(Node* string, Node* from, Node* to); TNode<String> SubString(TNode<String> string, SloppyTNode<Smi> from,
SloppyTNode<Smi> to);
// Return a new string object produced by concatenating |first| with |second|. // Return a new string object produced by concatenating |first| with |second|.
Node* StringAdd(Node* context, Node* first, Node* second, TNode<String> StringAdd(Node* context, TNode<String> first,
AllocationFlags flags = kNone); TNode<String> second, AllocationFlags flags = kNone);
// Check if |string| is an indirect (thin or flat cons) string type that can // Check if |string| is an indirect (thin or flat cons) string type that can
// be dereferenced by DerefIndirectString. // be dereferenced by DerefIndirectString.
...@@ -2096,12 +2104,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -2096,12 +2104,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* EmitKeyedSloppyArguments(Node* receiver, Node* key, Node* value, Node* EmitKeyedSloppyArguments(Node* receiver, Node* key, Node* value,
Label* bailout); Label* bailout);
Node* AllocateSlicedString(Heap::RootListIndex map_root_index, TNode<String> AllocateSlicedString(Heap::RootListIndex map_root_index,
TNode<Smi> length, Node* parent, Node* offset); TNode<Smi> length, Node* parent,
Node* offset);
Node* AllocateConsString(Heap::RootListIndex map_root_index, TNode<String> AllocateConsString(Heap::RootListIndex map_root_index,
TNode<Smi> length, Node* first, Node* second, TNode<Smi> length, TNode<String> first,
AllocationFlags flags); TNode<String> second, AllocationFlags flags);
// Implements DescriptorArray::number_of_entries. // Implements DescriptorArray::number_of_entries.
// Returns an untagged int32. // Returns an untagged int32.
...@@ -2114,9 +2123,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -2114,9 +2123,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* CollectFeedbackForString(Node* instance_type); Node* CollectFeedbackForString(Node* instance_type);
void GenerateEqual_Same(Node* value, Label* if_equal, Label* if_notequal, void GenerateEqual_Same(Node* value, Label* if_equal, Label* if_notequal,
Variable* var_type_feedback = nullptr); Variable* var_type_feedback = nullptr);
Node* AllocAndCopyStringCharacters(Node* from, Node* from_instance_type, TNode<String> AllocAndCopyStringCharacters(Node* from,
TNode<IntPtrT> from_index, Node* from_instance_type,
TNode<Smi> character_count); TNode<IntPtrT> from_index,
TNode<Smi> character_count);
static const int kElementLoopUnrollThreshold = 8; static const int kElementLoopUnrollThreshold = 8;
......
...@@ -289,7 +289,7 @@ TF_STUB(StringAddStub, CodeStubAssembler) { ...@@ -289,7 +289,7 @@ TF_STUB(StringAddStub, CodeStubAssembler) {
CodeStubAssembler::AllocationFlag allocation_flags = CodeStubAssembler::AllocationFlag allocation_flags =
(pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured (pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured
: CodeStubAssembler::kNone; : CodeStubAssembler::kNone;
Return(StringAdd(context, left, right, allocation_flags)); Return(StringAdd(context, CAST(left), CAST(right), allocation_flags));
} else { } else {
Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE,
pretenure_flag); pretenure_flag);
......
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