| Index: src/builtins/builtins-regexp.cc
|
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
|
| index 7edf93b19d124ca28f70758800585c679d259703..abf6a190d3c69f04478b25f88766a0fe85b72ba7 100644
|
| --- a/src/builtins/builtins-regexp.cc
|
| +++ b/src/builtins/builtins-regexp.cc
|
| @@ -24,158 +24,6 @@ typedef compiler::CodeAssemblerState CodeAssemblerState;
|
|
|
| namespace {
|
|
|
| -Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) {
|
| - static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0';
|
| - char flags_string[kMaxFlagsLength];
|
| - int i = 0;
|
| -
|
| - const JSRegExp::Flags flags = regexp->GetFlags();
|
| -
|
| - if ((flags & JSRegExp::kGlobal) != 0) flags_string[i++] = 'g';
|
| - if ((flags & JSRegExp::kIgnoreCase) != 0) flags_string[i++] = 'i';
|
| - if ((flags & JSRegExp::kMultiline) != 0) flags_string[i++] = 'm';
|
| - if ((flags & JSRegExp::kUnicode) != 0) flags_string[i++] = 'u';
|
| - if ((flags & JSRegExp::kSticky) != 0) flags_string[i++] = 'y';
|
| -
|
| - DCHECK_LT(i, kMaxFlagsLength);
|
| - memset(&flags_string[i], '\0', kMaxFlagsLength - i);
|
| -
|
| - return isolate->factory()->NewStringFromAsciiChecked(flags_string);
|
| -}
|
| -
|
| -// ES#sec-regexpinitialize
|
| -// Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
|
| -MUST_USE_RESULT MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate,
|
| - Handle<JSRegExp> regexp,
|
| - Handle<Object> pattern,
|
| - Handle<Object> flags) {
|
| - Handle<String> pattern_string;
|
| - if (pattern->IsUndefined(isolate)) {
|
| - pattern_string = isolate->factory()->empty_string();
|
| - } else {
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string,
|
| - Object::ToString(isolate, pattern), JSRegExp);
|
| - }
|
| -
|
| - Handle<String> flags_string;
|
| - if (flags->IsUndefined(isolate)) {
|
| - flags_string = isolate->factory()->empty_string();
|
| - } else {
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string,
|
| - Object::ToString(isolate, flags), JSRegExp);
|
| - }
|
| -
|
| - // TODO(jgruber): We could avoid the flags back and forth conversions.
|
| - return JSRegExp::Initialize(regexp, pattern_string, flags_string);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// ES#sec-regexp-pattern-flags
|
| -// RegExp ( pattern, flags )
|
| -BUILTIN(RegExpConstructor) {
|
| - HandleScope scope(isolate);
|
| -
|
| - Handle<HeapObject> new_target = args.new_target();
|
| - Handle<Object> pattern = args.atOrUndefined(isolate, 1);
|
| - Handle<Object> flags = args.atOrUndefined(isolate, 2);
|
| -
|
| - Handle<JSFunction> target = isolate->regexp_function();
|
| -
|
| - bool pattern_is_regexp;
|
| - {
|
| - Maybe<bool> maybe_pattern_is_regexp =
|
| - RegExpUtils::IsRegExp(isolate, pattern);
|
| - if (maybe_pattern_is_regexp.IsNothing()) {
|
| - DCHECK(isolate->has_pending_exception());
|
| - return isolate->heap()->exception();
|
| - }
|
| - pattern_is_regexp = maybe_pattern_is_regexp.FromJust();
|
| - }
|
| -
|
| - if (new_target->IsUndefined(isolate)) {
|
| - new_target = target;
|
| -
|
| - // ES6 section 21.2.3.1 step 3.b
|
| - if (pattern_is_regexp && flags->IsUndefined(isolate)) {
|
| - Handle<Object> pattern_constructor;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, pattern_constructor,
|
| - Object::GetProperty(pattern,
|
| - isolate->factory()->constructor_string()));
|
| -
|
| - if (pattern_constructor.is_identical_to(new_target)) {
|
| - return *pattern;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (pattern->IsJSRegExp()) {
|
| - Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern);
|
| -
|
| - if (flags->IsUndefined(isolate)) {
|
| - flags = PatternFlags(isolate, regexp_pattern);
|
| - }
|
| - pattern = handle(regexp_pattern->source(), isolate);
|
| - } else if (pattern_is_regexp) {
|
| - Handle<Object> pattern_source;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, pattern_source,
|
| - Object::GetProperty(pattern, isolate->factory()->source_string()));
|
| -
|
| - if (flags->IsUndefined(isolate)) {
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, flags,
|
| - Object::GetProperty(pattern, isolate->factory()->flags_string()));
|
| - }
|
| - pattern = pattern_source;
|
| - }
|
| -
|
| - Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target);
|
| -
|
| - // TODO(jgruber): Fast-path for target == new_target == unmodified JSRegExp.
|
| -
|
| - Handle<JSObject> object;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, object, JSObject::New(target, new_target_receiver));
|
| - Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object);
|
| -
|
| - RETURN_RESULT_OR_FAILURE(isolate,
|
| - RegExpInitialize(isolate, regexp, pattern, flags));
|
| -}
|
| -
|
| -BUILTIN(RegExpPrototypeCompile) {
|
| - HandleScope scope(isolate);
|
| - CHECK_RECEIVER(JSRegExp, regexp, "RegExp.prototype.compile");
|
| -
|
| - Handle<Object> pattern = args.atOrUndefined(isolate, 1);
|
| - Handle<Object> flags = args.atOrUndefined(isolate, 2);
|
| -
|
| - if (pattern->IsJSRegExp()) {
|
| - Handle<JSRegExp> pattern_regexp = Handle<JSRegExp>::cast(pattern);
|
| -
|
| - if (!flags->IsUndefined(isolate)) {
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate, NewTypeError(MessageTemplate::kRegExpFlags));
|
| - }
|
| -
|
| - flags = PatternFlags(isolate, pattern_regexp);
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, pattern,
|
| - Object::GetProperty(pattern, isolate->factory()->source_string()));
|
| - }
|
| -
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags));
|
| -
|
| - // Return undefined for compatibility with JSC.
|
| - // See http://crbug.com/585775 for web compat details.
|
| -
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -namespace {
|
| -
|
| Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) {
|
| // Load the in-object field.
|
| static const int field_offset =
|
| @@ -579,139 +427,395 @@ void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) {
|
| }
|
| }
|
|
|
| -void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) {
|
| - CodeStubAssembler a(state);
|
| -
|
| - Node* const receiver = a.Parameter(0);
|
| - Node* const context = a.Parameter(3);
|
| -
|
| - Isolate* isolate = a.isolate();
|
| - Node* const int_zero = a.IntPtrConstant(0);
|
| - Node* const int_one = a.IntPtrConstant(1);
|
| +namespace {
|
|
|
| - Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver,
|
| - MessageTemplate::kRegExpNonObject,
|
| - "RegExp.prototype.flags");
|
| +Node* FlagsGetter(CodeStubAssembler* a, Node* const receiver,
|
| + Node* const context, bool is_fastpath) {
|
| + Isolate* isolate = a->isolate();
|
|
|
| - CVariable var_length(&a, MachineType::PointerRepresentation());
|
| - CVariable var_flags(&a, MachineType::PointerRepresentation());
|
| + Node* const int_zero = a->IntPtrConstant(0);
|
| + Node* const int_one = a->IntPtrConstant(1);
|
| + CVariable var_length(a, MachineType::PointerRepresentation());
|
| + CVariable var_flags(a, MachineType::PointerRepresentation());
|
|
|
| // First, count the number of characters we will need and check which flags
|
| // are set.
|
|
|
| var_length.Bind(int_zero);
|
|
|
| - CLabel if_isunmodifiedjsregexp(&a),
|
| - if_isnotunmodifiedjsregexp(&a, CLabel::kDeferred);
|
| - a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp,
|
| - &if_isnotunmodifiedjsregexp);
|
| -
|
| - CLabel construct_string(&a);
|
| - a.Bind(&if_isunmodifiedjsregexp);
|
| - {
|
| + if (is_fastpath) {
|
| // Refer to JSRegExp's flag property on the fast-path.
|
| - Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset);
|
| - Node* const flags_intptr = a.SmiUntag(flags_smi);
|
| + Node* const flags_smi =
|
| + a->LoadObjectField(receiver, JSRegExp::kFlagsOffset);
|
| + Node* const flags_intptr = a->SmiUntag(flags_smi);
|
| var_flags.Bind(flags_intptr);
|
|
|
| - CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a),
|
| - label_unicode(&a), label_sticky(&a);
|
| -
|
| -#define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \
|
| - do { \
|
| - a.Bind(&LABEL); \
|
| - Node* const mask = a.IntPtrConstant(FLAG); \
|
| - a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \
|
| - &NEXT_LABEL); \
|
| - var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \
|
| - a.Goto(&NEXT_LABEL); \
|
| +#define CASE_FOR_FLAG(FLAG) \
|
| + do { \
|
| + CLabel next(a); \
|
| + a->GotoUnless(a->IsSetWord(flags_intptr, FLAG), &next); \
|
| + var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \
|
| + a->Goto(&next); \
|
| + a->Bind(&next); \
|
| } while (false)
|
|
|
| - a.Goto(&label_global);
|
| - CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase);
|
| - CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline);
|
| - CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode);
|
| - CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky);
|
| - CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string);
|
| + CASE_FOR_FLAG(JSRegExp::kGlobal);
|
| + CASE_FOR_FLAG(JSRegExp::kIgnoreCase);
|
| + CASE_FOR_FLAG(JSRegExp::kMultiline);
|
| + CASE_FOR_FLAG(JSRegExp::kUnicode);
|
| + CASE_FOR_FLAG(JSRegExp::kSticky);
|
| #undef CASE_FOR_FLAG
|
| - }
|
| + } else {
|
| + DCHECK(!is_fastpath);
|
|
|
| - a.Bind(&if_isnotunmodifiedjsregexp);
|
| - {
|
| // Fall back to GetProperty stub on the slow-path.
|
| var_flags.Bind(int_zero);
|
|
|
| - Callable getproperty_callable = CodeFactory::GetProperty(a.isolate());
|
| - CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a),
|
| - label_unicode(&a), label_sticky(&a);
|
| -
|
| -#define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \
|
| - do { \
|
| - a.Bind(&LABEL); \
|
| - Node* const name = \
|
| - a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \
|
| - Node* const flag = \
|
| - a.CallStub(getproperty_callable, context, receiver, name); \
|
| - CLabel if_isflagset(&a); \
|
| - a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \
|
| - a.Bind(&if_isflagset); \
|
| - var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \
|
| - var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \
|
| - a.Goto(&NEXT_LABEL); \
|
| + Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
| +
|
| +#define CASE_FOR_FLAG(NAME, FLAG) \
|
| + do { \
|
| + CLabel next(a); \
|
| + Node* const name = \
|
| + a->HeapConstant(isolate->factory()->InternalizeUtf8String(NAME)); \
|
| + Node* const flag = \
|
| + a->CallStub(getproperty_callable, context, receiver, name); \
|
| + CLabel if_isflagset(a); \
|
| + a->BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
|
| + a->Bind(&if_isflagset); \
|
| + var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \
|
| + var_flags.Bind(a->WordOr(var_flags.value(), a->IntPtrConstant(FLAG))); \
|
| + a->Goto(&next); \
|
| + a->Bind(&next); \
|
| } while (false)
|
|
|
| - a.Goto(&label_global);
|
| - CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase);
|
| - CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase,
|
| - label_multiline);
|
| - CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline,
|
| - label_unicode);
|
| - CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky);
|
| - CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string);
|
| + CASE_FOR_FLAG("global", JSRegExp::kGlobal);
|
| + CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase);
|
| + CASE_FOR_FLAG("multiline", JSRegExp::kMultiline);
|
| + CASE_FOR_FLAG("unicode", JSRegExp::kUnicode);
|
| + CASE_FOR_FLAG("sticky", JSRegExp::kSticky);
|
| #undef CASE_FOR_FLAG
|
| }
|
|
|
| // Allocate a string of the required length and fill it with the corresponding
|
| // char for each set flag.
|
|
|
| - a.Bind(&construct_string);
|
| {
|
| Node* const result =
|
| - a.AllocateSeqOneByteString(context, var_length.value());
|
| + a->AllocateSeqOneByteString(context, var_length.value());
|
| Node* const flags_intptr = var_flags.value();
|
|
|
| - CVariable var_offset(&a, MachineType::PointerRepresentation());
|
| + CVariable var_offset(a, MachineType::PointerRepresentation());
|
| var_offset.Bind(
|
| - a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
|
| -
|
| - CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a),
|
| - label_unicode(&a), label_sticky(&a), out(&a);
|
| -
|
| -#define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \
|
| - do { \
|
| - a.Bind(&LABEL); \
|
| - Node* const mask = a.IntPtrConstant(FLAG); \
|
| - a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \
|
| - &NEXT_LABEL); \
|
| - Node* const value = a.IntPtrConstant(CHAR); \
|
| - a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \
|
| - var_offset.value(), value); \
|
| - var_offset.Bind(a.IntPtrAdd(var_offset.value(), int_one)); \
|
| - a.Goto(&NEXT_LABEL); \
|
| + a->IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
|
| +
|
| +#define CASE_FOR_FLAG(FLAG, CHAR) \
|
| + do { \
|
| + CLabel next(a); \
|
| + a->GotoUnless(a->IsSetWord(flags_intptr, FLAG), &next); \
|
| + Node* const value = a->IntPtrConstant(CHAR); \
|
| + a->StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \
|
| + var_offset.value(), value); \
|
| + var_offset.Bind(a->IntPtrAdd(var_offset.value(), int_one)); \
|
| + a->Goto(&next); \
|
| + a->Bind(&next); \
|
| } while (false)
|
|
|
| - a.Goto(&label_global);
|
| - CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase);
|
| - CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase,
|
| - label_multiline);
|
| - CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode);
|
| - CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky);
|
| - CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out);
|
| + CASE_FOR_FLAG(JSRegExp::kGlobal, 'g');
|
| + CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i');
|
| + CASE_FOR_FLAG(JSRegExp::kMultiline, 'm');
|
| + CASE_FOR_FLAG(JSRegExp::kUnicode, 'u');
|
| + CASE_FOR_FLAG(JSRegExp::kSticky, 'y');
|
| #undef CASE_FOR_FLAG
|
|
|
| - a.Bind(&out);
|
| - a.Return(result);
|
| + return result;
|
| + }
|
| +}
|
| +
|
| +// ES#sec-isregexp IsRegExp ( argument )
|
| +Node* IsRegExp(CodeStubAssembler* a, Node* const context,
|
| + Node* const maybe_receiver) {
|
| + CLabel out(a), if_isregexp(a);
|
| +
|
| + CVariable var_result(a, MachineType::PointerRepresentation());
|
| + var_result.Bind(a->IntPtrConstant(0));
|
| +
|
| + a->GotoIf(a->TaggedIsSmi(maybe_receiver), &out);
|
| + a->GotoUnless(a->IsJSReceiver(maybe_receiver), &out);
|
| +
|
| + Node* const receiver = maybe_receiver;
|
| +
|
| + // Check @@match.
|
| + {
|
| + Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
|
| + Node* const name = a->HeapConstant(a->isolate()->factory()->match_symbol());
|
| + Node* const value =
|
| + a->CallStub(getproperty_callable, context, receiver, name);
|
| +
|
| + CLabel match_isundefined(a), match_isnotundefined(a);
|
| + a->Branch(a->IsUndefined(value), &match_isundefined, &match_isnotundefined);
|
| +
|
| + a->Bind(&match_isundefined);
|
| + a->Branch(a->HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out);
|
| +
|
| + a->Bind(&match_isnotundefined);
|
| + a->BranchIfToBooleanIsTrue(value, &if_isregexp, &out);
|
| + }
|
| +
|
| + a->Bind(&if_isregexp);
|
| + var_result.Bind(a->IntPtrConstant(1));
|
| + a->Goto(&out);
|
| +
|
| + a->Bind(&out);
|
| + return var_result.value();
|
| +}
|
| +
|
| +// ES#sec-regexpinitialize
|
| +// Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
|
| +Node* RegExpInitialize(CodeStubAssembler* a, Node* const context,
|
| + Node* const regexp, Node* const maybe_pattern,
|
| + Node* const maybe_flags) {
|
| + // Normalize pattern.
|
| + Node* const pattern = a->Select(
|
| + a->IsUndefined(maybe_pattern), [=] { return a->EmptyStringConstant(); },
|
| + [=] { return a->ToString(context, maybe_pattern); },
|
| + MachineRepresentation::kTagged);
|
| +
|
| + // Normalize flags.
|
| + Node* const flags = a->Select(
|
| + a->IsUndefined(maybe_flags), [=] { return a->EmptyStringConstant(); },
|
| + [=] { return a->ToString(context, maybe_flags); },
|
| + MachineRepresentation::kTagged);
|
| +
|
| + // Initialize.
|
| +
|
| + return a->CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp,
|
| + pattern, flags);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) {
|
| + CodeStubAssembler a(state);
|
| +
|
| + Isolate* isolate = a.isolate();
|
| +
|
| + Node* const maybe_receiver = a.Parameter(0);
|
| + Node* const context = a.Parameter(3);
|
| +
|
| + Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver,
|
| + MessageTemplate::kRegExpNonObject,
|
| + "RegExp.prototype.flags");
|
| + Node* const receiver = maybe_receiver;
|
| +
|
| + CLabel if_isfastpath(&a), if_isslowpath(&a, CLabel::kDeferred);
|
| + a.Branch(IsInitialRegExpMap(&a, context, map), &if_isfastpath,
|
| + &if_isslowpath);
|
| +
|
| + a.Bind(&if_isfastpath);
|
| + a.Return(FlagsGetter(&a, receiver, context, true));
|
| +
|
| + a.Bind(&if_isslowpath);
|
| + a.Return(FlagsGetter(&a, receiver, context, false));
|
| +}
|
| +
|
| +// ES#sec-regexp-pattern-flags
|
| +// RegExp ( pattern, flags )
|
| +void Builtins::Generate_RegExpConstructor(CodeAssemblerState* state) {
|
| + CodeStubAssembler a(state);
|
| +
|
| + Node* const pattern = a.Parameter(1);
|
| + Node* const flags = a.Parameter(2);
|
| + Node* const new_target = a.Parameter(3);
|
| + Node* const context = a.Parameter(5);
|
| +
|
| + Isolate* isolate = a.isolate();
|
| +
|
| + CVariable var_flags(&a, MachineRepresentation::kTagged);
|
| + CVariable var_pattern(&a, MachineRepresentation::kTagged);
|
| + CVariable var_new_target(&a, MachineRepresentation::kTagged);
|
| +
|
| + var_flags.Bind(flags);
|
| + var_pattern.Bind(pattern);
|
| + var_new_target.Bind(new_target);
|
| +
|
| + Node* const native_context = a.LoadNativeContext(context);
|
| + Node* const regexp_function =
|
| + a.LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
|
| +
|
| + Node* const pattern_is_regexp = IsRegExp(&a, context, pattern);
|
| +
|
| + {
|
| + CLabel next(&a);
|
| +
|
| + a.GotoUnless(a.IsUndefined(new_target), &next);
|
| + var_new_target.Bind(regexp_function);
|
| +
|
| + a.GotoUnless(pattern_is_regexp, &next);
|
| + a.GotoUnless(a.IsUndefined(flags), &next);
|
| +
|
| + Callable getproperty_callable = CodeFactory::GetProperty(isolate);
|
| + Node* const name = a.HeapConstant(isolate->factory()->constructor_string());
|
| + Node* const value =
|
| + a.CallStub(getproperty_callable, context, pattern, name);
|
| +
|
| + a.GotoUnless(a.WordEqual(value, regexp_function), &next);
|
| + a.Return(pattern);
|
| +
|
| + a.Bind(&next);
|
| + }
|
| +
|
| + {
|
| + CLabel next(&a), if_patternisfastregexp(&a), if_patternisslowregexp(&a);
|
| + a.GotoIf(a.TaggedIsSmi(pattern), &next);
|
| +
|
| + a.GotoIf(a.HasInstanceType(pattern, JS_REGEXP_TYPE),
|
| + &if_patternisfastregexp);
|
| +
|
| + a.Branch(pattern_is_regexp, &if_patternisslowregexp, &next);
|
| +
|
| + a.Bind(&if_patternisfastregexp);
|
| + {
|
| + Node* const source = a.LoadObjectField(pattern, JSRegExp::kSourceOffset);
|
| + var_pattern.Bind(source);
|
| +
|
| + {
|
| + CLabel inner_next(&a);
|
| + a.GotoUnless(a.IsUndefined(flags), &inner_next);
|
| +
|
| + Node* const value = FlagsGetter(&a, pattern, context, true);
|
| + var_flags.Bind(value);
|
| + a.Goto(&inner_next);
|
| +
|
| + a.Bind(&inner_next);
|
| + }
|
| +
|
| + a.Goto(&next);
|
| + }
|
| +
|
| + a.Bind(&if_patternisslowregexp);
|
| + {
|
| + Callable getproperty_callable = CodeFactory::GetProperty(isolate);
|
| +
|
| + {
|
| + Node* const name = a.HeapConstant(isolate->factory()->source_string());
|
| + Node* const value =
|
| + a.CallStub(getproperty_callable, context, pattern, name);
|
| + var_pattern.Bind(value);
|
| + }
|
| +
|
| + {
|
| + CLabel inner_next(&a);
|
| + a.GotoUnless(a.IsUndefined(flags), &inner_next);
|
| +
|
| + Node* const name = a.HeapConstant(isolate->factory()->flags_string());
|
| + Node* const value =
|
| + a.CallStub(getproperty_callable, context, pattern, name);
|
| + var_flags.Bind(value);
|
| + a.Goto(&inner_next);
|
| +
|
| + a.Bind(&inner_next);
|
| + }
|
| +
|
| + a.Goto(&next);
|
| + }
|
| +
|
| + a.Bind(&next);
|
| + }
|
| +
|
| + // Allocate.
|
| +
|
| + CVariable var_regexp(&a, MachineRepresentation::kTagged);
|
| + {
|
| + CLabel allocate_jsregexp(&a), allocate_generic(&a, CLabel::kDeferred),
|
| + next(&a);
|
| + a.Branch(a.WordEqual(var_new_target.value(), regexp_function),
|
| + &allocate_jsregexp, &allocate_generic);
|
| +
|
| + a.Bind(&allocate_jsregexp);
|
| + {
|
| + Node* const initial_map = a.LoadObjectField(
|
| + regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
|
| + Node* const regexp = a.AllocateJSObjectFromMap(initial_map);
|
| + var_regexp.Bind(regexp);
|
| + a.Goto(&next);
|
| + }
|
| +
|
| + a.Bind(&allocate_generic);
|
| + {
|
| + Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate);
|
| + Node* const regexp = a.CallStub(fastnewobject_callable, context,
|
| + regexp_function, var_new_target.value());
|
| + var_regexp.Bind(regexp);
|
| + a.Goto(&next);
|
| + }
|
| +
|
| + a.Bind(&next);
|
| }
|
| +
|
| + Node* const result = RegExpInitialize(&a, context, var_regexp.value(),
|
| + var_pattern.value(), var_flags.value());
|
| + a.Return(result);
|
| +}
|
| +
|
| +// ES#sec-regexp.prototype.compile
|
| +// RegExp.prototype.compile ( pattern, flags )
|
| +void Builtins::Generate_RegExpPrototypeCompile(CodeAssemblerState* state) {
|
| + CodeStubAssembler a(state);
|
| +
|
| + Node* const maybe_receiver = a.Parameter(0);
|
| + Node* const maybe_pattern = a.Parameter(1);
|
| + Node* const maybe_flags = a.Parameter(2);
|
| + Node* const context = a.Parameter(5);
|
| +
|
| + a.ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
|
| + "RegExp.prototype.compile");
|
| + Node* const receiver = maybe_receiver;
|
| +
|
| + CVariable var_flags(&a, MachineRepresentation::kTagged);
|
| + CVariable var_pattern(&a, MachineRepresentation::kTagged);
|
| +
|
| + var_flags.Bind(maybe_flags);
|
| + var_pattern.Bind(maybe_pattern);
|
| +
|
| + // Handle a JSRegExp pattern.
|
| + {
|
| + CLabel next(&a);
|
| +
|
| + a.GotoIf(a.TaggedIsSmi(maybe_pattern), &next);
|
| + a.GotoUnless(a.HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next);
|
| +
|
| + Node* const pattern = maybe_pattern;
|
| +
|
| + // {maybe_flags} must be undefined in this case, otherwise throw.
|
| + {
|
| + CLabel next(&a);
|
| + a.GotoIf(a.IsUndefined(maybe_flags), &next);
|
| +
|
| + Node* const message_id = a.SmiConstant(MessageTemplate::kRegExpFlags);
|
| + a.TailCallRuntime(Runtime::kThrowTypeError, context, message_id);
|
| +
|
| + a.Bind(&next);
|
| + }
|
| +
|
| + Node* const new_flags = FlagsGetter(&a, pattern, context, true);
|
| + Node* const new_pattern =
|
| + a.LoadObjectField(pattern, JSRegExp::kSourceOffset);
|
| +
|
| + var_flags.Bind(new_flags);
|
| + var_pattern.Bind(new_pattern);
|
| +
|
| + a.Goto(&next);
|
| + a.Bind(&next);
|
| + }
|
| +
|
| + RegExpInitialize(&a, context, receiver, var_pattern.value(),
|
| + var_flags.value());
|
| +
|
| + // Return undefined for compatibility with JSC.
|
| + // See http://crbug.com/585775 for web compat details.
|
| +
|
| + a.Return(a.UndefinedConstant());
|
| }
|
|
|
| // ES6 21.2.5.10.
|
|
|