Commit 0aa80be1 authored by jgruber's avatar jgruber Committed by Commit bot

[regexp] Port RegExpConstructor

BUG=v8:5339

Review-Url: https://codereview.chromium.org/2302773002
Cr-Commit-Position: refs/heads/master@{#39074}
parent 39d65198
......@@ -909,6 +909,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-object.cc",
"src/builtins/builtins-proxy.cc",
"src/builtins/builtins-reflect.cc",
"src/builtins/builtins-regexp.cc",
"src/builtins/builtins-sharedarraybuffer.cc",
"src/builtins/builtins-string.cc",
"src/builtins/builtins-symbol.cc",
......
......@@ -1575,14 +1575,23 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
{ // -- R e g E x p
// Builtin functions for RegExp.prototype.
Handle<JSFunction> regexp_fun =
InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
isolate->initial_object_prototype(),
Builtins::kIllegal);
Handle<JSFunction> regexp_fun = InstallFunction(
global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
isolate->initial_object_prototype(), Builtins::kRegExpConstructor);
InstallWithIntrinsicDefaultProto(isolate, regexp_fun,
Context::REGEXP_FUNCTION_INDEX);
regexp_fun->shared()->SetConstructStub(
*isolate->builtins()->JSBuiltinsConstructStub());
Handle<SharedFunctionInfo> shared(regexp_fun->shared(), isolate);
shared->SetConstructStub(*isolate->builtins()->RegExpConstructor());
shared->set_instance_class_name(isolate->heap()->RegExp_string());
shared->DontAdaptArguments();
shared->set_length(2);
Handle<JSObject> proto =
factory->NewJSObject(isolate->object_function(), TENURED);
JSObject::AddProperty(proto, factory->constructor_string(), regexp_fun,
DONT_ENUM);
Accessors::FunctionSetPrototype(regexp_fun, proto).Assert();
DCHECK(regexp_fun->has_initial_map());
Handle<Map> initial_map(regexp_fun->initial_map());
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/string-builder.h"
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);
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) {
IncrementalStringBuilder builder(isolate);
const JSRegExp::Flags flags = regexp->GetFlags();
if ((flags & JSRegExp::kGlobal) != 0) builder.AppendCharacter('g');
if ((flags & JSRegExp::kIgnoreCase) != 0) builder.AppendCharacter('i');
if ((flags & JSRegExp::kMultiline) != 0) builder.AppendCharacter('m');
if ((flags & JSRegExp::kUnicode) != 0) builder.AppendCharacter('u');
if ((flags & JSRegExp::kSticky) != 0) builder.AppendCharacter('y');
return builder.Finish().ToHandleChecked();
}
// 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 =
handle(isolate->native_context()->regexp_function(), isolate);
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 == *new_target) {
return *pattern;
}
}
} else if (!new_target->IsJSReceiver()) {
// TODO(jgruber): Better error message.
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledNonCallable, new_target));
}
Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target);
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<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 internal
} // namespace v8
......@@ -491,6 +491,9 @@ namespace internal {
CPP(ReflectSet) \
CPP(ReflectSetPrototypeOf) \
\
/* RegExp */ \
CPP(RegExpConstructor) \
\
/* SharedArrayBuffer */ \
CPP(SharedArrayBufferPrototypeGetByteLength) \
TFJ(AtomicsLoad, 3) \
......
......@@ -61,6 +61,7 @@
V(eval_string, "eval") \
V(EvalError_string, "EvalError") \
V(false_string, "false") \
V(flags_string, "flags") \
V(float32x4_string, "float32x4") \
V(Float32x4_string, "Float32x4") \
V(for_api_string, "for_api") \
......
......@@ -13,7 +13,6 @@ var ExpandReplacement;
var GlobalArray = global.Array;
var GlobalObject = global.Object;
var GlobalRegExp = global.RegExp;
var GlobalRegExpPrototype;
var InternalArray = utils.InternalArray;
var InternalPackedArray = utils.InternalPackedArray;
var MaxSimple;
......@@ -80,37 +79,6 @@ function PatternFlags(pattern) {
}
// ES#sec-regexp-pattern-flags
// RegExp ( pattern, flags )
function RegExpConstructor(pattern, flags) {
var newtarget = new.target;
var pattern_is_regexp = IsRegExp(pattern);
if (IS_UNDEFINED(newtarget)) {
newtarget = GlobalRegExp;
// ES6 section 21.2.3.1 step 3.b
if (pattern_is_regexp && IS_UNDEFINED(flags) &&
pattern.constructor === newtarget) {
return pattern;
}
}
if (IS_REGEXP(pattern)) {
if (IS_UNDEFINED(flags)) flags = PatternFlags(pattern);
pattern = REGEXP_SOURCE(pattern);
} else if (pattern_is_regexp) {
var input_pattern = pattern;
pattern = pattern.source;
if (IS_UNDEFINED(flags)) flags = input_pattern.flags;
}
var object = %_NewObject(GlobalRegExp, newtarget);
return RegExpInitialize(object, pattern, flags);
}
// ES#sec-regexp.prototype.compile RegExp.prototype.compile (pattern, flags)
function RegExpCompileJS(pattern, flags) {
if (!IS_REGEXP(this)) {
......@@ -371,7 +339,7 @@ function RegExpToString() {
throw %make_type_error(
kIncompatibleMethodReceiver, 'RegExp.prototype.toString', this);
}
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeToString);
}
return '/' + TO_STRING(this.source) + '/' + TO_STRING(this.flags);
......@@ -1036,7 +1004,7 @@ function RegExpGetFlags() {
function RegExpGetGlobal() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
......@@ -1051,7 +1019,7 @@ function RegExpGetGlobal() {
function RegExpGetIgnoreCase() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
......@@ -1065,7 +1033,7 @@ function RegExpGetIgnoreCase() {
function RegExpGetMultiline() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
......@@ -1079,7 +1047,7 @@ function RegExpGetMultiline() {
function RegExpGetSource() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeSourceGetter);
return "(?:)";
}
......@@ -1094,7 +1062,7 @@ function RegExpGetSticky() {
if (!IS_REGEXP(this)) {
// Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
// TODO(littledan): Remove this workaround or standardize it
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeStickyGetter);
return UNDEFINED;
}
......@@ -1109,7 +1077,7 @@ function RegExpGetSticky() {
function RegExpGetUnicode() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
if (this === GlobalRegExp.prototype) {
%IncrementUseCounter(kRegExpPrototypeUnicodeGetter);
return UNDEFINED;
}
......@@ -1127,13 +1095,6 @@ function RegExpSpecies() {
// -------------------------------------------------------------------
%FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
GlobalRegExpPrototype = new GlobalObject();
%FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype);
%AddNamedProperty(
GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
%SetCode(GlobalRegExp, RegExpConstructor);
utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies);
utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
......
......@@ -503,6 +503,7 @@
'builtins/builtins-object.cc',
'builtins/builtins-proxy.cc',
'builtins/builtins-reflect.cc',
'builtins/builtins-regexp.cc',
'builtins/builtins-sharedarraybuffer.cc',
'builtins/builtins-string.cc',
'builtins/builtins-symbol.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment