Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Unified Diff: src/builtins/builtins-regexp.cc

Issue 2551443002: [regexp] Migrate constructor and compile to CSA (Closed)
Patch Set: Address comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698