[regexp] Move RegExp.prototype.test to TF
This results in a speedup of around 2x. RegExpExec is also ported in this CL. BUG=v8:5339 Review-Url: https://codereview.chromium.org/2441993002 Cr-Commit-Position: refs/heads/master@{#40532}
This commit is contained in:
parent
65e68c66af
commit
ae3357d216
@ -1809,8 +1809,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
|
||||
{
|
||||
Handle<JSFunction> fun = SimpleInstallFunction(
|
||||
prototype, "exec", Builtins::kRegExpPrototypeExec, 1, true,
|
||||
DONT_ENUM);
|
||||
prototype, factory->exec_string(), Builtins::kRegExpPrototypeExec,
|
||||
1, true, DONT_ENUM);
|
||||
native_context()->set_regexp_exec_function(*fun);
|
||||
}
|
||||
|
||||
@ -1836,7 +1836,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Builtins::kRegExpPrototypeToString, 0, false,
|
||||
DONT_ENUM);
|
||||
SimpleInstallFunction(prototype, "test", Builtins::kRegExpPrototypeTest,
|
||||
1, false, DONT_ENUM);
|
||||
1, true, DONT_ENUM);
|
||||
|
||||
{
|
||||
Handle<JSFunction> fun = SimpleCreateFunction(
|
||||
|
@ -969,25 +969,106 @@ BUILTIN(RegExpRightContextGetter) {
|
||||
return *isolate->factory()->NewSubString(last_subject, start_index, len);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
|
||||
compiler::Node* RegExpExec(CodeStubAssembler* a, compiler::Node* context,
|
||||
compiler::Node* recv, compiler::Node* string) {
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Isolate* isolate = a->isolate();
|
||||
|
||||
Node* const null = a->NullConstant();
|
||||
|
||||
Variable var_result(a, MachineRepresentation::kTagged);
|
||||
Label out(a), call_builtin_exec(a), slow_path(a, Label::kDeferred);
|
||||
|
||||
Node* const map = a->LoadMap(recv);
|
||||
BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path);
|
||||
|
||||
a->Bind(&call_builtin_exec);
|
||||
{
|
||||
Node* const result = RegExpPrototypeExecInternal(a, context, recv, string);
|
||||
var_result.Bind(result);
|
||||
a->Goto(&out);
|
||||
}
|
||||
|
||||
a->Bind(&slow_path);
|
||||
{
|
||||
// Take the slow path of fetching the exec property, calling it, and
|
||||
// verifying its return value.
|
||||
|
||||
// Get the exec property.
|
||||
Node* const name = a->HeapConstant(isolate->factory()->exec_string());
|
||||
Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
||||
Node* const exec = a->CallStub(getproperty_callable, context, recv, name);
|
||||
|
||||
// Is {exec} callable?
|
||||
Label if_iscallable(a), if_isnotcallable(a);
|
||||
|
||||
a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable);
|
||||
|
||||
Node* const exec_map = a->LoadMap(exec);
|
||||
a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable);
|
||||
|
||||
a->Bind(&if_iscallable);
|
||||
{
|
||||
Callable call_callable = CodeFactory::Call(isolate);
|
||||
Node* const result =
|
||||
a->CallJS(call_callable, context, exec, recv, string);
|
||||
|
||||
var_result.Bind(result);
|
||||
a->GotoIf(a->WordEqual(result, null), &out);
|
||||
|
||||
ThrowIfNotJSReceiver(a, isolate, context, result,
|
||||
MessageTemplate::kInvalidRegExpExecResult, "unused");
|
||||
|
||||
a->Goto(&out);
|
||||
}
|
||||
|
||||
a->Bind(&if_isnotcallable);
|
||||
{
|
||||
a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE,
|
||||
"RegExp.prototype.exec");
|
||||
a->Goto(&call_builtin_exec);
|
||||
}
|
||||
}
|
||||
|
||||
a->Bind(&out);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ES#sec-regexp.prototype.test
|
||||
// RegExp.prototype.test ( S )
|
||||
BUILTIN(RegExpPrototypeTest) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.test");
|
||||
void Builtins::Generate_RegExpPrototypeTest(CodeStubAssembler* a) {
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
|
||||
Isolate* const isolate = a->isolate();
|
||||
|
||||
Handle<String> string;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
|
||||
Object::ToString(isolate, string_obj));
|
||||
Node* const maybe_receiver = a->Parameter(0);
|
||||
Node* const maybe_string = a->Parameter(1);
|
||||
Node* const context = a->Parameter(4);
|
||||
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
RegExpUtils::RegExpExec(isolate, recv, string,
|
||||
isolate->factory()->undefined_value()));
|
||||
// Ensure {maybe_receiver} is a JSReceiver.
|
||||
ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
|
||||
MessageTemplate::kIncompatibleMethodReceiver,
|
||||
"RegExp.prototype.test");
|
||||
Node* const receiver = maybe_receiver;
|
||||
|
||||
return isolate->heap()->ToBoolean(!result->IsNull(isolate));
|
||||
// Convert {maybe_string} to a String.
|
||||
Node* const string = a->ToString(context, maybe_string);
|
||||
|
||||
// Call exec.
|
||||
Node* const match_indices = RegExpExec(a, context, receiver, string);
|
||||
|
||||
// Return true iff exec matched successfully.
|
||||
Node* const result = a->Select(a->WordEqual(match_indices, a->NullConstant()),
|
||||
a->FalseConstant(), a->TrueConstant());
|
||||
a->Return(result);
|
||||
}
|
||||
|
||||
// ES#sec-regexp.prototype-@@match
|
||||
@ -1820,7 +1901,7 @@ void Builtins::Generate_RegExpPrototypeReplace(CodeStubAssembler* a) {
|
||||
|
||||
Node* const int_zero = a->IntPtrConstant(0);
|
||||
|
||||
// Ensure {receiver} is a JSReceiver.
|
||||
// Ensure {maybe_receiver} is a JSReceiver.
|
||||
Node* const map =
|
||||
ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
|
||||
MessageTemplate::kIncompatibleMethodReceiver,
|
||||
|
@ -606,7 +606,7 @@ namespace internal {
|
||||
CPP(RegExpPrototypeSpeciesGetter) \
|
||||
CPP(RegExpPrototypeSplit) \
|
||||
TFJ(RegExpPrototypeStickyGetter, 0) \
|
||||
CPP(RegExpPrototypeTest) \
|
||||
TFJ(RegExpPrototypeTest, 1) \
|
||||
CPP(RegExpPrototypeToString) \
|
||||
TFJ(RegExpPrototypeUnicodeGetter, 0) \
|
||||
CPP(RegExpRightContextGetter) \
|
||||
|
@ -59,6 +59,7 @@
|
||||
V(done_string, "done") \
|
||||
V(dot_result_string, ".result") \
|
||||
V(dot_string, ".") \
|
||||
V(exec_string, "exec") \
|
||||
V(entries_string, "entries") \
|
||||
V(enqueue_string, "enqueue") \
|
||||
V(enumerable_string, "enumerable") \
|
||||
|
@ -72,9 +72,7 @@ MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate,
|
||||
if (exec->IsUndefined(isolate)) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, exec,
|
||||
Object::GetProperty(
|
||||
regexp, isolate->factory()->NewStringFromAsciiChecked("exec")),
|
||||
Object);
|
||||
Object::GetProperty(regexp, isolate->factory()->exec_string()), Object);
|
||||
}
|
||||
|
||||
if (exec->IsCallable()) {
|
||||
|
@ -221,9 +221,6 @@
|
||||
'harmony/async-debug-caught-exception-cases2': [SKIP],
|
||||
'harmony/async-debug-caught-exception-cases3': [SKIP],
|
||||
|
||||
# TODO(jgruber): Too slow with new C++ port. Reenable once fixed.
|
||||
'harmony/regexp-property-lu-ui': [SKIP],
|
||||
|
||||
# TODO(mstarzinger): Takes too long with TF.
|
||||
'array-sort': [PASS, NO_VARIANTS],
|
||||
'regress/regress-91008': [PASS, NO_VARIANTS],
|
||||
|
Loading…
Reference in New Issue
Block a user