[regexp] Port RegExp getters and setters
Flag getters are implemented as TurboFan stubs while the rest are written as C++. This distinction is somewhat arbitrary and more getters could be ported to TurboFan in the future. BUG=v8:5339 Review-Url: https://codereview.chromium.org/2389233002 Cr-Commit-Position: refs/heads/master@{#40036}
This commit is contained in:
parent
a105dafa96
commit
4e219bb46a
@ -364,17 +364,6 @@ void InstallFunction(Handle<JSObject> target, Handle<JSFunction> function,
|
||||
InstallFunction(target, name, function, name_string, attributes);
|
||||
}
|
||||
|
||||
Handle<JSFunction> InstallGetter(Handle<JSObject> target,
|
||||
Handle<Name> property_name,
|
||||
Handle<JSFunction> getter,
|
||||
PropertyAttributes attributes = DONT_ENUM) {
|
||||
Handle<Object> setter = target->GetIsolate()->factory()->undefined_value();
|
||||
JSObject::DefineAccessor(target, property_name, getter, setter, attributes)
|
||||
.Check();
|
||||
getter->shared()->set_native(true);
|
||||
return getter;
|
||||
}
|
||||
|
||||
Handle<JSFunction> CreateFunction(Isolate* isolate, Handle<String> name,
|
||||
InstanceType type, int instance_size,
|
||||
MaybeHandle<JSObject> maybe_prototype,
|
||||
@ -460,17 +449,54 @@ Handle<JSFunction> SimpleInstallFunction(Handle<JSObject> base,
|
||||
return fun;
|
||||
}
|
||||
|
||||
void SimpleInstallGetterSetter(Handle<JSObject> base, Handle<String> name,
|
||||
Builtins::Name call_getter,
|
||||
Builtins::Name call_setter,
|
||||
PropertyAttributes attribs) {
|
||||
Isolate* const isolate = base->GetIsolate();
|
||||
|
||||
Handle<String> getter_name =
|
||||
Name::ToFunctionName(name, isolate->factory()->get_string())
|
||||
.ToHandleChecked();
|
||||
Handle<JSFunction> getter =
|
||||
SimpleCreateFunction(isolate, getter_name, call_getter, 0, false);
|
||||
getter->shared()->set_native(true);
|
||||
|
||||
Handle<String> setter_name =
|
||||
Name::ToFunctionName(name, isolate->factory()->set_string())
|
||||
.ToHandleChecked();
|
||||
Handle<JSFunction> setter =
|
||||
SimpleCreateFunction(isolate, setter_name, call_setter, 0, false);
|
||||
setter->shared()->set_native(true);
|
||||
|
||||
JSObject::DefineAccessor(base, name, getter, setter, attribs).Check();
|
||||
}
|
||||
|
||||
Handle<JSFunction> SimpleInstallGetter(Handle<JSObject> base,
|
||||
Handle<String> name,
|
||||
Handle<Name> property_name,
|
||||
Builtins::Name call, bool adapt) {
|
||||
Isolate* const isolate = base->GetIsolate();
|
||||
|
||||
Handle<String> getter_name =
|
||||
Name::ToFunctionName(name, isolate->factory()->get_string())
|
||||
.ToHandleChecked();
|
||||
Handle<JSFunction> getter =
|
||||
SimpleCreateFunction(isolate, getter_name, call, 0, adapt);
|
||||
getter->shared()->set_native(true);
|
||||
|
||||
Handle<Object> setter = isolate->factory()->undefined_value();
|
||||
|
||||
JSObject::DefineAccessor(base, property_name, getter, setter, DONT_ENUM)
|
||||
.Check();
|
||||
|
||||
return getter;
|
||||
}
|
||||
|
||||
Handle<JSFunction> SimpleInstallGetter(Handle<JSObject> base,
|
||||
Handle<String> name, Builtins::Name call,
|
||||
bool adapt) {
|
||||
Isolate* const isolate = base->GetIsolate();
|
||||
Handle<String> fun_name =
|
||||
Name::ToFunctionName(name, isolate->factory()->get_string())
|
||||
.ToHandleChecked();
|
||||
Handle<JSFunction> fun =
|
||||
SimpleCreateFunction(isolate, fun_name, call, 0, adapt);
|
||||
InstallGetter(base, name, fun);
|
||||
return fun;
|
||||
return SimpleInstallGetter(base, name, name, call, adapt);
|
||||
}
|
||||
|
||||
Handle<JSFunction> SimpleInstallGetter(Handle<JSObject> base,
|
||||
@ -1660,14 +1686,105 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
shared->DontAdaptArguments();
|
||||
shared->set_length(2);
|
||||
|
||||
// RegExp.prototype setup.
|
||||
{
|
||||
// RegExp.prototype setup.
|
||||
|
||||
// Install the "constructor" property on the {prototype}.
|
||||
JSObject::AddProperty(prototype, factory->constructor_string(), regexp_fun,
|
||||
DONT_ENUM);
|
||||
// Install the "constructor" property on the {prototype}.
|
||||
JSObject::AddProperty(prototype, factory->constructor_string(),
|
||||
regexp_fun, DONT_ENUM);
|
||||
|
||||
SimpleInstallFunction(prototype, "exec", Builtins::kRegExpPrototypeExec, 1,
|
||||
true, DONT_ENUM);
|
||||
SimpleInstallFunction(prototype, "exec", Builtins::kRegExpPrototypeExec,
|
||||
1, true, DONT_ENUM);
|
||||
|
||||
SimpleInstallGetter(prototype, factory->flags_string(),
|
||||
Builtins::kRegExpPrototypeFlagsGetter, true);
|
||||
SimpleInstallGetter(prototype, factory->global_string(),
|
||||
Builtins::kRegExpPrototypeGlobalGetter, true);
|
||||
SimpleInstallGetter(prototype, factory->ignoreCase_string(),
|
||||
Builtins::kRegExpPrototypeIgnoreCaseGetter, true);
|
||||
SimpleInstallGetter(prototype, factory->multiline_string(),
|
||||
Builtins::kRegExpPrototypeMultilineGetter, true);
|
||||
SimpleInstallGetter(prototype, factory->source_string(),
|
||||
Builtins::kRegExpPrototypeSourceGetter, false);
|
||||
SimpleInstallGetter(prototype, factory->sticky_string(),
|
||||
Builtins::kRegExpPrototypeStickyGetter, true);
|
||||
SimpleInstallGetter(prototype, factory->unicode_string(),
|
||||
Builtins::kRegExpPrototypeUnicodeGetter, true);
|
||||
}
|
||||
|
||||
{
|
||||
// RegExp getters and setters.
|
||||
|
||||
// TODO(jgruber): This should really be DONT_ENUM | DONT_DELETE.
|
||||
// However, that currently breaks layout test expectations. Note that
|
||||
// Firefox sets a couple of these as enumerable.
|
||||
// On the other hand, installing attributes as DONT_ENUM matches the draft
|
||||
// specification at
|
||||
// https://github.com/claudepache/es-regexp-legacy-static-properties.
|
||||
const PropertyAttributes no_enum = DONT_ENUM;
|
||||
|
||||
SimpleInstallGetter(regexp_fun,
|
||||
factory->InternalizeUtf8String("[Symbol.species]"),
|
||||
factory->species_symbol(),
|
||||
Builtins::kRegExpPrototypeSpeciesGetter, false);
|
||||
|
||||
// Static properties set by a successful match.
|
||||
|
||||
SimpleInstallGetterSetter(regexp_fun, factory->input_string(),
|
||||
Builtins::kRegExpInputGetter,
|
||||
Builtins::kRegExpInputSetter, DONT_DELETE);
|
||||
SimpleInstallGetterSetter(
|
||||
regexp_fun, factory->InternalizeUtf8String("$_"),
|
||||
Builtins::kRegExpInputGetter, Builtins::kRegExpInputSetter, no_enum);
|
||||
|
||||
SimpleInstallGetterSetter(
|
||||
regexp_fun, factory->InternalizeUtf8String("lastMatch"),
|
||||
Builtins::kRegExpLastMatchGetter, Builtins::kEmptyFunction, no_enum);
|
||||
SimpleInstallGetterSetter(
|
||||
regexp_fun, factory->InternalizeUtf8String("$&"),
|
||||
Builtins::kRegExpLastMatchGetter, Builtins::kEmptyFunction, no_enum);
|
||||
|
||||
SimpleInstallGetterSetter(
|
||||
regexp_fun, factory->InternalizeUtf8String("lastParen"),
|
||||
Builtins::kRegExpLastParenGetter, Builtins::kEmptyFunction, no_enum);
|
||||
SimpleInstallGetterSetter(
|
||||
regexp_fun, factory->InternalizeUtf8String("$+"),
|
||||
Builtins::kRegExpLastParenGetter, Builtins::kEmptyFunction, no_enum);
|
||||
|
||||
SimpleInstallGetterSetter(regexp_fun,
|
||||
factory->InternalizeUtf8String("leftContext"),
|
||||
Builtins::kRegExpLeftContextGetter,
|
||||
Builtins::kEmptyFunction, no_enum);
|
||||
SimpleInstallGetterSetter(regexp_fun,
|
||||
factory->InternalizeUtf8String("$`"),
|
||||
Builtins::kRegExpLeftContextGetter,
|
||||
Builtins::kEmptyFunction, no_enum);
|
||||
|
||||
SimpleInstallGetterSetter(regexp_fun,
|
||||
factory->InternalizeUtf8String("rightContext"),
|
||||
Builtins::kRegExpRightContextGetter,
|
||||
Builtins::kEmptyFunction, no_enum);
|
||||
SimpleInstallGetterSetter(regexp_fun,
|
||||
factory->InternalizeUtf8String("$'"),
|
||||
Builtins::kRegExpRightContextGetter,
|
||||
Builtins::kEmptyFunction, no_enum);
|
||||
|
||||
#define INSTALL_CAPTURE_GETTER(i) \
|
||||
SimpleInstallGetterSetter(regexp_fun, \
|
||||
factory->InternalizeUtf8String("$" #i), \
|
||||
Builtins::kRegExpCapture##i##Getter, \
|
||||
Builtins::kEmptyFunction, DONT_DELETE)
|
||||
INSTALL_CAPTURE_GETTER(1);
|
||||
INSTALL_CAPTURE_GETTER(2);
|
||||
INSTALL_CAPTURE_GETTER(3);
|
||||
INSTALL_CAPTURE_GETTER(4);
|
||||
INSTALL_CAPTURE_GETTER(5);
|
||||
INSTALL_CAPTURE_GETTER(6);
|
||||
INSTALL_CAPTURE_GETTER(7);
|
||||
INSTALL_CAPTURE_GETTER(8);
|
||||
INSTALL_CAPTURE_GETTER(9);
|
||||
#undef INSTALL_CAPTURE_GETTER
|
||||
}
|
||||
|
||||
DCHECK(regexp_fun->has_initial_map());
|
||||
Handle<Map> initial_map(regexp_fun->initial_map());
|
||||
|
@ -437,5 +437,476 @@ void Builtins::Generate_RegExpPrototypeExec(CodeStubAssembler* a) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate,
|
||||
compiler::Node* context,
|
||||
compiler::Node* value,
|
||||
char const* method_name) {
|
||||
typedef compiler::Node Node;
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
|
||||
Label out(a), throw_exception(a, Label::kDeferred);
|
||||
Variable var_value_map(a, MachineRepresentation::kTagged);
|
||||
|
||||
a->GotoIf(a->WordIsSmi(value), &throw_exception);
|
||||
|
||||
// Load the instance type of the {value}.
|
||||
var_value_map.Bind(a->LoadMap(value));
|
||||
Node* const value_instance_type =
|
||||
a->LoadMapInstanceType(var_value_map.value());
|
||||
|
||||
a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out,
|
||||
&throw_exception);
|
||||
|
||||
// The {value} is not a compatible receiver for this method.
|
||||
a->Bind(&throw_exception);
|
||||
{
|
||||
Node* const message_id =
|
||||
a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonObject));
|
||||
Node* const method_name_str = a->HeapConstant(
|
||||
isolate->factory()->NewStringFromAsciiChecked(method_name, TENURED));
|
||||
|
||||
Callable callable = CodeFactory::ToString(isolate);
|
||||
Node* const value_str = a->CallStub(callable, context, value);
|
||||
|
||||
a->CallRuntime(Runtime::kThrowTypeError, context, message_id,
|
||||
method_name_str, value_str);
|
||||
var_value_map.Bind(a->UndefinedConstant());
|
||||
a->Goto(&out); // Never reached.
|
||||
}
|
||||
|
||||
a->Bind(&out);
|
||||
return var_value_map.value();
|
||||
}
|
||||
|
||||
compiler::Node* IsInitialRegExpMap(CodeStubAssembler* a,
|
||||
compiler::Node* context,
|
||||
compiler::Node* map) {
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Node* const native_context = a->LoadNativeContext(context);
|
||||
Node* const regexp_fun =
|
||||
a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
|
||||
Node* const initial_map =
|
||||
a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
|
||||
Node* const has_initialmap = a->WordEqual(map, initial_map);
|
||||
|
||||
return has_initialmap;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeStubAssembler* a) {
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
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);
|
||||
|
||||
Node* const map = ThrowIfNotJSReceiver(a, isolate, context, receiver,
|
||||
"RegExp.prototype.flags");
|
||||
|
||||
Variable var_length(a, MachineType::PointerRepresentation());
|
||||
Variable 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);
|
||||
|
||||
Label if_isunmodifiedjsregexp(a),
|
||||
if_isnotunmodifiedjsregexp(a, Label::kDeferred);
|
||||
a->Branch(IsInitialRegExpMap(a, context, map), &if_isunmodifiedjsregexp,
|
||||
&if_isnotunmodifiedjsregexp);
|
||||
|
||||
Label construct_string(a);
|
||||
a->Bind(&if_isunmodifiedjsregexp);
|
||||
{
|
||||
// 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);
|
||||
var_flags.Bind(flags_intptr);
|
||||
|
||||
Label 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); \
|
||||
} 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);
|
||||
#undef CASE_FOR_FLAG
|
||||
}
|
||||
|
||||
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());
|
||||
Label 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); \
|
||||
Label 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); \
|
||||
} 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);
|
||||
#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());
|
||||
Node* const flags_intptr = var_flags.value();
|
||||
|
||||
Variable var_offset(a, MachineType::PointerRepresentation());
|
||||
var_offset.Bind(
|
||||
a->IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
|
||||
|
||||
Label 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); \
|
||||
} 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);
|
||||
#undef CASE_FOR_FLAG
|
||||
|
||||
a->Bind(&out);
|
||||
a->Return(result);
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 21.2.5.10.
|
||||
BUILTIN(RegExpPrototypeSourceGetter) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Handle<Object> recv = args.receiver();
|
||||
if (!recv->IsJSRegExp()) {
|
||||
Handle<JSFunction> regexp_fun = isolate->regexp_function();
|
||||
if (*recv == regexp_fun->prototype()) {
|
||||
isolate->CountUsage(v8::Isolate::kRegExpPrototypeSourceGetter);
|
||||
return *isolate->factory()->NewStringFromAsciiChecked("(?:)");
|
||||
}
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kRegExpNonRegExp,
|
||||
isolate->factory()->NewStringFromAsciiChecked(
|
||||
"RegExp.prototype.source")));
|
||||
}
|
||||
|
||||
Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(recv);
|
||||
return regexp->source();
|
||||
}
|
||||
|
||||
// ES6 21.2.4.2.
|
||||
BUILTIN(RegExpPrototypeSpeciesGetter) {
|
||||
HandleScope scope(isolate);
|
||||
return *args.receiver();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag,
|
||||
v8::Isolate::UseCounterFeature counter,
|
||||
const char* method_name) {
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
|
||||
Node* const receiver = a->Parameter(0);
|
||||
Node* const context = a->Parameter(3);
|
||||
|
||||
Isolate* isolate = a->isolate();
|
||||
Node* const int_zero = a->IntPtrConstant(0);
|
||||
|
||||
// Check whether we have an unmodified regexp instance.
|
||||
Label if_isunmodifiedjsregexp(a),
|
||||
if_isnotunmodifiedjsregexp(a, Label::kDeferred);
|
||||
|
||||
a->GotoIf(a->WordIsSmi(receiver), &if_isnotunmodifiedjsregexp);
|
||||
|
||||
Node* const receiver_map = a->LoadMap(receiver);
|
||||
Node* const instance_type = a->LoadMapInstanceType(receiver_map);
|
||||
|
||||
a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)),
|
||||
&if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp);
|
||||
|
||||
a->Bind(&if_isunmodifiedjsregexp);
|
||||
{
|
||||
// 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 mask = a->IntPtrConstant(flag);
|
||||
Node* const is_global =
|
||||
a->WordNotEqual(a->WordAnd(flags_intptr, mask), int_zero);
|
||||
a->Return(a->Select(is_global, a->TrueConstant(), a->FalseConstant()));
|
||||
}
|
||||
|
||||
a->Bind(&if_isnotunmodifiedjsregexp);
|
||||
{
|
||||
Node* const native_context = a->LoadNativeContext(context);
|
||||
Node* const regexp_fun =
|
||||
a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
|
||||
Node* const initial_map = a->LoadObjectField(
|
||||
regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
|
||||
Node* const initial_prototype = a->LoadMapPrototype(initial_map);
|
||||
|
||||
Label if_isprototype(a), if_isnotprototype(a);
|
||||
a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype,
|
||||
&if_isnotprototype);
|
||||
|
||||
a->Bind(&if_isprototype);
|
||||
{
|
||||
Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter));
|
||||
a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
|
||||
a->Return(a->UndefinedConstant());
|
||||
}
|
||||
|
||||
a->Bind(&if_isnotprototype);
|
||||
{
|
||||
Node* const message_id =
|
||||
a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp));
|
||||
Node* const method_name_str = a->HeapConstant(
|
||||
isolate->factory()->NewStringFromAsciiChecked(method_name));
|
||||
a->CallRuntime(Runtime::kThrowTypeError, context, message_id,
|
||||
method_name_str);
|
||||
a->Return(a->UndefinedConstant()); // Never reached.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ES6 21.2.5.4.
|
||||
void Builtins::Generate_RegExpPrototypeGlobalGetter(CodeStubAssembler* a) {
|
||||
Generate_FlagGetter(a, JSRegExp::kGlobal,
|
||||
v8::Isolate::kRegExpPrototypeOldFlagGetter,
|
||||
"RegExp.prototype.global");
|
||||
}
|
||||
|
||||
// ES6 21.2.5.5.
|
||||
void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter(CodeStubAssembler* a) {
|
||||
Generate_FlagGetter(a, JSRegExp::kIgnoreCase,
|
||||
v8::Isolate::kRegExpPrototypeOldFlagGetter,
|
||||
"RegExp.prototype.ignoreCase");
|
||||
}
|
||||
|
||||
// ES6 21.2.5.7.
|
||||
void Builtins::Generate_RegExpPrototypeMultilineGetter(CodeStubAssembler* a) {
|
||||
Generate_FlagGetter(a, JSRegExp::kMultiline,
|
||||
v8::Isolate::kRegExpPrototypeOldFlagGetter,
|
||||
"RegExp.prototype.multiline");
|
||||
}
|
||||
|
||||
// ES6 21.2.5.12.
|
||||
void Builtins::Generate_RegExpPrototypeStickyGetter(CodeStubAssembler* a) {
|
||||
Generate_FlagGetter(a, JSRegExp::kSticky,
|
||||
v8::Isolate::kRegExpPrototypeStickyGetter,
|
||||
"RegExp.prototype.sticky");
|
||||
}
|
||||
|
||||
// ES6 21.2.5.15.
|
||||
void Builtins::Generate_RegExpPrototypeUnicodeGetter(CodeStubAssembler* a) {
|
||||
Generate_FlagGetter(a, JSRegExp::kUnicode,
|
||||
v8::Isolate::kRegExpPrototypeUnicodeGetter,
|
||||
"RegExp.prototype.unicode");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Constants for accessing RegExpLastMatchInfo.
|
||||
// TODO(jgruber): Currently, RegExpLastMatchInfo is still a JSObject maintained
|
||||
// and accessed from JS. This is a crutch until all RegExp logic is ported, then
|
||||
// we can take care of RegExpLastMatchInfo.
|
||||
|
||||
Handle<Object> GetLastMatchField(Isolate* isolate, int index) {
|
||||
Handle<JSObject> last_match_info = isolate->regexp_last_match_info();
|
||||
return JSReceiver::GetElement(isolate, last_match_info, index)
|
||||
.ToHandleChecked();
|
||||
}
|
||||
|
||||
void SetLastMatchField(Isolate* isolate, int index, Handle<Object> value) {
|
||||
Handle<JSObject> last_match_info = isolate->regexp_last_match_info();
|
||||
JSReceiver::SetElement(isolate, last_match_info, index, value, SLOPPY)
|
||||
.ToHandleChecked();
|
||||
}
|
||||
|
||||
int GetLastMatchNumberOfCaptures(Isolate* isolate) {
|
||||
Handle<Object> obj =
|
||||
GetLastMatchField(isolate, RegExpImpl::kLastCaptureCount);
|
||||
return Handle<Smi>::cast(obj)->value();
|
||||
}
|
||||
|
||||
Handle<String> GetLastMatchSubject(Isolate* isolate) {
|
||||
return Handle<String>::cast(
|
||||
GetLastMatchField(isolate, RegExpImpl::kLastSubject));
|
||||
}
|
||||
|
||||
Handle<Object> GetLastMatchInput(Isolate* isolate) {
|
||||
return GetLastMatchField(isolate, RegExpImpl::kLastInput);
|
||||
}
|
||||
|
||||
int GetLastMatchCapture(Isolate* isolate, int i) {
|
||||
Handle<Object> obj =
|
||||
GetLastMatchField(isolate, RegExpImpl::kFirstCapture + i);
|
||||
return Handle<Smi>::cast(obj)->value();
|
||||
}
|
||||
|
||||
Object* GenericCaptureGetter(Isolate* isolate, int capture) {
|
||||
HandleScope scope(isolate);
|
||||
const int index = capture * 2;
|
||||
if (index >= GetLastMatchNumberOfCaptures(isolate)) {
|
||||
return isolate->heap()->empty_string();
|
||||
}
|
||||
|
||||
const int match_start = GetLastMatchCapture(isolate, index);
|
||||
const int match_end = GetLastMatchCapture(isolate, index + 1);
|
||||
if (match_start == -1 || match_end == -1) {
|
||||
return isolate->heap()->empty_string();
|
||||
}
|
||||
|
||||
Handle<String> last_subject = GetLastMatchSubject(isolate);
|
||||
return *isolate->factory()->NewSubString(last_subject, match_start,
|
||||
match_end);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// The properties $1..$9 are the first nine capturing substrings of the last
|
||||
// successful match, or ''. The function RegExpMakeCaptureGetter will be
|
||||
// called with indices from 1 to 9.
|
||||
#define DEFINE_CAPTURE_GETTER(i) \
|
||||
BUILTIN(RegExpCapture##i##Getter) { \
|
||||
HandleScope scope(isolate); \
|
||||
return GenericCaptureGetter(isolate, i); \
|
||||
}
|
||||
DEFINE_CAPTURE_GETTER(1)
|
||||
DEFINE_CAPTURE_GETTER(2)
|
||||
DEFINE_CAPTURE_GETTER(3)
|
||||
DEFINE_CAPTURE_GETTER(4)
|
||||
DEFINE_CAPTURE_GETTER(5)
|
||||
DEFINE_CAPTURE_GETTER(6)
|
||||
DEFINE_CAPTURE_GETTER(7)
|
||||
DEFINE_CAPTURE_GETTER(8)
|
||||
DEFINE_CAPTURE_GETTER(9)
|
||||
#undef DEFINE_CAPTURE_GETTER
|
||||
|
||||
// The properties `input` and `$_` are aliases for each other. When this
|
||||
// value is set, the value it is set to is coerced to a string.
|
||||
// Getter and setter for the input.
|
||||
|
||||
BUILTIN(RegExpInputGetter) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> obj = GetLastMatchInput(isolate);
|
||||
return obj->IsUndefined(isolate) ? isolate->heap()->empty_string()
|
||||
: String::cast(*obj);
|
||||
}
|
||||
|
||||
BUILTIN(RegExpInputSetter) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> value = args.atOrUndefined(isolate, 1);
|
||||
Handle<String> str;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str,
|
||||
Object::ToString(isolate, value));
|
||||
SetLastMatchField(isolate, RegExpImpl::kLastInput, str);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
// Getters for the static properties lastMatch, lastParen, leftContext, and
|
||||
// rightContext of the RegExp constructor. The properties are computed based
|
||||
// on the captures array of the last successful match and the subject string
|
||||
// of the last successful match.
|
||||
BUILTIN(RegExpLastMatchGetter) {
|
||||
HandleScope scope(isolate);
|
||||
return GenericCaptureGetter(isolate, 0);
|
||||
}
|
||||
|
||||
BUILTIN(RegExpLastParenGetter) {
|
||||
HandleScope scope(isolate);
|
||||
const int length = GetLastMatchNumberOfCaptures(isolate);
|
||||
if (length <= 2) return isolate->heap()->empty_string(); // No captures.
|
||||
|
||||
DCHECK_EQ(0, length % 2);
|
||||
const int last_capture = (length / 2) - 1;
|
||||
|
||||
// We match the SpiderMonkey behavior: return the substring defined by the
|
||||
// last pair (after the first pair) of elements of the capture array even if
|
||||
// it is empty.
|
||||
return GenericCaptureGetter(isolate, last_capture);
|
||||
}
|
||||
|
||||
BUILTIN(RegExpLeftContextGetter) {
|
||||
HandleScope scope(isolate);
|
||||
const int start_index = GetLastMatchCapture(isolate, 0);
|
||||
Handle<String> last_subject = GetLastMatchSubject(isolate);
|
||||
return *isolate->factory()->NewSubString(last_subject, 0, start_index);
|
||||
}
|
||||
|
||||
BUILTIN(RegExpRightContextGetter) {
|
||||
HandleScope scope(isolate);
|
||||
const int start_index = GetLastMatchCapture(isolate, 1);
|
||||
Handle<String> last_subject = GetLastMatchSubject(isolate);
|
||||
const int len = last_subject->length();
|
||||
return *isolate->factory()->NewSubString(last_subject, start_index, len);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -533,8 +533,31 @@ namespace internal {
|
||||
CPP(ReflectSetPrototypeOf) \
|
||||
\
|
||||
/* RegExp */ \
|
||||
CPP(RegExpCapture1Getter) \
|
||||
CPP(RegExpCapture2Getter) \
|
||||
CPP(RegExpCapture3Getter) \
|
||||
CPP(RegExpCapture4Getter) \
|
||||
CPP(RegExpCapture5Getter) \
|
||||
CPP(RegExpCapture6Getter) \
|
||||
CPP(RegExpCapture7Getter) \
|
||||
CPP(RegExpCapture8Getter) \
|
||||
CPP(RegExpCapture9Getter) \
|
||||
CPP(RegExpConstructor) \
|
||||
CPP(RegExpInputGetter) \
|
||||
CPP(RegExpInputSetter) \
|
||||
CPP(RegExpLastMatchGetter) \
|
||||
CPP(RegExpLastParenGetter) \
|
||||
CPP(RegExpLeftContextGetter) \
|
||||
TFJ(RegExpPrototypeExec, 2) \
|
||||
TFJ(RegExpPrototypeFlagsGetter, 1) \
|
||||
TFJ(RegExpPrototypeGlobalGetter, 1) \
|
||||
TFJ(RegExpPrototypeIgnoreCaseGetter, 1) \
|
||||
TFJ(RegExpPrototypeMultilineGetter, 1) \
|
||||
CPP(RegExpPrototypeSourceGetter) \
|
||||
CPP(RegExpPrototypeSpeciesGetter) \
|
||||
TFJ(RegExpPrototypeStickyGetter, 1) \
|
||||
TFJ(RegExpPrototypeUnicodeGetter, 1) \
|
||||
CPP(RegExpRightContextGetter) \
|
||||
\
|
||||
/* SharedArrayBuffer */ \
|
||||
CPP(SharedArrayBufferPrototypeGetByteLength) \
|
||||
|
@ -23,6 +23,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(BooleanMap, BooleanMap) \
|
||||
V(empty_string, EmptyString) \
|
||||
V(EmptyFixedArray, EmptyFixedArray) \
|
||||
V(FalseValue, False) \
|
||||
V(FixedArrayMap, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, FixedDoubleArrayMap) \
|
||||
@ -31,6 +32,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(NanValue, Nan) \
|
||||
V(NullValue, Null) \
|
||||
V(TheHoleValue, TheHole) \
|
||||
V(TrueValue, True) \
|
||||
V(UndefinedValue, Undefined)
|
||||
|
||||
// Provides JavaScript-specific "macro-assembler" functionality on top of the
|
||||
|
@ -140,6 +140,7 @@
|
||||
V(source_url_string, "source_url") \
|
||||
V(stack_string, "stack") \
|
||||
V(stackTraceLimit_string, "stackTraceLimit") \
|
||||
V(sticky_string, "sticky") \
|
||||
V(strict_compare_ic_string, "===") \
|
||||
V(string_string, "string") \
|
||||
V(String_string, "String") \
|
||||
@ -163,6 +164,7 @@
|
||||
V(Uint8x16_string, "Uint8x16") \
|
||||
V(undefined_string, "undefined") \
|
||||
V(undefined_to_string, "[object Undefined]") \
|
||||
V(unicode_string, "unicode") \
|
||||
V(URIError_string, "URIError") \
|
||||
V(valueOf_string, "valueOf") \
|
||||
V(values_string, "values") \
|
||||
|
227
src/js/regexp.js
227
src/js/regexp.js
@ -777,173 +777,8 @@ function RegExpSubclassSearch(string) {
|
||||
%FunctionRemovePrototype(RegExpSubclassSearch);
|
||||
|
||||
|
||||
// Getters for the static properties lastMatch, lastParen, leftContext, and
|
||||
// rightContext of the RegExp constructor. The properties are computed based
|
||||
// on the captures array of the last successful match and the subject string
|
||||
// of the last successful match.
|
||||
function RegExpGetLastMatch() {
|
||||
var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
|
||||
return %_SubString(regExpSubject,
|
||||
RegExpLastMatchInfo[CAPTURE0],
|
||||
RegExpLastMatchInfo[CAPTURE1]);
|
||||
}
|
||||
|
||||
|
||||
function RegExpGetLastParen() {
|
||||
var length = NUMBER_OF_CAPTURES(RegExpLastMatchInfo);
|
||||
if (length <= 2) return ''; // There were no captures.
|
||||
// We match the SpiderMonkey behavior: return the substring defined by the
|
||||
// last pair (after the first pair) of elements of the capture array even if
|
||||
// it is empty.
|
||||
var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo);
|
||||
var start = RegExpLastMatchInfo[CAPTURE(length - 2)];
|
||||
var end = RegExpLastMatchInfo[CAPTURE(length - 1)];
|
||||
if (start != -1 && end != -1) {
|
||||
return %_SubString(regExpSubject, start, end);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function RegExpGetLeftContext() {
|
||||
var start_index;
|
||||
var subject;
|
||||
start_index = RegExpLastMatchInfo[CAPTURE0];
|
||||
subject = LAST_SUBJECT(RegExpLastMatchInfo);
|
||||
return %_SubString(subject, 0, start_index);
|
||||
}
|
||||
|
||||
|
||||
function RegExpGetRightContext() {
|
||||
var start_index;
|
||||
var subject;
|
||||
start_index = RegExpLastMatchInfo[CAPTURE1];
|
||||
subject = LAST_SUBJECT(RegExpLastMatchInfo);
|
||||
return %_SubString(subject, start_index, subject.length);
|
||||
}
|
||||
|
||||
|
||||
// The properties $1..$9 are the first nine capturing substrings of the last
|
||||
// successful match, or ''. The function RegExpMakeCaptureGetter will be
|
||||
// called with indices from 1 to 9.
|
||||
function RegExpMakeCaptureGetter(n) {
|
||||
return function foo() {
|
||||
var index = n * 2;
|
||||
if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return '';
|
||||
var matchStart = RegExpLastMatchInfo[CAPTURE(index)];
|
||||
var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)];
|
||||
if (matchStart == -1 || matchEnd == -1) return '';
|
||||
return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.3.
|
||||
function RegExpGetFlags() {
|
||||
if (!IS_RECEIVER(this)) {
|
||||
throw %make_type_error(
|
||||
kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
|
||||
}
|
||||
var result = '';
|
||||
if (this.global) result += 'g';
|
||||
if (this.ignoreCase) result += 'i';
|
||||
if (this.multiline) result += 'm';
|
||||
if (this.unicode) result += 'u';
|
||||
if (this.sticky) result += 'y';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.4.
|
||||
function RegExpGetGlobal() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
||||
return UNDEFINED;
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global");
|
||||
}
|
||||
return TO_BOOLEAN(REGEXP_GLOBAL(this));
|
||||
}
|
||||
%SetForceInlineFlag(RegExpGetGlobal);
|
||||
|
||||
|
||||
// ES6 21.2.5.5.
|
||||
function RegExpGetIgnoreCase() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
||||
return UNDEFINED;
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
|
||||
}
|
||||
return TO_BOOLEAN(REGEXP_IGNORE_CASE(this));
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.7.
|
||||
function RegExpGetMultiline() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
|
||||
return UNDEFINED;
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline");
|
||||
}
|
||||
return TO_BOOLEAN(REGEXP_MULTILINE(this));
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.10.
|
||||
function RegExpGetSource() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeSourceGetter);
|
||||
return "(?:)";
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source");
|
||||
}
|
||||
return REGEXP_SOURCE(this);
|
||||
}
|
||||
|
||||
|
||||
// ES6 21.2.5.12.
|
||||
function RegExpGetSticky() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeStickyGetter);
|
||||
return UNDEFINED;
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky");
|
||||
}
|
||||
return TO_BOOLEAN(REGEXP_STICKY(this));
|
||||
}
|
||||
%SetForceInlineFlag(RegExpGetSticky);
|
||||
|
||||
|
||||
// ES6 21.2.5.15.
|
||||
function RegExpGetUnicode() {
|
||||
if (!IS_REGEXP(this)) {
|
||||
if (this === GlobalRegExpPrototype) {
|
||||
%IncrementUseCounter(kRegExpPrototypeUnicodeGetter);
|
||||
return UNDEFINED;
|
||||
}
|
||||
throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode");
|
||||
}
|
||||
return TO_BOOLEAN(REGEXP_UNICODE(this));
|
||||
}
|
||||
%SetForceInlineFlag(RegExpGetUnicode);
|
||||
|
||||
|
||||
function RegExpSpecies() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies);
|
||||
|
||||
utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
|
||||
"test", RegExpSubclassTest,
|
||||
"toString", RegExpToString,
|
||||
@ -954,68 +789,6 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
|
||||
splitSymbol, RegExpSubclassSplit,
|
||||
]);
|
||||
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'ignoreCase', RegExpGetIgnoreCase);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'multiline', RegExpGetMultiline);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'source', RegExpGetSource);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky);
|
||||
utils.InstallGetter(GlobalRegExp.prototype, 'unicode', RegExpGetUnicode);
|
||||
|
||||
// The properties `input` and `$_` are aliases for each other. When this
|
||||
// value is set the value it is set to is coerced to a string.
|
||||
// Getter and setter for the input.
|
||||
var RegExpGetInput = function() {
|
||||
var regExpInput = LAST_INPUT(RegExpLastMatchInfo);
|
||||
return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
|
||||
};
|
||||
var RegExpSetInput = function(string) {
|
||||
LAST_INPUT(RegExpLastMatchInfo) = TO_STRING(string);
|
||||
};
|
||||
|
||||
// TODO(jgruber): All of these getters and setters were intended to be installed
|
||||
// with various attributes (e.g. DONT_ENUM | DONT_DELETE), but
|
||||
// InstallGetterSetter had a bug which ignored the passed attributes and
|
||||
// simply installed as DONT_ENUM instead. We might want to change back
|
||||
// to the intended attributes at some point.
|
||||
// On the other hand, installing attributes as DONT_ENUM matches the draft
|
||||
// specification at
|
||||
// https://github.com/claudepache/es-regexp-legacy-static-properties
|
||||
|
||||
%OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22);
|
||||
utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput,
|
||||
DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput,
|
||||
DONT_ENUM);
|
||||
|
||||
|
||||
var NoOpSetter = function(ignored) {};
|
||||
|
||||
|
||||
// Static properties set by a successful match.
|
||||
utils.InstallGetterSetter(GlobalRegExp, 'lastMatch', RegExpGetLastMatch,
|
||||
NoOpSetter, DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, '$&', RegExpGetLastMatch, NoOpSetter,
|
||||
DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, 'lastParen', RegExpGetLastParen,
|
||||
NoOpSetter, DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, '$+', RegExpGetLastParen, NoOpSetter,
|
||||
DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, 'leftContext', RegExpGetLeftContext,
|
||||
NoOpSetter, DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, '$`', RegExpGetLeftContext, NoOpSetter,
|
||||
DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, 'rightContext', RegExpGetRightContext,
|
||||
NoOpSetter, DONT_ENUM);
|
||||
utils.InstallGetterSetter(GlobalRegExp, "$'", RegExpGetRightContext, NoOpSetter,
|
||||
DONT_ENUM);
|
||||
|
||||
for (var i = 1; i < 10; ++i) {
|
||||
utils.InstallGetterSetter(GlobalRegExp, '$' + i, RegExpMakeCaptureGetter(i),
|
||||
NoOpSetter, DONT_ENUM);
|
||||
}
|
||||
%ToFastProperties(GlobalRegExp);
|
||||
|
||||
%InstallToContext(["regexp_last_match_info", RegExpLastMatchInfo]);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -100,6 +100,23 @@ RUNTIME_FUNCTION(Runtime_ThrowStackOverflow) {
|
||||
return isolate->StackOverflow();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowTypeError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_LE(1, args.length());
|
||||
CONVERT_SMI_ARG_CHECKED(message_id_smi, 0);
|
||||
|
||||
Handle<Object> undefined = isolate->factory()->undefined_value();
|
||||
Handle<Object> arg0 = (args.length() > 1) ? args.at<Object>(1) : undefined;
|
||||
Handle<Object> arg1 = (args.length() > 2) ? args.at<Object>(2) : undefined;
|
||||
Handle<Object> arg2 = (args.length() > 3) ? args.at<Object>(3) : undefined;
|
||||
|
||||
MessageTemplate::Template message_id =
|
||||
static_cast<MessageTemplate::Template>(message_id_smi);
|
||||
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(isolate,
|
||||
NewTypeError(message_id, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(2, args.length());
|
||||
|
@ -325,6 +325,7 @@ namespace internal {
|
||||
F(ThrowNotGeneric, 1, 1) \
|
||||
F(ThrowReferenceError, 1, 1) \
|
||||
F(ThrowStackOverflow, 0, 1) \
|
||||
F(ThrowTypeError, -1 /* >= 1 */, 1) \
|
||||
F(ThrowWasmError, 2, 1) \
|
||||
F(ThrowUndefinedOrNullToObject, 1, 1) \
|
||||
F(Typeof, 1, 1) \
|
||||
|
Loading…
Reference in New Issue
Block a user