summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/builtins-regexp-gen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/builtins-regexp-gen.cc')
-rw-r--r--deps/v8/src/builtins/builtins-regexp-gen.cc214
1 files changed, 147 insertions, 67 deletions
diff --git a/deps/v8/src/builtins/builtins-regexp-gen.cc b/deps/v8/src/builtins/builtins-regexp-gen.cc
index f1169c0b94..04a35bd000 100644
--- a/deps/v8/src/builtins/builtins-regexp-gen.cc
+++ b/deps/v8/src/builtins/builtins-regexp-gen.cc
@@ -231,11 +231,11 @@ void RegExpBuiltinsAssembler::GetStringPointers(
var_string_end->Bind(IntPtrAdd(string_data, to_offset));
}
-Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context,
- Node* const regexp,
- Node* const string,
- Node* const last_index,
- Node* const match_info) {
+Node* RegExpBuiltinsAssembler::RegExpExecInternal(Node* const context,
+ Node* const regexp,
+ Node* const string,
+ Node* const last_index,
+ Node* const match_info) {
// Just jump directly to runtime if native RegExp is not selected at compile
// time or if regexp entry in generated code is turned off runtime switch or
// at compilation.
@@ -260,12 +260,14 @@ Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context,
Label out(this), runtime(this, Label::kDeferred);
// External constants.
+ Node* const isolate_address =
+ ExternalConstant(ExternalReference::isolate_address(isolate()));
+ Node* const regexp_stack_memory_address_address = ExternalConstant(
+ ExternalReference::address_of_regexp_stack_memory_address(isolate()));
Node* const regexp_stack_memory_size_address = ExternalConstant(
ExternalReference::address_of_regexp_stack_memory_size(isolate()));
Node* const static_offsets_vector_address = ExternalConstant(
ExternalReference::address_of_static_offsets_vector(isolate()));
- Node* const pending_exception_address = ExternalConstant(
- ExternalReference(Isolate::kPendingExceptionAddress, isolate()));
// Ensure that a RegExp stack is allocated.
{
@@ -304,9 +306,16 @@ Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context,
Node* const smi_string_length = LoadStringLength(string);
- // Bail out to runtime for invalid {last_index} values.
- GotoIfNot(TaggedIsSmi(last_index), &runtime);
- GotoIf(SmiAboveOrEqual(last_index, smi_string_length), &runtime);
+ // At this point, last_index is definitely a canonicalized non-negative
+ // number, which implies that any non-Smi last_index is greater than
+ // the maximal string length. If lastIndex > string.length then the matcher
+ // must fail.
+
+ Label if_failure(this);
+ CSA_ASSERT(this, IsNumberNormalized(last_index));
+ CSA_ASSERT(this, IsNumberPositive(last_index));
+ GotoIfNot(TaggedIsSmi(last_index), &if_failure); // Outside Smi range.
+ GotoIf(SmiGreaterThan(last_index, smi_string_length), &if_failure);
// Load the irregexp code object and offsets into the subject string. Both
// depend on whether the string is one- or two-byte.
@@ -356,27 +365,89 @@ Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context,
GotoIf(TaggedIsSmi(code), &runtime);
CSA_ASSERT(this, HasInstanceType(code, CODE_TYPE));
- Label if_success(this), if_failure(this),
- if_exception(this, Label::kDeferred);
+ Label if_success(this), if_exception(this, Label::kDeferred);
{
IncrementCounter(isolate()->counters()->regexp_entry_native(), 1);
- Callable exec_callable = CodeFactory::RegExpExec(isolate());
- Node* const result = CallStub(
- exec_callable, context, string, TruncateWordToWord32(int_last_index),
- var_string_start.value(), var_string_end.value(), code);
+ // Set up args for the final call into generated Irregexp code.
+
+ MachineType type_int32 = MachineType::Int32();
+ MachineType type_tagged = MachineType::AnyTagged();
+ MachineType type_ptr = MachineType::Pointer();
+
+ // Result: A NativeRegExpMacroAssembler::Result return code.
+ MachineType retval_type = type_int32;
+
+ // Argument 0: Original subject string.
+ MachineType arg0_type = type_tagged;
+ Node* const arg0 = string;
+
+ // Argument 1: Previous index.
+ MachineType arg1_type = type_int32;
+ Node* const arg1 = TruncateWordToWord32(int_last_index);
+
+ // Argument 2: Start of string data.
+ MachineType arg2_type = type_ptr;
+ Node* const arg2 = var_string_start.value();
+
+ // Argument 3: End of string data.
+ MachineType arg3_type = type_ptr;
+ Node* const arg3 = var_string_end.value();
+
+ // Argument 4: static offsets vector buffer.
+ MachineType arg4_type = type_ptr;
+ Node* const arg4 = static_offsets_vector_address;
+
+ // Argument 5: Set the number of capture registers to zero to force global
+ // regexps to behave as non-global. This does not affect non-global
+ // regexps.
+ MachineType arg5_type = type_int32;
+ Node* const arg5 = Int32Constant(0);
+
+ // Argument 6: Start (high end) of backtracking stack memory area.
+ Node* const stack_start =
+ Load(MachineType::Pointer(), regexp_stack_memory_address_address);
+ Node* const stack_size =
+ Load(MachineType::IntPtr(), regexp_stack_memory_size_address);
+ Node* const stack_end = IntPtrAdd(stack_start, stack_size);
+
+ MachineType arg6_type = type_ptr;
+ Node* const arg6 = stack_end;
+
+ // Argument 7: Indicate that this is a direct call from JavaScript.
+ MachineType arg7_type = type_int32;
+ Node* const arg7 = Int32Constant(1);
+
+ // Argument 8: Pass current isolate address.
+ MachineType arg8_type = type_ptr;
+ Node* const arg8 = isolate_address;
+
+ Node* const code_entry =
+ IntPtrAdd(BitcastTaggedToWord(code),
+ IntPtrConstant(Code::kHeaderSize - kHeapObjectTag));
+
+ Node* const result = CallCFunction9(
+ retval_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ arg5_type, arg6_type, arg7_type, arg8_type, code_entry, arg0, arg1,
+ arg2, arg3, arg4, arg5, arg6, arg7, arg8);
// Check the result.
- // We expect exactly one result since the stub forces the called regexp to
- // behave as non-global.
- GotoIf(SmiEqual(result, SmiConstant(1)), &if_success);
- GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::FAILURE)),
+ // We expect exactly one result since we force the called regexp to behave
+ // as non-global.
+ Node* const int_result = ChangeInt32ToIntPtr(result);
+ GotoIf(IntPtrEqual(int_result,
+ IntPtrConstant(NativeRegExpMacroAssembler::SUCCESS)),
+ &if_success);
+ GotoIf(IntPtrEqual(int_result,
+ IntPtrConstant(NativeRegExpMacroAssembler::FAILURE)),
&if_failure);
- GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::EXCEPTION)),
+ GotoIf(IntPtrEqual(int_result,
+ IntPtrConstant(NativeRegExpMacroAssembler::EXCEPTION)),
&if_exception);
- CSA_ASSERT(
- this, SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::RETRY)));
+ CSA_ASSERT(this,
+ IntPtrEqual(int_result,
+ IntPtrConstant(NativeRegExpMacroAssembler::RETRY)));
Goto(&runtime);
}
@@ -440,22 +511,15 @@ Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context,
BIND(&if_exception);
{
- Node* const pending_exception =
- Load(MachineType::AnyTagged(), pending_exception_address);
-
- // If there is no pending exception, a
- // stack overflow (on the backtrack stack) was detected in RegExp code.
-
- Label stack_overflow(this), rethrow(this);
- Branch(IsTheHole(pending_exception), &stack_overflow, &rethrow);
-
- BIND(&stack_overflow);
+// A stack overflow was detected in RegExp code.
+#ifdef DEBUG
+ Node* const pending_exception_address = ExternalConstant(
+ ExternalReference(Isolate::kPendingExceptionAddress, isolate()));
+ CSA_ASSERT(this, IsTheHole(Load(MachineType::AnyTagged(),
+ pending_exception_address)));
+#endif // DEBUG
CallRuntime(Runtime::kThrowStackOverflow, context);
Unreachable();
-
- BIND(&rethrow);
- CallRuntime(Runtime::kRegExpExecReThrow, context);
- Unreachable();
}
BIND(&runtime);
@@ -513,8 +577,7 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
BIND(&call_tolength);
{
- var_lastindex.Bind(
- CallBuiltin(Builtins::kToLength, context, regexp_lastindex));
+ var_lastindex.Bind(ToLength_Inline(context, regexp_lastindex));
Goto(&next);
}
@@ -571,8 +634,8 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
// Call the exec stub.
- match_indices = IrregexpExec(context, regexp, string, var_lastindex.value(),
- last_match_info);
+ match_indices = RegExpExecInternal(context, regexp, string,
+ var_lastindex.value(), last_match_info);
var_result.Bind(match_indices);
// {match_indices} is either null or the RegExpMatchInfo array.
@@ -1877,7 +1940,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
if (is_fastpath) {
CSA_ASSERT(this, TaggedIsPositiveSmi(last_index));
} else {
- last_index = CallBuiltin(Builtins::kToLength, context, last_index);
+ last_index = ToLength_Inline(context, last_index);
}
Node* const new_last_index =
@@ -2104,8 +2167,8 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
Node* const last_match_info = LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
- Node* const match_indices =
- IrregexpExec(context, regexp, string, smi_zero, last_match_info);
+ Node* const match_indices = RegExpExecInternal(context, regexp, string,
+ smi_zero, last_match_info);
Label return_singleton_array(this);
Branch(WordEqual(match_indices, null), &return_singleton_array,
@@ -2166,8 +2229,8 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
Node* const last_match_info = LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
- Node* const match_indices = IrregexpExec(context, regexp, string,
- next_search_from, last_match_info);
+ Node* const match_indices = RegExpExecInternal(
+ context, regexp, string, next_search_from, last_match_info);
// We're done if no match was found.
{
@@ -2373,10 +2436,19 @@ TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) {
// ES#sec-regexp.prototype-@@split
// RegExp.prototype [ @@split ] ( string, limit )
TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
- Node* const maybe_receiver = Parameter(Descriptor::kReceiver);
- Node* const maybe_string = Parameter(Descriptor::kString);
- Node* const maybe_limit = Parameter(Descriptor::kLimit);
- Node* const context = Parameter(Descriptor::kContext);
+ const int kStringArg = 0;
+ const int kLimitArg = 1;
+
+ Node* argc =
+ ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
+ CodeStubArguments args(this, argc);
+
+ Node* const maybe_receiver = args.GetReceiver();
+ Node* const maybe_string =
+ args.GetOptionalArgumentValue(kStringArg, UndefinedConstant());
+ Node* const maybe_limit =
+ args.GetOptionalArgumentValue(kLimitArg, UndefinedConstant());
+ Node* const context = Parameter(BuiltinDescriptor::kContext);
// Ensure {maybe_receiver} is a JSReceiver.
ThrowIfNotJSReceiver(context, maybe_receiver,
@@ -2391,12 +2463,12 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
BranchIfFastRegExp(context, receiver, &stub, &runtime);
BIND(&stub);
- Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string,
- maybe_limit));
+ args.PopAndReturn(CallBuiltin(Builtins::kRegExpSplit, context, receiver,
+ string, maybe_limit));
BIND(&runtime);
- Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string,
- maybe_limit));
+ args.PopAndReturn(CallRuntime(Runtime::kRegExpSplit, context, receiver,
+ string, maybe_limit));
}
Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
@@ -2736,8 +2808,7 @@ TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
// 3. Does ToString({replace_value}) contain '$'?
BIND(&checkreplacestring);
{
- Node* const replace_string =
- CallBuiltin(Builtins::kToString, context, replace_value);
+ Node* const replace_string = ToString_Inline(context, replace_value);
// ToString(replaceValue) could potentially change the shape of the RegExp
// object. Recheck that we are still on the fast path and bail to runtime
@@ -2786,10 +2857,19 @@ TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
// ES#sec-regexp.prototype-@@replace
// RegExp.prototype [ @@replace ] ( string, replaceValue )
TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
- Node* const maybe_receiver = Parameter(Descriptor::kReceiver);
- Node* const maybe_string = Parameter(Descriptor::kString);
- Node* const replace_value = Parameter(Descriptor::kReplaceValue);
- Node* const context = Parameter(Descriptor::kContext);
+ const int kStringArg = 0;
+ const int kReplaceValueArg = 1;
+
+ Node* argc =
+ ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
+ CodeStubArguments args(this, argc);
+
+ Node* const maybe_receiver = args.GetReceiver();
+ Node* const maybe_string =
+ args.GetOptionalArgumentValue(kStringArg, UndefinedConstant());
+ Node* const replace_value =
+ args.GetOptionalArgumentValue(kReplaceValueArg, UndefinedConstant());
+ Node* const context = Parameter(BuiltinDescriptor::kContext);
// RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic:
//
@@ -2816,19 +2896,19 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String.
- Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string);
+ Node* const string = ToString_Inline(context, maybe_string);
// Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
Label stub(this), runtime(this, Label::kDeferred);
BranchIfFastRegExp(context, receiver, &stub, &runtime);
BIND(&stub);
- Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string,
- replace_value));
+ args.PopAndReturn(CallBuiltin(Builtins::kRegExpReplace, context, receiver,
+ string, replace_value));
BIND(&runtime);
- Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string,
- replace_value));
+ args.PopAndReturn(CallRuntime(Runtime::kRegExpReplace, context, receiver,
+ string, replace_value));
}
// Simple string matching functionality for internal use which does not modify
@@ -2848,8 +2928,8 @@ TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
Node* const internal_match_info = LoadContextElement(
native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX);
- Node* const match_indices =
- IrregexpExec(context, regexp, string, smi_zero, internal_match_info);
+ Node* const match_indices = RegExpExecInternal(context, regexp, string,
+ smi_zero, internal_match_info);
Label if_matched(this), if_didnotmatch(this);
Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);