| Index: src/builtins/builtins-regexp.cc
|
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
|
| index d720bbed011dd2e67f8be57550b6b9f518f832f9..371221fa70a8d0d49c83e2c38bd2e37ddbc77668 100644
|
| --- a/src/builtins/builtins-regexp.cc
|
| +++ b/src/builtins/builtins-regexp.cc
|
| @@ -11,6 +11,153 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +// -----------------------------------------------------------------------------
|
| +// ES6 section 21.2 RegExp Objects
|
| +
|
| +namespace {
|
| +
|
| +// ES#sec-isregexp IsRegExp ( argument )
|
| +Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object) {
|
| + if (!object->IsJSReceiver()) return Just(false);
|
| +
|
| + Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
|
| +
|
| + if (isolate->regexp_function()->initial_map() == receiver->map()) {
|
| + // Fast-path for unmodified JSRegExp instances.
|
| + return Just(true);
|
| + }
|
| +
|
| + Handle<Object> match;
|
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| + isolate, match,
|
| + JSObject::GetProperty(receiver, isolate->factory()->match_symbol()),
|
| + Nothing<bool>());
|
| +
|
| + if (!match->IsUndefined(isolate)) return Just(match->BooleanValue());
|
| + return Just(object->IsJSRegExp());
|
| +}
|
| +
|
| +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 )
|
| +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_RESULT(isolate,
|
| + JSRegExp::Initialize(regexp, pattern_string, flags_string),
|
| + JSRegExp);
|
| +}
|
| +
|
| +} // 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 = 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));
|
| +}
|
| +
|
| namespace {
|
|
|
| compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context,
|
|
|