Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Unified Diff: src/builtins/builtins-string.cc

Issue 2373493002: [stubs] Port String.prototype.substr to TurboFan (Closed)
Patch Set: Additional tests Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/js/i18n.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins/builtins-string.cc
diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc
index e716dca73bfd562767759d07c71bfdb4812c5b91..19338fbd9c173ba1042b3b3cc40dadbeb9b9f7c8 100644
--- a/src/builtins/builtins-string.cc
+++ b/src/builtins/builtins-string.cc
@@ -873,6 +873,129 @@ BUILTIN(StringPrototypeNormalize) {
return *string;
}
+// ES6 section B.2.3.1 String.prototype.substr ( start, length )
+void Builtins::Generate_StringPrototypeSubstr(CodeStubAssembler* a) {
+ typedef CodeStubAssembler::Label Label;
+ typedef compiler::Node Node;
+ typedef CodeStubAssembler::Variable Variable;
+
+ Label out(a), handle_length(a);
+
+ Variable var_start(a, MachineRepresentation::kTagged);
+ Variable var_length(a, MachineRepresentation::kTagged);
+
+ Node* const receiver = a->Parameter(0);
+ Node* const start = a->Parameter(1);
+ Node* const length = a->Parameter(2);
+ Node* const context = a->Parameter(5);
+
+ Node* const zero = a->SmiConstant(Smi::FromInt(0));
+
+ // Check that {receiver} is coercible to Object and convert it to a String.
+ Node* const string =
+ a->ToThisString(context, receiver, "String.prototype.substr");
+
+ Node* const string_length = a->LoadStringLength(string);
+
+ // Conversions and bounds-checks for {start}.
+ {
+ Node* const start_int =
+ a->ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero);
+
+ Label if_issmi(a), if_isheapnumber(a, Label::kDeferred);
+ a->Branch(a->WordIsSmi(start_int), &if_issmi, &if_isheapnumber);
+
+ a->Bind(&if_issmi);
+ {
+ Node* const length_plus_start = a->SmiAdd(string_length, start_int);
+ var_start.Bind(a->Select(a->SmiLessThan(start_int, zero),
+ a->SmiMax(length_plus_start, zero), start_int));
+ a->Goto(&handle_length);
+ }
+
+ a->Bind(&if_isheapnumber);
+ {
+ // If {start} is a heap number, it is definitely out of bounds. If it is
+ // negative, {start} = max({string_length} + {start}),0) = 0'. If it is
+ // positive, set {start} to {string_length} which ultimately results in
+ // returning an empty string.
+ Node* const float_zero = a->Float64Constant(0.);
+ Node* const start_float = a->LoadHeapNumberValue(start_int);
+ var_start.Bind(a->Select(a->Float64LessThan(start_float, float_zero),
+ zero, string_length));
+ a->Goto(&handle_length);
+ }
+ }
+
+ // Conversions and bounds-checks for {length}.
+ a->Bind(&handle_length);
+ {
+ Label if_issmi(a), if_isheapnumber(a, Label::kDeferred);
+
+ // Default to {string_length} if {length} is undefined.
+ {
+ Label if_isundefined(a, Label::kDeferred), if_isnotundefined(a);
+ a->Branch(a->WordEqual(length, a->UndefinedConstant()), &if_isundefined,
+ &if_isnotundefined);
+
+ a->Bind(&if_isundefined);
+ var_length.Bind(string_length);
+ a->Goto(&if_issmi);
+
+ a->Bind(&if_isnotundefined);
+ var_length.Bind(
+ a->ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero));
+ }
+
+ a->Branch(a->WordIsSmi(var_length.value()), &if_issmi, &if_isheapnumber);
+
+ // Set {length} to min(max({length}, 0), {string_length} - {start}
+ a->Bind(&if_issmi);
+ {
+ Node* const positive_length = a->SmiMax(var_length.value(), zero);
+
+ Node* const minimal_length = a->SmiSub(string_length, var_start.value());
+ var_length.Bind(a->SmiMin(positive_length, minimal_length));
+
+ a->GotoUnless(a->SmiLessThanOrEqual(var_length.value(), zero), &out);
+ a->Return(a->EmptyStringConstant());
+ }
+
+ a->Bind(&if_isheapnumber);
+ {
+ // If {length} is a heap number, it is definitely out of bounds. There are
+ // two cases according to the spec: if it is negative, "" is returned; if
+ // it is positive, then length is set to {string_length} - {start}.
+
+ a->Assert(a->WordEqual(a->LoadMap(var_length.value()),
+ a->HeapNumberMapConstant()));
+
+ Label if_isnegative(a), if_ispositive(a);
+ Node* const float_zero = a->Float64Constant(0.);
+ Node* const length_float = a->LoadHeapNumberValue(var_length.value());
+ a->Branch(a->Float64LessThan(length_float, float_zero), &if_isnegative,
+ &if_ispositive);
+
+ a->Bind(&if_isnegative);
+ a->Return(a->EmptyStringConstant());
+
+ a->Bind(&if_ispositive);
+ {
+ var_length.Bind(a->SmiSub(string_length, var_start.value()));
+ a->GotoUnless(a->SmiLessThanOrEqual(var_length.value(), zero), &out);
+ a->Return(a->EmptyStringConstant());
+ }
+ }
+ }
+
+ a->Bind(&out);
+ {
+ Node* const end = a->SmiAdd(var_start.value(), var_length.value());
+ Node* const result = a->SubString(context, string, var_start.value(), end);
+ a->Return(result);
+ }
+}
+
namespace {
compiler::Node* ToSmiBetweenZeroAnd(CodeStubAssembler* a,
« no previous file with comments | « src/builtins/builtins.h ('k') | src/js/i18n.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698