Index: src/builtins/builtins-regexp.cc |
diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc |
index 2b103d2c60f2ce6e507d3de987878735b3aeaf1d..d993e82f2eae7ee0a2545f712ae43f22b0810db6 100644 |
--- a/src/builtins/builtins-regexp.cc |
+++ b/src/builtins/builtins-regexp.cc |
@@ -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, |