| Index: src/builtins/builtins-regexp.cc
|
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
|
| index de2528dc59bfa21c65ba924ae91c64828ad9e7bc..5f8d18be433e7ce0957c62c05eb3b5e7fcc4723f 100644
|
| --- a/src/builtins/builtins-regexp.cc
|
| +++ b/src/builtins/builtins-regexp.cc
|
| @@ -170,34 +170,45 @@ BUILTIN(RegExpPrototypeCompile) {
|
|
|
| namespace {
|
|
|
| +compiler::Node* FastLoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| + compiler::Node* regexp) {
|
| + // Load the in-object field.
|
| + static const int field_offset =
|
| + JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
|
| + return a->LoadObjectField(regexp, field_offset);
|
| +}
|
| +
|
| +compiler::Node* SlowLoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| + compiler::Node* regexp) {
|
| + // Load through the GetProperty stub.
|
| + typedef compiler::Node Node;
|
| +
|
| + Node* const name =
|
| + a->HeapConstant(a->isolate()->factory()->lastIndex_string());
|
| + Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
| + return a->CallStub(getproperty_callable, context, regexp, name);
|
| +}
|
| +
|
| compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| compiler::Node* has_initialmap,
|
| compiler::Node* regexp) {
|
| typedef CodeStubAssembler::Variable Variable;
|
| typedef CodeStubAssembler::Label Label;
|
| - typedef compiler::Node Node;
|
|
|
| Variable var_value(a, MachineRepresentation::kTagged);
|
|
|
| - Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred);
|
| + Label out(a), if_unmodified(a), if_modified(a);
|
| a->Branch(has_initialmap, &if_unmodified, &if_modified);
|
|
|
| a->Bind(&if_unmodified);
|
| {
|
| - // Load the in-object field.
|
| - static const int field_offset =
|
| - JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
|
| - var_value.Bind(a->LoadObjectField(regexp, field_offset));
|
| + var_value.Bind(FastLoadLastIndex(a, context, regexp));
|
| a->Goto(&out);
|
| }
|
|
|
| a->Bind(&if_modified);
|
| {
|
| - // Load through the GetProperty stub.
|
| - Node* const name =
|
| - a->HeapConstant(a->isolate()->factory()->lastIndex_string());
|
| - Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
| - var_value.Bind(a->CallStub(getproperty_callable, context, regexp, name));
|
| + var_value.Bind(SlowLoadLastIndex(a, context, regexp));
|
| a->Goto(&out);
|
| }
|
|
|
| @@ -215,13 +226,25 @@ void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| a->StoreObjectField(regexp, field_offset, value);
|
| }
|
|
|
| +void SlowStoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| + compiler::Node* regexp, compiler::Node* value) {
|
| + // Store through runtime.
|
| + // TODO(ishell): Use SetPropertyStub here once available.
|
| + typedef compiler::Node Node;
|
| +
|
| + Node* const name =
|
| + a->HeapConstant(a->isolate()->factory()->lastIndex_string());
|
| + Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
|
| + a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
|
| + language_mode);
|
| +}
|
| +
|
| void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
| compiler::Node* has_initialmap, compiler::Node* regexp,
|
| compiler::Node* value) {
|
| typedef CodeStubAssembler::Label Label;
|
| - typedef compiler::Node Node;
|
|
|
| - Label out(a), if_unmodified(a), if_modified(a, Label::kDeferred);
|
| + Label out(a), if_unmodified(a), if_modified(a);
|
| a->Branch(has_initialmap, &if_unmodified, &if_modified);
|
|
|
| a->Bind(&if_unmodified);
|
| @@ -232,13 +255,7 @@ void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
|
|
| a->Bind(&if_modified);
|
| {
|
| - // Store through runtime.
|
| - // TODO(ishell): Use SetPropertyStub here once available.
|
| - Node* const name =
|
| - a->HeapConstant(a->isolate()->factory()->lastIndex_string());
|
| - Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
|
| - a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
|
| - language_mode);
|
| + SlowStoreLastIndex(a, context, regexp, value);
|
| a->Goto(&out);
|
| }
|
|
|
| @@ -1142,57 +1159,128 @@ BUILTIN(RegExpPrototypeMatch) {
|
| return *isolate->factory()->NewJSArrayWithElements(elems);
|
| }
|
|
|
| -// ES#sec-regexp.prototype-@@search
|
| -// RegExp.prototype [ @@search ] ( string )
|
| -BUILTIN(RegExpPrototypeSearch) {
|
| - HandleScope scope(isolate);
|
| - CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@search");
|
| +namespace {
|
|
|
| - Handle<Object> string_obj = args.atOrUndefined(isolate, 1);
|
| +void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a,
|
| + compiler::Node* const receiver,
|
| + compiler::Node* const string,
|
| + compiler::Node* const context,
|
| + bool is_fastpath) {
|
| + typedef CodeStubAssembler::Label Label;
|
| + typedef compiler::Node Node;
|
|
|
| - Handle<String> string;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
|
| - Object::ToString(isolate, string_obj));
|
| + Isolate* const isolate = a->isolate();
|
| +
|
| + Node* const smi_zero = a->SmiConstant(Smi::kZero);
|
|
|
| - Handle<Object> previous_last_index_obj;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, previous_last_index_obj,
|
| - RegExpUtils::GetLastIndex(isolate, recv));
|
| + // Grab the initial value of last index.
|
| + Node* const previous_last_index =
|
| + is_fastpath ? FastLoadLastIndex(a, context, receiver)
|
| + : SlowLoadLastIndex(a, context, receiver);
|
|
|
| - if (!previous_last_index_obj->SameValue(Smi::kZero)) {
|
| - RETURN_FAILURE_ON_EXCEPTION(isolate,
|
| - RegExpUtils::SetLastIndex(isolate, recv, 0));
|
| + // Ensure last index is 0.
|
| + if (is_fastpath) {
|
| + FastStoreLastIndex(a, context, receiver, smi_zero);
|
| + } else {
|
| + Label next(a);
|
| + a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next);
|
| +
|
| + SlowStoreLastIndex(a, context, receiver, smi_zero);
|
| + a->Goto(&next);
|
| + a->Bind(&next);
|
| }
|
|
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - RegExpUtils::RegExpExec(isolate, recv, string,
|
| - isolate->factory()->undefined_value()));
|
| -
|
| - Handle<Object> current_last_index_obj;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, current_last_index_obj,
|
| - RegExpUtils::GetLastIndex(isolate, recv));
|
| -
|
| - const bool is_last_index_unchanged =
|
| - current_last_index_obj->SameValue(*previous_last_index_obj);
|
| - if (!is_last_index_unchanged) {
|
| - if (previous_last_index_obj->IsSmi()) {
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate,
|
| - RegExpUtils::SetLastIndex(
|
| - isolate, recv, Smi::cast(*previous_last_index_obj)->value()));
|
| - } else {
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate,
|
| - Object::SetProperty(recv, isolate->factory()->lastIndex_string(),
|
| - previous_last_index_obj, STRICT));
|
| + // Call exec.
|
| + Node* const match_indices =
|
| + is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string)
|
| + : RegExpExec(a, context, receiver, string);
|
| +
|
| + // Reset last index if necessary.
|
| + if (is_fastpath) {
|
| + FastStoreLastIndex(a, context, receiver, previous_last_index);
|
| + } else {
|
| + Label next(a);
|
| + Node* const current_last_index = SlowLoadLastIndex(a, context, receiver);
|
| +
|
| + a->GotoIf(a->SameValue(current_last_index, previous_last_index, context),
|
| + &next);
|
| +
|
| + SlowStoreLastIndex(a, context, receiver, previous_last_index);
|
| + a->Goto(&next);
|
| + a->Bind(&next);
|
| + }
|
| +
|
| + // Return -1 if no match was found.
|
| + {
|
| + Label next(a);
|
| + a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next);
|
| + a->Return(a->SmiConstant(-1));
|
| + a->Bind(&next);
|
| + }
|
| +
|
| + // Return the index of the match.
|
| + {
|
| + Label fast_result(a), slow_result(a, Label::kDeferred);
|
| +
|
| + Node* const native_context = a->LoadNativeContext(context);
|
| + Node* const initial_regexp_result_map =
|
| + a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
|
| + Node* const match_indices_map = a->LoadMap(match_indices);
|
| +
|
| + a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map),
|
| + &fast_result, &slow_result);
|
| +
|
| + a->Bind(&fast_result);
|
| + {
|
| + Node* const index =
|
| + a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset,
|
| + MachineType::AnyTagged());
|
| + a->Return(index);
|
| + }
|
| +
|
| + a->Bind(&slow_result);
|
| + {
|
| + Node* const name = a->HeapConstant(isolate->factory()->index_string());
|
| + Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
| + Node* const index =
|
| + a->CallStub(getproperty_callable, context, match_indices, name);
|
| + a->Return(index);
|
| }
|
| }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// ES#sec-regexp.prototype-@@search
|
| +// RegExp.prototype [ @@search ] ( string )
|
| +void Builtins::Generate_RegExpPrototypeSearch(CodeStubAssembler* a) {
|
| + typedef CodeStubAssembler::Label Label;
|
| + typedef compiler::Node Node;
|
|
|
| - if (result->IsNull(isolate)) return Smi::FromInt(-1);
|
| + Isolate* const isolate = a->isolate();
|
| +
|
| + Node* const maybe_receiver = a->Parameter(0);
|
| + Node* const maybe_string = a->Parameter(1);
|
| + Node* const context = a->Parameter(4);
|
|
|
| - RETURN_RESULT_OR_FAILURE(
|
| - isolate, Object::GetProperty(result, isolate->factory()->index_string()));
|
| + // Ensure {maybe_receiver} is a JSReceiver.
|
| + Node* const map =
|
| + ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
|
| + MessageTemplate::kIncompatibleMethodReceiver,
|
| + "RegExp.prototype.@@search");
|
| + Node* const receiver = maybe_receiver;
|
| +
|
| + // Convert {maybe_string} to a String.
|
| + Node* const string = a->ToString(context, maybe_string);
|
| +
|
| + Label fast_path(a), slow_path(a);
|
| + BranchIfFastPath(a, context, map, &fast_path, &slow_path);
|
| +
|
| + a->Bind(&fast_path);
|
| + Generate_RegExpPrototypeSearchBody(a, receiver, string, context, true);
|
| +
|
| + a->Bind(&slow_path);
|
| + Generate_RegExpPrototypeSearchBody(a, receiver, string, context, false);
|
| }
|
|
|
| namespace {
|
|
|