Commit eb6a8ada authored by jgruber's avatar jgruber Committed by Commit bot

[regexp] Convert builtins to TF_BUILTIN macro

BUG=v8:5339

Review-Url: https://codereview.chromium.org/2543243002
Cr-Commit-Position: refs/heads/master@{#41491}
parent 28cc20ee
...@@ -19,6 +19,14 @@ typedef CodeStubAssembler::Variable CVariable; ...@@ -19,6 +19,14 @@ typedef CodeStubAssembler::Variable CVariable;
typedef CodeStubAssembler::ParameterMode ParameterMode; typedef CodeStubAssembler::ParameterMode ParameterMode;
typedef compiler::CodeAssemblerState CodeAssemblerState; typedef compiler::CodeAssemblerState CodeAssemblerState;
class RegExpBuiltinsAssembler : public CodeStubAssembler {
public:
explicit RegExpBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ES6 section 21.2 RegExp Objects // ES6 section 21.2 RegExp Objects
...@@ -393,37 +401,35 @@ void BranchIfFastRegExpResult(CodeStubAssembler* a, Node* context, Node* map, ...@@ -393,37 +401,35 @@ void BranchIfFastRegExpResult(CodeStubAssembler* a, Node* context, Node* map,
// ES#sec-regexp.prototype.exec // ES#sec-regexp.prototype.exec
// RegExp.prototype.exec ( string ) // RegExp.prototype.exec ( string )
void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = Parameter(1);
Node* const maybe_receiver = a.Parameter(0); Node* const context = Parameter(4);
Node* const maybe_string = a.Parameter(1);
Node* const context = a.Parameter(4);
// Ensure {maybe_receiver} is a JSRegExp. // Ensure {maybe_receiver} is a JSRegExp.
Node* const regexp_map = a.ThrowIfNotInstanceType( Node* const regexp_map = ThrowIfNotInstanceType(
context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec");
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 = a.ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
CLabel if_isfastpath(&a), if_isslowpath(&a); CLabel if_isfastpath(this), if_isslowpath(this);
a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath, Branch(IsInitialRegExpMap(this, context, regexp_map), &if_isfastpath,
&if_isslowpath); &if_isslowpath);
a.Bind(&if_isfastpath); Bind(&if_isfastpath);
{ {
Node* const result = Node* const result =
RegExpPrototypeExecBody(&a, context, receiver, string, true); RegExpPrototypeExecBody(this, context, receiver, string, true);
a.Return(result); Return(result);
} }
a.Bind(&if_isslowpath); Bind(&if_isslowpath);
{ {
Node* const result = Node* const result =
RegExpPrototypeExecBody(&a, context, receiver, string, false); RegExpPrototypeExecBody(this, context, receiver, string, false);
a.Return(result); Return(result);
} }
} }
...@@ -595,282 +601,273 @@ Node* RegExpInitialize(CodeStubAssembler* a, Node* const context, ...@@ -595,282 +601,273 @@ Node* RegExpInitialize(CodeStubAssembler* a, Node* const context,
} // namespace } // namespace
void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* isolate = this->isolate();
Isolate* isolate = a.isolate(); Node* const maybe_receiver = Parameter(0);
Node* const context = Parameter(3);
Node* const maybe_receiver = a.Parameter(0); Node* const map = ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver,
Node* const context = a.Parameter(3);
Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver,
MessageTemplate::kRegExpNonObject, MessageTemplate::kRegExpNonObject,
"RegExp.prototype.flags"); "RegExp.prototype.flags");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
CLabel if_isfastpath(&a), if_isslowpath(&a, CLabel::kDeferred); CLabel if_isfastpath(this), if_isslowpath(this, CLabel::kDeferred);
a.Branch(IsInitialRegExpMap(&a, context, map), &if_isfastpath, Branch(IsInitialRegExpMap(this, context, map), &if_isfastpath,
&if_isslowpath); &if_isslowpath);
a.Bind(&if_isfastpath); Bind(&if_isfastpath);
a.Return(FlagsGetter(&a, receiver, context, true)); Return(FlagsGetter(this, receiver, context, true));
a.Bind(&if_isslowpath); Bind(&if_isslowpath);
a.Return(FlagsGetter(&a, receiver, context, false)); Return(FlagsGetter(this, receiver, context, false));
} }
// ES#sec-regexp-pattern-flags // ES#sec-regexp-pattern-flags
// RegExp ( pattern, flags ) // RegExp ( pattern, flags )
void Builtins::Generate_RegExpConstructor(CodeAssemblerState* state) { TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Node* const pattern = Parameter(1);
Node* const flags = Parameter(2);
Node* const pattern = a.Parameter(1); Node* const new_target = Parameter(3);
Node* const flags = a.Parameter(2); Node* const context = Parameter(5);
Node* const new_target = a.Parameter(3);
Node* const context = a.Parameter(5);
Isolate* isolate = a.isolate(); Isolate* isolate = this->isolate();
CVariable var_flags(&a, MachineRepresentation::kTagged); CVariable var_flags(this, MachineRepresentation::kTagged);
CVariable var_pattern(&a, MachineRepresentation::kTagged); CVariable var_pattern(this, MachineRepresentation::kTagged);
CVariable var_new_target(&a, MachineRepresentation::kTagged); CVariable var_new_target(this, MachineRepresentation::kTagged);
var_flags.Bind(flags); var_flags.Bind(flags);
var_pattern.Bind(pattern); var_pattern.Bind(pattern);
var_new_target.Bind(new_target); var_new_target.Bind(new_target);
Node* const native_context = a.LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const regexp_function = Node* const regexp_function =
a.LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
Node* const pattern_is_regexp = IsRegExp(&a, context, pattern); Node* const pattern_is_regexp = IsRegExp(this, context, pattern);
{ {
CLabel next(&a); CLabel next(this);
a.GotoUnless(a.IsUndefined(new_target), &next); GotoUnless(IsUndefined(new_target), &next);
var_new_target.Bind(regexp_function); var_new_target.Bind(regexp_function);
a.GotoUnless(pattern_is_regexp, &next); GotoUnless(pattern_is_regexp, &next);
a.GotoUnless(a.IsUndefined(flags), &next); GotoUnless(IsUndefined(flags), &next);
Callable getproperty_callable = CodeFactory::GetProperty(isolate); Callable getproperty_callable = CodeFactory::GetProperty(isolate);
Node* const name = a.HeapConstant(isolate->factory()->constructor_string()); Node* const name = HeapConstant(isolate->factory()->constructor_string());
Node* const value = Node* const value = CallStub(getproperty_callable, context, pattern, name);
a.CallStub(getproperty_callable, context, pattern, name);
a.GotoUnless(a.WordEqual(value, regexp_function), &next); GotoUnless(WordEqual(value, regexp_function), &next);
a.Return(pattern); Return(pattern);
a.Bind(&next); Bind(&next);
} }
{ {
CLabel next(&a), if_patternisfastregexp(&a), if_patternisslowregexp(&a); CLabel next(this), if_patternisfastregexp(this),
a.GotoIf(a.TaggedIsSmi(pattern), &next); if_patternisslowregexp(this);
GotoIf(TaggedIsSmi(pattern), &next);
a.GotoIf(a.HasInstanceType(pattern, JS_REGEXP_TYPE), GotoIf(HasInstanceType(pattern, JS_REGEXP_TYPE), &if_patternisfastregexp);
&if_patternisfastregexp);
a.Branch(pattern_is_regexp, &if_patternisslowregexp, &next); Branch(pattern_is_regexp, &if_patternisslowregexp, &next);
a.Bind(&if_patternisfastregexp); Bind(&if_patternisfastregexp);
{ {
Node* const source = a.LoadObjectField(pattern, JSRegExp::kSourceOffset); Node* const source = LoadObjectField(pattern, JSRegExp::kSourceOffset);
var_pattern.Bind(source); var_pattern.Bind(source);
{ {
CLabel inner_next(&a); CLabel inner_next(this);
a.GotoUnless(a.IsUndefined(flags), &inner_next); GotoUnless(IsUndefined(flags), &inner_next);
Node* const value = FlagsGetter(&a, pattern, context, true); Node* const value = FlagsGetter(this, pattern, context, true);
var_flags.Bind(value); var_flags.Bind(value);
a.Goto(&inner_next); Goto(&inner_next);
a.Bind(&inner_next); Bind(&inner_next);
} }
a.Goto(&next); Goto(&next);
} }
a.Bind(&if_patternisslowregexp); Bind(&if_patternisslowregexp);
{ {
Callable getproperty_callable = CodeFactory::GetProperty(isolate); Callable getproperty_callable = CodeFactory::GetProperty(isolate);
{ {
Node* const name = a.HeapConstant(isolate->factory()->source_string()); Node* const name = HeapConstant(isolate->factory()->source_string());
Node* const value = Node* const value =
a.CallStub(getproperty_callable, context, pattern, name); CallStub(getproperty_callable, context, pattern, name);
var_pattern.Bind(value); var_pattern.Bind(value);
} }
{ {
CLabel inner_next(&a); CLabel inner_next(this);
a.GotoUnless(a.IsUndefined(flags), &inner_next); GotoUnless(IsUndefined(flags), &inner_next);
Node* const name = a.HeapConstant(isolate->factory()->flags_string()); Node* const name = HeapConstant(isolate->factory()->flags_string());
Node* const value = Node* const value =
a.CallStub(getproperty_callable, context, pattern, name); CallStub(getproperty_callable, context, pattern, name);
var_flags.Bind(value); var_flags.Bind(value);
a.Goto(&inner_next); Goto(&inner_next);
a.Bind(&inner_next); Bind(&inner_next);
} }
a.Goto(&next); Goto(&next);
} }
a.Bind(&next); Bind(&next);
} }
// Allocate. // Allocate.
CVariable var_regexp(&a, MachineRepresentation::kTagged); CVariable var_regexp(this, MachineRepresentation::kTagged);
{ {
CLabel allocate_jsregexp(&a), allocate_generic(&a, CLabel::kDeferred), CLabel allocate_jsregexp(this), allocate_generic(this, CLabel::kDeferred),
next(&a); next(this);
a.Branch(a.WordEqual(var_new_target.value(), regexp_function), Branch(WordEqual(var_new_target.value(), regexp_function),
&allocate_jsregexp, &allocate_generic); &allocate_jsregexp, &allocate_generic);
a.Bind(&allocate_jsregexp); Bind(&allocate_jsregexp);
{ {
Node* const initial_map = a.LoadObjectField( Node* const initial_map = LoadObjectField(
regexp_function, JSFunction::kPrototypeOrInitialMapOffset); regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
Node* const regexp = a.AllocateJSObjectFromMap(initial_map); Node* const regexp = AllocateJSObjectFromMap(initial_map);
var_regexp.Bind(regexp); var_regexp.Bind(regexp);
a.Goto(&next); Goto(&next);
} }
a.Bind(&allocate_generic); Bind(&allocate_generic);
{ {
Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate); Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate);
Node* const regexp = a.CallStub(fastnewobject_callable, context, Node* const regexp = CallStub(fastnewobject_callable, context,
regexp_function, var_new_target.value()); regexp_function, var_new_target.value());
var_regexp.Bind(regexp); var_regexp.Bind(regexp);
a.Goto(&next); Goto(&next);
} }
a.Bind(&next); Bind(&next);
} }
Node* const result = RegExpInitialize(&a, context, var_regexp.value(), Node* const result = RegExpInitialize(this, context, var_regexp.value(),
var_pattern.value(), var_flags.value()); var_pattern.value(), var_flags.value());
a.Return(result); Return(result);
} }
// ES#sec-regexp.prototype.compile // ES#sec-regexp.prototype.compile
// RegExp.prototype.compile ( pattern, flags ) // RegExp.prototype.compile ( pattern, flags )
void Builtins::Generate_RegExpPrototypeCompile(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Node* const maybe_receiver = Parameter(0);
Node* const maybe_pattern = Parameter(1);
Node* const maybe_receiver = a.Parameter(0); Node* const maybe_flags = Parameter(2);
Node* const maybe_pattern = a.Parameter(1); Node* const context = Parameter(5);
Node* const maybe_flags = a.Parameter(2);
Node* const context = a.Parameter(5); ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
"RegExp.prototype.compile");
a.ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
"RegExp.prototype.compile");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
CVariable var_flags(&a, MachineRepresentation::kTagged); CVariable var_flags(this, MachineRepresentation::kTagged);
CVariable var_pattern(&a, MachineRepresentation::kTagged); CVariable var_pattern(this, MachineRepresentation::kTagged);
var_flags.Bind(maybe_flags); var_flags.Bind(maybe_flags);
var_pattern.Bind(maybe_pattern); var_pattern.Bind(maybe_pattern);
// Handle a JSRegExp pattern. // Handle a JSRegExp pattern.
{ {
CLabel next(&a); CLabel next(this);
a.GotoIf(a.TaggedIsSmi(maybe_pattern), &next); GotoIf(TaggedIsSmi(maybe_pattern), &next);
a.GotoUnless(a.HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next); GotoUnless(HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next);
Node* const pattern = maybe_pattern; Node* const pattern = maybe_pattern;
// {maybe_flags} must be undefined in this case, otherwise throw. // {maybe_flags} must be undefined in this case, otherwise throw.
{ {
CLabel next(&a); CLabel next(this);
a.GotoIf(a.IsUndefined(maybe_flags), &next); GotoIf(IsUndefined(maybe_flags), &next);
Node* const message_id = a.SmiConstant(MessageTemplate::kRegExpFlags); Node* const message_id = SmiConstant(MessageTemplate::kRegExpFlags);
a.TailCallRuntime(Runtime::kThrowTypeError, context, message_id); TailCallRuntime(Runtime::kThrowTypeError, context, message_id);
a.Bind(&next); Bind(&next);
} }
Node* const new_flags = FlagsGetter(&a, pattern, context, true); Node* const new_flags = FlagsGetter(this, pattern, context, true);
Node* const new_pattern = Node* const new_pattern = LoadObjectField(pattern, JSRegExp::kSourceOffset);
a.LoadObjectField(pattern, JSRegExp::kSourceOffset);
var_flags.Bind(new_flags); var_flags.Bind(new_flags);
var_pattern.Bind(new_pattern); var_pattern.Bind(new_pattern);
a.Goto(&next); Goto(&next);
a.Bind(&next); Bind(&next);
} }
RegExpInitialize(&a, context, receiver, var_pattern.value(), RegExpInitialize(this, context, receiver, var_pattern.value(),
var_flags.value()); var_flags.value());
// Return undefined for compatibility with JSC. // Return undefined for compatibility with JSC.
// See http://crbug.com/585775 for web compat details. // See http://crbug.com/585775 for web compat details.
a.Return(a.UndefinedConstant()); Return(UndefinedConstant());
} }
// ES6 21.2.5.10. // ES6 21.2.5.10.
void Builtins::Generate_RegExpPrototypeSourceGetter(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeSourceGetter, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Node* const receiver = Parameter(0);
Node* const receiver = a.Parameter(0); Node* const context = Parameter(3);
Node* const context = a.Parameter(3);
// Check whether we have an unmodified regexp instance. // Check whether we have an unmodified regexp instance.
CLabel if_isjsregexp(&a), if_isnotjsregexp(&a, CLabel::kDeferred); CLabel if_isjsregexp(this), if_isnotjsregexp(this, CLabel::kDeferred);
a.GotoIf(a.TaggedIsSmi(receiver), &if_isnotjsregexp); GotoIf(TaggedIsSmi(receiver), &if_isnotjsregexp);
a.Branch(a.HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isjsregexp, Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isjsregexp,
&if_isnotjsregexp); &if_isnotjsregexp);
a.Bind(&if_isjsregexp); Bind(&if_isjsregexp);
{ {
Node* const source = a.LoadObjectField(receiver, JSRegExp::kSourceOffset); Node* const source = LoadObjectField(receiver, JSRegExp::kSourceOffset);
a.Return(source); Return(source);
} }
a.Bind(&if_isnotjsregexp); Bind(&if_isnotjsregexp);
{ {
Isolate* isolate = a.isolate(); Isolate* isolate = this->isolate();
Node* const native_context = a.LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const regexp_fun = Node* const regexp_fun =
a.LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
Node* const initial_map = Node* const initial_map =
a.LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
Node* const initial_prototype = a.LoadMapPrototype(initial_map); Node* const initial_prototype = LoadMapPrototype(initial_map);
CLabel if_isprototype(&a), if_isnotprototype(&a); CLabel if_isprototype(this), if_isnotprototype(this);
a.Branch(a.WordEqual(receiver, initial_prototype), &if_isprototype, Branch(WordEqual(receiver, initial_prototype), &if_isprototype,
&if_isnotprototype); &if_isnotprototype);
a.Bind(&if_isprototype); Bind(&if_isprototype);
{ {
const int counter = v8::Isolate::kRegExpPrototypeSourceGetter; const int counter = v8::Isolate::kRegExpPrototypeSourceGetter;
Node* const counter_smi = a.SmiConstant(counter); Node* const counter_smi = SmiConstant(counter);
a.CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
Node* const result = Node* const result =
a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked("(?:)")); HeapConstant(isolate->factory()->NewStringFromAsciiChecked("(?:)"));
a.Return(result); Return(result);
} }
a.Bind(&if_isnotprototype); Bind(&if_isnotprototype);
{ {
Node* const message_id = Node* const message_id =
a.SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp));
Node* const method_name_str = Node* const method_name_str =
a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked( HeapConstant(isolate->factory()->NewStringFromAsciiChecked(
"RegExp.prototype.source")); "RegExp.prototype.source"));
a.TailCallRuntime(Runtime::kThrowTypeError, context, message_id, TailCallRuntime(Runtime::kThrowTypeError, context, message_id,
method_name_str); method_name_str);
} }
} }
} }
...@@ -913,11 +910,9 @@ BUILTIN(RegExpPrototypeToString) { ...@@ -913,11 +910,9 @@ BUILTIN(RegExpPrototypeToString) {
} }
// ES6 21.2.4.2. // ES6 21.2.4.2.
void Builtins::Generate_RegExpPrototypeSpeciesGetter( TF_BUILTIN(RegExpPrototypeSpeciesGetter, RegExpBuiltinsAssembler) {
CodeAssemblerState* state) { Node* const receiver = Parameter(0);
CodeStubAssembler a(state); Return(receiver);
Node* const receiver = a.Parameter(0);
a.Return(receiver);
} }
namespace { namespace {
...@@ -1057,44 +1052,36 @@ void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, ...@@ -1057,44 +1052,36 @@ void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag,
} // namespace } // namespace
// ES6 21.2.5.4. // ES6 21.2.5.4.
void Builtins::Generate_RegExpPrototypeGlobalGetter(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeGlobalGetter, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Generate_FlagGetter(this, JSRegExp::kGlobal,
Generate_FlagGetter(&a, JSRegExp::kGlobal,
v8::Isolate::kRegExpPrototypeOldFlagGetter, v8::Isolate::kRegExpPrototypeOldFlagGetter,
"RegExp.prototype.global"); "RegExp.prototype.global");
} }
// ES6 21.2.5.5. // ES6 21.2.5.5.
void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter( TF_BUILTIN(RegExpPrototypeIgnoreCaseGetter, RegExpBuiltinsAssembler) {
CodeAssemblerState* state) { Generate_FlagGetter(this, JSRegExp::kIgnoreCase,
CodeStubAssembler a(state);
Generate_FlagGetter(&a, JSRegExp::kIgnoreCase,
v8::Isolate::kRegExpPrototypeOldFlagGetter, v8::Isolate::kRegExpPrototypeOldFlagGetter,
"RegExp.prototype.ignoreCase"); "RegExp.prototype.ignoreCase");
} }
// ES6 21.2.5.7. // ES6 21.2.5.7.
void Builtins::Generate_RegExpPrototypeMultilineGetter( TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) {
CodeAssemblerState* state) { Generate_FlagGetter(this, JSRegExp::kMultiline,
CodeStubAssembler a(state);
Generate_FlagGetter(&a, JSRegExp::kMultiline,
v8::Isolate::kRegExpPrototypeOldFlagGetter, v8::Isolate::kRegExpPrototypeOldFlagGetter,
"RegExp.prototype.multiline"); "RegExp.prototype.multiline");
} }
// ES6 21.2.5.12. // ES6 21.2.5.12.
void Builtins::Generate_RegExpPrototypeStickyGetter(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Generate_FlagGetter(this, JSRegExp::kSticky,
Generate_FlagGetter(&a, JSRegExp::kSticky,
v8::Isolate::kRegExpPrototypeStickyGetter, v8::Isolate::kRegExpPrototypeStickyGetter,
"RegExp.prototype.sticky"); "RegExp.prototype.sticky");
} }
// ES6 21.2.5.15. // ES6 21.2.5.15.
void Builtins::Generate_RegExpPrototypeUnicodeGetter( TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) {
CodeAssemblerState* state) { Generate_FlagGetter(this, JSRegExp::kUnicode,
CodeStubAssembler a(state);
Generate_FlagGetter(&a, JSRegExp::kUnicode,
v8::Isolate::kRegExpPrototypeUnicodeGetter, v8::Isolate::kRegExpPrototypeUnicodeGetter,
"RegExp.prototype.unicode"); "RegExp.prototype.unicode");
} }
...@@ -1258,47 +1245,45 @@ Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, ...@@ -1258,47 +1245,45 @@ Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv,
// ES#sec-regexp.prototype.test // ES#sec-regexp.prototype.test
// RegExp.prototype.test ( S ) // RegExp.prototype.test ( S )
void Builtins::Generate_RegExpPrototypeTest(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* const isolate = this->isolate();
Isolate* const isolate = a.isolate();
Node* const maybe_receiver = a.Parameter(0); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = a.Parameter(1); Node* const maybe_string = Parameter(1);
Node* const context = a.Parameter(4); Node* const context = Parameter(4);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( Node* const map = ThrowIfNotJSReceiver(
&a, isolate, context, maybe_receiver, this, isolate, context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.test"); MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.test");
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 = a.ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
CLabel fast_path(&a), slow_path(&a); CLabel fast_path(this), slow_path(this);
BranchIfFastPath(&a, context, map, &fast_path, &slow_path); BranchIfFastPath(this, context, map, &fast_path, &slow_path);
a.Bind(&fast_path); Bind(&fast_path);
{ {
CLabel if_didnotmatch(&a); CLabel if_didnotmatch(this);
RegExpPrototypeExecBodyWithoutResult(&a, context, receiver, string, RegExpPrototypeExecBodyWithoutResult(this, context, receiver, string,
&if_didnotmatch, true); &if_didnotmatch, true);
a.Return(a.TrueConstant()); Return(TrueConstant());
a.Bind(&if_didnotmatch); Bind(&if_didnotmatch);
a.Return(a.FalseConstant()); Return(FalseConstant());
} }
a.Bind(&slow_path); Bind(&slow_path);
{ {
// Call exec. // Call exec.
Node* const match_indices = RegExpExec(&a, context, receiver, string); Node* const match_indices = RegExpExec(this, context, receiver, string);
// Return true iff exec matched successfully. // Return true iff exec matched successfully.
Node* const result = a.SelectBooleanConstant( Node* const result =
a.WordNotEqual(match_indices, a.NullConstant())); SelectBooleanConstant(WordNotEqual(match_indices, NullConstant()));
a.Return(result); Return(result);
} }
} }
...@@ -1619,30 +1604,28 @@ void RegExpPrototypeMatchBody(CodeStubAssembler* a, Node* const receiver, ...@@ -1619,30 +1604,28 @@ void RegExpPrototypeMatchBody(CodeStubAssembler* a, Node* const receiver,
// ES#sec-regexp.prototype-@@match // ES#sec-regexp.prototype-@@match
// RegExp.prototype [ @@match ] ( string ) // RegExp.prototype [ @@match ] ( string )
void Builtins::Generate_RegExpPrototypeMatch(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = Parameter(1);
Node* const maybe_receiver = a.Parameter(0); Node* const context = Parameter(4);
Node* const maybe_string = a.Parameter(1);
Node* const context = a.Parameter(4);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( Node* const map = ThrowIfNotJSReceiver(
&a, a.isolate(), context, maybe_receiver, this, isolate(), context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match"); MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match");
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 = a.ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
CLabel fast_path(&a), slow_path(&a); CLabel fast_path(this), slow_path(this);
BranchIfFastPath(&a, context, map, &fast_path, &slow_path); BranchIfFastPath(this, context, map, &fast_path, &slow_path);
a.Bind(&fast_path); Bind(&fast_path);
RegExpPrototypeMatchBody(&a, receiver, string, context, true); RegExpPrototypeMatchBody(this, receiver, string, context, true);
a.Bind(&slow_path); Bind(&slow_path);
RegExpPrototypeMatchBody(&a, receiver, string, context, false); RegExpPrototypeMatchBody(this, receiver, string, context, false);
} }
namespace { namespace {
...@@ -1751,33 +1734,31 @@ void RegExpPrototypeSearchBodySlow(CodeStubAssembler* a, Node* const receiver, ...@@ -1751,33 +1734,31 @@ void RegExpPrototypeSearchBodySlow(CodeStubAssembler* a, Node* const receiver,
// ES#sec-regexp.prototype-@@search // ES#sec-regexp.prototype-@@search
// RegExp.prototype [ @@search ] ( string ) // RegExp.prototype [ @@search ] ( string )
void Builtins::Generate_RegExpPrototypeSearch(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* const isolate = this->isolate();
Isolate* const isolate = a.isolate(); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = Parameter(1);
Node* const maybe_receiver = a.Parameter(0); Node* const context = Parameter(4);
Node* const maybe_string = a.Parameter(1);
Node* const context = a.Parameter(4);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = Node* const map =
ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@search"); "RegExp.prototype.@@search");
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 = a.ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
CLabel fast_path(&a), slow_path(&a); CLabel fast_path(this), slow_path(this);
BranchIfFastPath(&a, context, map, &fast_path, &slow_path); BranchIfFastPath(this, context, map, &fast_path, &slow_path);
a.Bind(&fast_path); Bind(&fast_path);
RegExpPrototypeSearchBodyFast(&a, receiver, string, context); RegExpPrototypeSearchBodyFast(this, receiver, string, context);
a.Bind(&slow_path); Bind(&slow_path);
RegExpPrototypeSearchBodySlow(&a, receiver, string, context); RegExpPrototypeSearchBodySlow(this, receiver, string, context);
} }
namespace { namespace {
...@@ -2033,67 +2014,65 @@ void Generate_RegExpPrototypeSplitBody(CodeStubAssembler* a, Node* const regexp, ...@@ -2033,67 +2014,65 @@ void Generate_RegExpPrototypeSplitBody(CodeStubAssembler* a, Node* const regexp,
// ES#sec-regexp.prototype-@@split // ES#sec-regexp.prototype-@@split
// RegExp.prototype [ @@split ] ( string, limit ) // RegExp.prototype [ @@split ] ( string, limit )
void Builtins::Generate_RegExpPrototypeSplit(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* const isolate = this->isolate();
Isolate* const isolate = a.isolate();
Node* const undefined = a.UndefinedConstant(); Node* const undefined = UndefinedConstant();
Node* const maybe_receiver = a.Parameter(0); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = a.Parameter(1); Node* const maybe_string = Parameter(1);
Node* const maybe_limit = a.Parameter(2); Node* const maybe_limit = Parameter(2);
Node* const context = a.Parameter(5); Node* const context = Parameter(5);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( Node* const map = ThrowIfNotJSReceiver(
&a, isolate, context, maybe_receiver, this, isolate, context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@split"); MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@split");
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 = a.ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
CLabel fast_path(&a), slow_path(&a); CLabel fast_path(this), slow_path(this);
BranchIfFastPath(&a, context, map, &fast_path, &slow_path); BranchIfFastPath(this, context, map, &fast_path, &slow_path);
a.Bind(&fast_path); Bind(&fast_path);
{ {
// Convert {maybe_limit} to a uint32, capping at the maximal smi value. // Convert {maybe_limit} to a uint32, capping at the maximal smi value.
CVariable var_limit(&a, MachineRepresentation::kTagged); CVariable var_limit(this, MachineRepresentation::kTagged);
CLabel if_limitissmimax(&a), limit_done(&a); CLabel if_limitissmimax(this), limit_done(this);
a.GotoIf(a.WordEqual(maybe_limit, undefined), &if_limitissmimax); GotoIf(WordEqual(maybe_limit, undefined), &if_limitissmimax);
{ {
Node* const limit = a.ToUint32(context, maybe_limit); Node* const limit = ToUint32(context, maybe_limit);
a.GotoUnless(a.TaggedIsSmi(limit), &if_limitissmimax); GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
var_limit.Bind(limit); var_limit.Bind(limit);
a.Goto(&limit_done); Goto(&limit_done);
} }
a.Bind(&if_limitissmimax); Bind(&if_limitissmimax);
{ {
// TODO(jgruber): In this case, we can probably generation of limit checks // TODO(jgruber): In this case, we can probably generation of limit checks
// in Generate_RegExpPrototypeSplitBody. // in Generate_RegExpPrototypeSplitBody.
Node* const smi_max = a.SmiConstant(Smi::kMaxValue); Node* const smi_max = SmiConstant(Smi::kMaxValue);
var_limit.Bind(smi_max); var_limit.Bind(smi_max);
a.Goto(&limit_done); Goto(&limit_done);
} }
a.Bind(&limit_done); Bind(&limit_done);
{ {
Node* const limit = var_limit.value(); Node* const limit = var_limit.value();
Generate_RegExpPrototypeSplitBody(&a, receiver, string, limit, context); Generate_RegExpPrototypeSplitBody(this, receiver, string, limit, context);
} }
} }
a.Bind(&slow_path); Bind(&slow_path);
{ {
Node* const result = a.CallRuntime(Runtime::kRegExpSplit, context, receiver, Node* const result = CallRuntime(Runtime::kRegExpSplit, context, receiver,
string, maybe_limit); string, maybe_limit);
a.Return(result); Return(result);
} }
} }
...@@ -2424,128 +2403,124 @@ Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, Node* context, ...@@ -2424,128 +2403,124 @@ Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, Node* context,
// ES#sec-regexp.prototype-@@replace // ES#sec-regexp.prototype-@@replace
// RegExp.prototype [ @@replace ] ( string, replaceValue ) // RegExp.prototype [ @@replace ] ( string, replaceValue )
void Builtins::Generate_RegExpPrototypeReplace(CodeAssemblerState* state) { TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* const isolate = this->isolate();
Isolate* const isolate = a.isolate(); Node* const maybe_receiver = Parameter(0);
Node* const maybe_string = Parameter(1);
Node* const replace_value = Parameter(2);
Node* const context = Parameter(5);
Node* const maybe_receiver = a.Parameter(0); Node* const int_zero = IntPtrConstant(0);
Node* const maybe_string = a.Parameter(1);
Node* const replace_value = a.Parameter(2);
Node* const context = a.Parameter(5);
Node* const int_zero = a.IntPtrConstant(0);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = Node* const map =
ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@replace"); "RegExp.prototype.@@replace");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Callable tostring_callable = CodeFactory::ToString(isolate); Callable tostring_callable = CodeFactory::ToString(isolate);
Node* const string = a.CallStub(tostring_callable, context, maybe_string); Node* const string = CallStub(tostring_callable, 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?
CLabel checkreplacecallable(&a), runtime(&a, CLabel::kDeferred), fastpath(&a); CLabel checkreplacecallable(this), runtime(this, CLabel::kDeferred),
BranchIfFastPath(&a, context, map, &checkreplacecallable, &runtime); fastpath(this);
BranchIfFastPath(this, context, map, &checkreplacecallable, &runtime);
a.Bind(&checkreplacecallable); Bind(&checkreplacecallable);
Node* const regexp = receiver; Node* const regexp = receiver;
// 2. Is {replace_value} callable? // 2. Is {replace_value} callable?
CLabel checkreplacestring(&a), if_iscallable(&a); CLabel checkreplacestring(this), if_iscallable(this);
a.GotoIf(a.TaggedIsSmi(replace_value), &checkreplacestring); GotoIf(TaggedIsSmi(replace_value), &checkreplacestring);
Node* const replace_value_map = a.LoadMap(replace_value); Node* const replace_value_map = LoadMap(replace_value);
a.Branch(a.IsCallableMap(replace_value_map), &if_iscallable, Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring);
&checkreplacestring);
// 3. Does ToString({replace_value}) contain '$'? // 3. Does ToString({replace_value}) contain '$'?
a.Bind(&checkreplacestring); Bind(&checkreplacestring);
{ {
Node* const replace_string = Node* const replace_string =
a.CallStub(tostring_callable, context, replace_value); CallStub(tostring_callable, context, replace_value);
Node* const dollar_char = a.IntPtrConstant('$'); Node* const dollar_char = IntPtrConstant('$');
Node* const smi_minusone = a.SmiConstant(Smi::FromInt(-1)); Node* const smi_minusone = SmiConstant(Smi::FromInt(-1));
a.GotoUnless(a.SmiEqual(a.StringIndexOfChar(context, replace_string, GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char,
dollar_char, int_zero), int_zero),
smi_minusone), smi_minusone),
&runtime); &runtime);
a.Return(ReplaceSimpleStringFastPath(&a, context, regexp, string, Return(ReplaceSimpleStringFastPath(this, context, regexp, string,
replace_string)); replace_string));
} }
// {regexp} is unmodified and {replace_value} is callable. // {regexp} is unmodified and {replace_value} is callable.
a.Bind(&if_iscallable); Bind(&if_iscallable);
{ {
Node* const replace_callable = replace_value; Node* const replace_callable = replace_value;
// Check if the {regexp} is global. // Check if the {regexp} is global.
CLabel if_isglobal(&a), if_isnotglobal(&a); CLabel if_isglobal(this), if_isnotglobal(this);
Node* const is_global = FastFlagGetter(&a, regexp, JSRegExp::kGlobal); Node* const is_global = FastFlagGetter(this, regexp, JSRegExp::kGlobal);
a.Branch(is_global, &if_isglobal, &if_isnotglobal); Branch(is_global, &if_isglobal, &if_isnotglobal);
a.Bind(&if_isglobal); Bind(&if_isglobal);
{ {
Node* const result = ReplaceGlobalCallableFastPath( Node* const result = ReplaceGlobalCallableFastPath(
&a, context, regexp, string, replace_callable); this, context, regexp, string, replace_callable);
a.Return(result); Return(result);
} }
a.Bind(&if_isnotglobal); Bind(&if_isnotglobal);
{ {
Node* const result = Node* const result =
a.CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
context, string, regexp, replace_callable); context, string, regexp, replace_callable);
a.Return(result); Return(result);
} }
} }
a.Bind(&runtime); Bind(&runtime);
{ {
Node* const result = a.CallRuntime(Runtime::kRegExpReplace, context, Node* const result = CallRuntime(Runtime::kRegExpReplace, context, receiver,
receiver, string, replace_value); string, replace_value);
a.Return(result); Return(result);
} }
} }
// 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.
void Builtins::Generate_RegExpInternalMatch(CodeAssemblerState* state) { TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
CodeStubAssembler a(state); Isolate* const isolate = this->isolate();
Isolate* const isolate = a.isolate();
Node* const regexp = a.Parameter(1); Node* const regexp = Parameter(1);
Node* const string = a.Parameter(2); Node* const string = Parameter(2);
Node* const context = a.Parameter(5); Node* const context = Parameter(5);
Node* const null = a.NullConstant(); Node* const null = NullConstant();
Node* const smi_zero = a.SmiConstant(Smi::FromInt(0)); Node* const smi_zero = SmiConstant(Smi::FromInt(0));
Node* const native_context = a.LoadNativeContext(context); Node* const native_context = LoadNativeContext(context);
Node* const internal_match_info = a.LoadContextElement( Node* const internal_match_info = LoadContextElement(
native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX);
Callable exec_callable = CodeFactory::RegExpExec(isolate); Callable exec_callable = CodeFactory::RegExpExec(isolate);
Node* const match_indices = a.CallStub(exec_callable, context, regexp, string, Node* const match_indices = CallStub(exec_callable, context, regexp, string,
smi_zero, internal_match_info); smi_zero, internal_match_info);
CLabel if_matched(&a), if_didnotmatch(&a); CLabel if_matched(this), if_didnotmatch(this);
a.Branch(a.WordEqual(match_indices, null), &if_didnotmatch, &if_matched); Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
a.Bind(&if_didnotmatch); Bind(&if_didnotmatch);
a.Return(null); Return(null);
a.Bind(&if_matched); Bind(&if_matched);
{ {
Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, Node* result = ConstructNewResultFromMatchInfo(isolate, this, context,
match_indices, string); match_indices, string);
a.Return(result); Return(result);
} }
} }
......
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