mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-23 15:47:30 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
6db7856f7f
10 changed files with 280 additions and 93 deletions
|
|
@ -31,8 +31,30 @@ using mozilla::Maybe;
|
||||||
|
|
||||||
using CapturesVector = GCVector<Value, 4>;
|
using CapturesVector = GCVector<Value, 4>;
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate an object for the |.groups| or |.indices.groups| property
|
||||||
|
// of a regexp match result.
|
||||||
|
static PlainObject* CreateGroupsObject(JSContext* cx,
|
||||||
|
HandlePlainObject groupsTemplate)
|
||||||
|
{
|
||||||
|
PlainObject* result = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
|
||||||
|
result->setGroup(groupsTemplate->group());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch a group index corresponding to a |key| from the template object
|
||||||
|
static uint32_t GetNamedCaptureIndex(JSContext* cx, HandlePlainObject groupsTemplate, HandleId key)
|
||||||
|
{
|
||||||
|
RootedValue ival(cx);
|
||||||
|
|
||||||
|
if (!NativeGetProperty(cx, groupsTemplate, key, &ival))
|
||||||
|
return -1;
|
||||||
|
return ival.toInt32();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ES 2021 draft 21.2.5.2.2: Steps 16-28
|
* Implements RegExpBuiltinExec: Steps 18-35
|
||||||
* https://tc39.es/ecma262/#sec-regexpbuiltinexec
|
* https://tc39.es/ecma262/#sec-regexpbuiltinexec
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
|
|
@ -51,24 +73,61 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
|
||||||
* input: input string
|
* input: input string
|
||||||
* index: start index for the match
|
* index: start index for the match
|
||||||
* groups: named capture groups for the match
|
* groups: named capture groups for the match
|
||||||
|
* indices: capture indices for the match, if required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool hasIndices = re.hasIndices();
|
||||||
|
|
||||||
/* Get the templateObject that defines the shape and type of the output object */
|
/* Get the templateObject that defines the shape and type of the output object */
|
||||||
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
|
RegExpCompartment::ResultTemplateKind kind =
|
||||||
|
hasIndices ? RegExpCompartment::ResultTemplateKind::WithIndices
|
||||||
|
: RegExpCompartment::ResultTemplateKind::Normal;
|
||||||
|
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx, kind);
|
||||||
if (!templateObject)
|
if (!templateObject)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Step 16
|
// Steps 18-19
|
||||||
size_t numPairs = matches.length();
|
size_t numPairs = matches.length();
|
||||||
MOZ_ASSERT(numPairs > 0);
|
MOZ_ASSERT(numPairs > 0);
|
||||||
|
|
||||||
/* Step 18-19. */
|
// Step 34a (reordered): Allocate and initialize the indices object if needed.
|
||||||
|
// This is an inlined implementation of MakeIndicesArray:
|
||||||
|
// https://tc39.es/ecma262/#sec-makeindicesarray
|
||||||
|
RootedArrayObject indices(cx);
|
||||||
|
RootedPlainObject indicesGroups(cx);
|
||||||
|
if (hasIndices) {
|
||||||
|
// MakeIndicesArray: step 8
|
||||||
|
ArrayObject* indicesTemplate =
|
||||||
|
cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx, RegExpCompartment::ResultTemplateKind::Indices);
|
||||||
|
if (!indicesTemplate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
indices = NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, indicesTemplate);
|
||||||
|
if (!indices) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeIndicesArray: steps 10-12
|
||||||
|
if (re.numNamedCaptures() > 0) {
|
||||||
|
RootedPlainObject groupsTemplate(cx, re.getGroupsTemplate());
|
||||||
|
indicesGroups = CreateGroupsObject(cx, groupsTemplate);
|
||||||
|
if (!indicesGroups) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
indices->setSlot(0, ObjectValue(*indicesGroups));
|
||||||
|
} else {
|
||||||
|
indices->setSlot(0, UndefinedValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 20-21: Allocate the match result object.
|
||||||
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
|
RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
|
||||||
if (!arr)
|
if (!arr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Steps 22-23 and 27 a-e
|
// Steps 28-29 and 33 a-d: Initialize the elements of the match result.
|
||||||
* Store a Value for each pair. */
|
// Store a Value for each match pair.
|
||||||
|
// Merged with MakeIndicesArray: step 13 a-d. (Step 13.e is implemented below.)
|
||||||
for (size_t i = 0; i < numPairs; i++) {
|
for (size_t i = 0; i < numPairs; i++) {
|
||||||
const MatchPair& pair = matches[i];
|
const MatchPair& pair = matches[i];
|
||||||
|
|
||||||
|
|
@ -76,24 +135,40 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
|
||||||
MOZ_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
|
MOZ_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
|
||||||
arr->setDenseInitializedLength(i + 1);
|
arr->setDenseInitializedLength(i + 1);
|
||||||
arr->initDenseElement(i, UndefinedValue());
|
arr->initDenseElement(i, UndefinedValue());
|
||||||
|
if (hasIndices) {
|
||||||
|
indices->setDenseInitializedLength(i + 1);
|
||||||
|
indices->initDenseElement(i, UndefinedValue());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
JSLinearString* str = NewDependentString(cx, input, pair.start, pair.length());
|
JSLinearString* str = NewDependentString(cx, input, pair.start, pair.length());
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
arr->setDenseInitializedLength(i + 1);
|
arr->setDenseInitializedLength(i + 1);
|
||||||
arr->initDenseElement(i, StringValue(str));
|
arr->initDenseElement(i, StringValue(str));
|
||||||
|
|
||||||
|
if (hasIndices) {
|
||||||
|
RootedArrayObject indexPair(cx, NewDenseFullyAllocatedArray(cx, 2));
|
||||||
|
if (!indexPair) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
indexPair->setDenseInitializedLength(2);
|
||||||
|
indexPair->initDenseElement(0, Int32Value(pair.start));
|
||||||
|
indexPair->initDenseElement(1, Int32Value(pair.limit));
|
||||||
|
|
||||||
|
indices->setDenseInitializedLength(i + 1);
|
||||||
|
indices->initDenseElement(i, ObjectValue(*indexPair));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 24 (reordered)
|
// Steps 30-31 (reordered): Allocate the groups object (if needed).
|
||||||
RootedPlainObject groups(cx);
|
RootedPlainObject groups(cx);
|
||||||
if (re.numNamedCaptures() > 0) {
|
if (re.numNamedCaptures() > 0) {
|
||||||
// construct a new object from the template saved on RegExpShared
|
// construct a new object from the template saved on RegExpShared
|
||||||
RootedPlainObject groupsTemplate(cx, re.getGroupsTemplate());
|
RootedPlainObject groupsTemplate(cx, re.getGroupsTemplate());
|
||||||
groups = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
|
groups = CreateGroupsObject(cx, groupsTemplate);
|
||||||
groups->setGroup(groupsTemplate->group());
|
|
||||||
|
|
||||||
// Step 27 f.
|
// Step 33 e-f
|
||||||
// The groups template object stores the names of the named captures in the
|
// The groups template object stores the names of the named captures in the
|
||||||
// the order in which they are defined.
|
// the order in which they are defined.
|
||||||
// Grab the index into the match vector from the template object and define the
|
// Grab the index into the match vector from the template object and define the
|
||||||
|
|
@ -104,33 +179,46 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(keys.length() == re.numNamedCaptures());
|
MOZ_ASSERT(keys.length() == re.numNamedCaptures());
|
||||||
RootedId key(cx);
|
RootedId key(cx);
|
||||||
RootedValue ival(cx);
|
|
||||||
RootedValue val(cx);
|
RootedValue val(cx);
|
||||||
for (size_t i = 0; i < keys.length(); i++) {
|
for (size_t i = 0; i < keys.length(); i++) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
// fetch the group's match index...
|
uint32_t idx = GetNamedCaptureIndex(cx, groupsTemplate, key);
|
||||||
if (!NativeGetProperty(cx, groupsTemplate, key, &ival))
|
MOZ_ASSERT(idx >= 0);
|
||||||
return false;
|
// Copy the matched string to |.groups|
|
||||||
// ... and set it on groups
|
val = arr->getDenseElement(idx);
|
||||||
val = arr->getDenseElement(ival.toInt32());
|
|
||||||
if (!NativeDefineProperty(cx, groups, key, val, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
if (!NativeDefineProperty(cx, groups, key, val, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// MakeIndicesArray: Step 13.e (reordered)
|
||||||
|
// If we have an |.indices|, copy the information to |.indices.groups|
|
||||||
|
if (hasIndices) {
|
||||||
|
val = indices->getDenseElement(idx);
|
||||||
|
if (!NativeDefineDataProperty(cx, indicesGroups, key, val,
|
||||||
|
JSPROP_ENUMERATE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 20 (reordered).
|
/* Step 22 (reordered).
|
||||||
* Set the |index| property. (TemplateObject positions it in slot 0) */
|
* Set the |index| property. (TemplateObject positions it in slot 0) */
|
||||||
arr->setSlot(0, Int32Value(matches[0].start));
|
arr->setSlot(0, Int32Value(matches[0].start));
|
||||||
|
|
||||||
/* Step 21 (reordered).
|
/* Step 23 (reordered).
|
||||||
* Set the |input| property. (TemplateObject positions it in slot 1) */
|
* Set the |input| property. (TemplateObject positions it in slot 1) */
|
||||||
arr->setSlot(1, StringValue(input));
|
arr->setSlot(1, StringValue(input));
|
||||||
|
|
||||||
// Steps 25-26 (reordered)
|
// Step 32 (reordered)
|
||||||
// Set the |groups| property.
|
// Set the |groups| property.
|
||||||
arr->setSlot(2, groups ? ObjectValue(*groups) : UndefinedValue());
|
arr->setSlot(2, groups ? ObjectValue(*groups) : UndefinedValue());
|
||||||
|
|
||||||
|
// Step 34b (reordered)
|
||||||
|
// Set the |indices| property.
|
||||||
|
if (hasIndices) {
|
||||||
|
arr->setSlot(3, ObjectValue(*indices));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
RootedValue test(cx);
|
RootedValue test(cx);
|
||||||
RootedId id(cx, NameToId(cx->names().index));
|
RootedId id(cx, NameToId(cx->names().index));
|
||||||
|
|
@ -143,7 +231,7 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re,
|
||||||
MOZ_ASSERT(test == arr->getSlot(1));
|
MOZ_ASSERT(test == arr->getSlot(1));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Step 25. */
|
/* Step 35. */
|
||||||
rval.setObject(*arr);
|
rval.setObject(*arr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -818,15 +906,42 @@ js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||||
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_unicode_impl>(cx, args);
|
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_unicode_impl>(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ES 2022 22.2.5.6.
|
||||||
|
MOZ_ALWAYS_INLINE bool
|
||||||
|
regexp_hasIndices_impl(JSContext* cx, const CallArgs& args)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
|
||||||
|
|
||||||
|
// Step 2.a.
|
||||||
|
if (!IsRegExpObject(args.thisv())) {
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 3-5.
|
||||||
|
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
|
||||||
|
args.rval().setBoolean(reObj->hasIndices());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||||
|
{
|
||||||
|
// Steps 1-3.
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_hasIndices_impl>(cx, args);
|
||||||
|
}
|
||||||
|
|
||||||
const JSPropertySpec js::regexp_properties[] = {
|
const JSPropertySpec js::regexp_properties[] = {
|
||||||
JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
|
JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
|
||||||
|
JS_PSG("hasIndices", regexp_hasIndices, 0),
|
||||||
JS_PSG("global", regexp_global, 0),
|
JS_PSG("global", regexp_global, 0),
|
||||||
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
|
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
|
||||||
JS_PSG("multiline", regexp_multiline, 0),
|
JS_PSG("multiline", regexp_multiline, 0),
|
||||||
|
JS_PSG("dotAll", regexp_dotAll, 0),
|
||||||
JS_PSG("source", regexp_source, 0),
|
JS_PSG("source", regexp_source, 0),
|
||||||
JS_PSG("sticky", regexp_sticky, 0),
|
JS_PSG("sticky", regexp_sticky, 0),
|
||||||
JS_PSG("unicode", regexp_unicode, 0),
|
JS_PSG("unicode", regexp_unicode, 0),
|
||||||
JS_PSG("dotAll", regexp_dotAll, 0),
|
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1802,6 +1917,13 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
|
||||||
if (!IsSelfHostedFunctionWithName(flagsGetter, cx->names().RegExpFlagsGetter))
|
if (!IsSelfHostedFunctionWithName(flagsGetter, cx->names().RegExpFlagsGetter))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
JSNative hasIndicesGetter;
|
||||||
|
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().hasIndices), &hasIndicesGetter))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (hasIndicesGetter != regexp_hasIndices)
|
||||||
|
return false;
|
||||||
|
|
||||||
JSNative globalGetter;
|
JSNative globalGetter;
|
||||||
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().global), &globalGetter))
|
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().global), &globalGetter))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -124,17 +124,19 @@ extern const JSFunctionSpec regexp_methods[];
|
||||||
|
|
||||||
// Used in RegExpObject::isOriginalFlagGetter.
|
// Used in RegExpObject::isOriginalFlagGetter.
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
|
regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
extern MOZ_MUST_USE bool
|
||||||
regexp_global(JSContext* cx, unsigned argc, JS::Value* vp);
|
regexp_global(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp);
|
regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp);
|
regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
|
regexp_dotAll(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
extern MOZ_MUST_USE bool
|
||||||
regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp);
|
regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp);
|
regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
|
||||||
regexp_dotAll(JSContext* cx, unsigned argc, JS::Value* vp);
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags
|
// ES2022 22.2.5.4 get RegExp.prototype.flags
|
||||||
// Updated for ES2018 /s (dotAll)
|
|
||||||
function RegExpFlagsGetter() {
|
function RegExpFlagsGetter() {
|
||||||
// Steps 1-2.
|
// Steps 1-2.
|
||||||
var R = this;
|
var R = this;
|
||||||
|
|
@ -13,31 +12,36 @@ function RegExpFlagsGetter() {
|
||||||
// Step 3.
|
// Step 3.
|
||||||
var result = "";
|
var result = "";
|
||||||
|
|
||||||
// Steps 4-6.
|
// Steps 4-5.
|
||||||
|
if (R.hasIndices)
|
||||||
|
result += "d";
|
||||||
|
|
||||||
|
// Steps 6-7.
|
||||||
if (R.global)
|
if (R.global)
|
||||||
result += "g";
|
result += "g";
|
||||||
|
|
||||||
// Steps 7-9.
|
// Steps 8-9.
|
||||||
if (R.ignoreCase)
|
if (R.ignoreCase)
|
||||||
result += "i";
|
result += "i";
|
||||||
|
|
||||||
// Steps 10-12.
|
// Steps 10-11.
|
||||||
if (R.multiline)
|
if (R.multiline)
|
||||||
result += "m";
|
result += "m";
|
||||||
|
|
||||||
// Steps 13-15.
|
// Steps 12-13.
|
||||||
if (R.unicode)
|
|
||||||
result += "u";
|
|
||||||
|
|
||||||
// Steps 16-18.
|
|
||||||
if (R.sticky)
|
|
||||||
result += "y";
|
|
||||||
|
|
||||||
// ES2018
|
|
||||||
if (R.dotAll)
|
if (R.dotAll)
|
||||||
result += "s";
|
result += "s";
|
||||||
|
|
||||||
// Step 19.
|
// Steps 14-15.
|
||||||
|
if (R.unicode)
|
||||||
|
result += "u";
|
||||||
|
|
||||||
|
// Steps 16-17.
|
||||||
|
if (R.sticky)
|
||||||
|
result += "y";
|
||||||
|
|
||||||
|
|
||||||
|
// Step 18.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
_SetCanonicalName(RegExpFlagsGetter, "get flags");
|
_SetCanonicalName(RegExpFlagsGetter, "get flags");
|
||||||
|
|
@ -227,9 +231,11 @@ function RegExpGlobalMatchOpt(rx, S, fullUnicode) {
|
||||||
// Checks if following properties and getters are not modified, and accessing
|
// Checks if following properties and getters are not modified, and accessing
|
||||||
// them not observed by content script:
|
// them not observed by content script:
|
||||||
// * flags
|
// * flags
|
||||||
|
// * hasIndices
|
||||||
// * global
|
// * global
|
||||||
// * ignoreCase
|
// * ignoreCase
|
||||||
// * multiline
|
// * multiline
|
||||||
|
// * dotAll
|
||||||
// * sticky
|
// * sticky
|
||||||
// * unicode
|
// * unicode
|
||||||
// * exec
|
// * exec
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@
|
||||||
#define REGEXP_STICKY_FLAG 0x08
|
#define REGEXP_STICKY_FLAG 0x08
|
||||||
#define REGEXP_UNICODE_FLAG 0x10
|
#define REGEXP_UNICODE_FLAG 0x10
|
||||||
#define REGEXP_DOTALL_FLAG 0x20
|
#define REGEXP_DOTALL_FLAG 0x20
|
||||||
|
#define REGEXP_HASINDICES_FLAG 0x40
|
||||||
|
|
||||||
#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0
|
#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0
|
||||||
#define REGEXP_STRING_ITERATOR_STRING_SLOT 1
|
#define REGEXP_STRING_ITERATOR_STRING_SLOT 1
|
||||||
|
|
|
||||||
|
|
@ -2083,7 +2083,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!peekChar(&c))
|
if (!peekChar(&c))
|
||||||
goto error;
|
goto error;
|
||||||
if (c == 'g' && !(reflags & GlobalFlag))
|
if (c == 'd' && !(reflags & HasIndicesFlag))
|
||||||
|
reflags = RegExpFlag(reflags | HasIndicesFlag);
|
||||||
|
else if (c == 'g' && !(reflags & GlobalFlag))
|
||||||
reflags = RegExpFlag(reflags | GlobalFlag);
|
reflags = RegExpFlag(reflags | GlobalFlag);
|
||||||
else if (c == 'i' && !(reflags & IgnoreCaseFlag))
|
else if (c == 'i' && !(reflags & IgnoreCaseFlag))
|
||||||
reflags = RegExpFlag(reflags | IgnoreCaseFlag);
|
reflags = RegExpFlag(reflags | IgnoreCaseFlag);
|
||||||
|
|
|
||||||
|
|
@ -1545,6 +1545,11 @@ JitCompartment::generateRegExpMatcherStub(JSContext* cx)
|
||||||
ImmWord(0),
|
ImmWord(0),
|
||||||
&oolEntry);
|
&oolEntry);
|
||||||
|
|
||||||
|
// Similarly, if the |hasIndices| flag is set, fall back to the OOL stub.
|
||||||
|
masm.branchTest32(Assembler::NonZero,
|
||||||
|
Address(shared, RegExpShared::offsetOfFlags()),
|
||||||
|
Imm32(int32_t(HasIndicesFlag)), &oolEntry);
|
||||||
|
|
||||||
// Construct the result.
|
// Construct the result.
|
||||||
Register object = temp1;
|
Register object = temp1;
|
||||||
Label matchResultFallback, matchResultJoin;
|
Label matchResultFallback, matchResultJoin;
|
||||||
|
|
|
||||||
|
|
@ -5824,12 +5824,13 @@ JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate);
|
||||||
/*
|
/*
|
||||||
* Regular Expressions.
|
* Regular Expressions.
|
||||||
*/
|
*/
|
||||||
#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */
|
#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */
|
||||||
#define JSREG_GLOB 0x02u /* global exec, creates array of matches */
|
#define JSREG_GLOB 0x02u /* global exec, creates array of matches */
|
||||||
#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */
|
#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */
|
||||||
#define JSREG_STICKY 0x08u /* only match starting at lastIndex */
|
#define JSREG_STICKY 0x08u /* only match starting at lastIndex */
|
||||||
#define JSREG_UNICODE 0x10u /* unicode */
|
#define JSREG_UNICODE 0x10u /* unicode */
|
||||||
#define JSREG_DOTALL 0x20u /* match . to everything including newlines */
|
#define JSREG_DOTALL 0x20u /* match . to everything including newlines */
|
||||||
|
#define JSREG_HASINDICES 0x40u /* add .indices property to the match result */
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSObject*)
|
extern JS_PUBLIC_API(JSObject*)
|
||||||
JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags);
|
JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags);
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@
|
||||||
macro(groups, groups, "groups") \
|
macro(groups, groups, "groups") \
|
||||||
macro(Handle, Handle, "Handle") \
|
macro(Handle, Handle, "Handle") \
|
||||||
macro(has, has, "has") \
|
macro(has, has, "has") \
|
||||||
|
macro(hasIndices, hasIndices, "hasIndices") \
|
||||||
macro(hasOwn, hasOwn, "hasOwn") \
|
macro(hasOwn, hasOwn, "hasOwn") \
|
||||||
macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
|
macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
|
||||||
macro(highWaterMark, highWaterMark, "highWaterMark") \
|
macro(highWaterMark, highWaterMark, "highWaterMark") \
|
||||||
|
|
@ -197,6 +198,7 @@
|
||||||
macro(includes, includes, "includes") \
|
macro(includes, includes, "includes") \
|
||||||
macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \
|
macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \
|
||||||
macro(index, index, "index") \
|
macro(index, index, "index") \
|
||||||
|
macro(indices, indices, "indices") \
|
||||||
macro(infinity, infinity, "infinity") \
|
macro(infinity, infinity, "infinity") \
|
||||||
macro(Infinity, Infinity, "Infinity") \
|
macro(Infinity, Infinity, "Infinity") \
|
||||||
macro(InitializeCollator, InitializeCollator, "InitializeCollator") \
|
macro(InitializeCollator, InitializeCollator, "InitializeCollator") \
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
|
||||||
JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
|
JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
|
||||||
JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE);
|
JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE);
|
||||||
JS_STATIC_ASSERT(DotAllFlag == JSREG_DOTALL);
|
JS_STATIC_ASSERT(DotAllFlag == JSREG_DOTALL);
|
||||||
|
JS_STATIC_ASSERT(HasIndicesFlag == JSREG_HASINDICES);
|
||||||
|
|
||||||
RegExpObject*
|
RegExpObject*
|
||||||
js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
|
js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
|
||||||
|
|
@ -136,6 +137,10 @@ RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp,
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
||||||
{
|
{
|
||||||
|
if (native == regexp_hasIndices) {
|
||||||
|
*mask = HasIndicesFlag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (native == regexp_global) {
|
if (native == regexp_global) {
|
||||||
*mask = GlobalFlag;
|
*mask = GlobalFlag;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -148,6 +153,10 @@ RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
||||||
*mask = MultilineFlag;
|
*mask = MultilineFlag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (native == regexp_dotAll) {
|
||||||
|
*mask = DotAllFlag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (native == regexp_sticky) {
|
if (native == regexp_sticky) {
|
||||||
*mask = StickyFlag;
|
*mask = StickyFlag;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -156,10 +165,6 @@ RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
||||||
*mask = UnicodeFlag;
|
*mask = UnicodeFlag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (native == regexp_dotAll) {
|
|
||||||
*mask = DotAllFlag;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -488,12 +493,16 @@ RegExpObject::toString(JSContext* cx) const
|
||||||
sb.infallibleAppend('/');
|
sb.infallibleAppend('/');
|
||||||
|
|
||||||
// Steps 5-7.
|
// Steps 5-7.
|
||||||
|
if (hasIndices() && !sb.append('d'))
|
||||||
|
return nullptr;
|
||||||
if (global() && !sb.append('g'))
|
if (global() && !sb.append('g'))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (ignoreCase() && !sb.append('i'))
|
if (ignoreCase() && !sb.append('i'))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (multiline() && !sb.append('m'))
|
if (multiline() && !sb.append('m'))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
if (dotAll() && !sb.append('s'))
|
||||||
|
return nullptr;
|
||||||
if (unicode() && !sb.append('u'))
|
if (unicode() && !sb.append('u'))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (sticky() && !sb.append('y'))
|
if (sticky() && !sb.append('y'))
|
||||||
|
|
@ -1288,10 +1297,13 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||||
|
|
||||||
RegExpCompartment::RegExpCompartment(Zone* zone)
|
RegExpCompartment::RegExpCompartment(Zone* zone)
|
||||||
: set_(zone, Set(zone->runtimeFromMainThread())),
|
: set_(zone, Set(zone->runtimeFromMainThread())),
|
||||||
matchResultTemplateObject_(nullptr),
|
|
||||||
optimizableRegExpPrototypeShape_(nullptr),
|
optimizableRegExpPrototypeShape_(nullptr),
|
||||||
optimizableRegExpInstanceShape_(nullptr)
|
optimizableRegExpInstanceShape_(nullptr)
|
||||||
{}
|
{
|
||||||
|
for (auto& templateObj : matchResultTemplateObjects_) {
|
||||||
|
templateObj = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RegExpCompartment::~RegExpCompartment()
|
RegExpCompartment::~RegExpCompartment()
|
||||||
{
|
{
|
||||||
|
|
@ -1299,38 +1311,53 @@ RegExpCompartment::~RegExpCompartment()
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayObject*
|
ArrayObject*
|
||||||
RegExpCompartment::createMatchResultTemplateObject(JSContext* cx)
|
RegExpCompartment::createMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!matchResultTemplateObject_);
|
MOZ_ASSERT(!matchResultTemplateObjects_[kind]);
|
||||||
|
|
||||||
/* Create template array object */
|
/* Create template array object */
|
||||||
RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
|
RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
|
||||||
nullptr, TenuredObject));
|
nullptr, TenuredObject));
|
||||||
if (!templateObject)
|
if (!templateObject) {
|
||||||
return matchResultTemplateObject_; // = nullptr
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new group for the template.
|
// Create a new group for the template.
|
||||||
Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
|
Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
|
||||||
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto);
|
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto);
|
||||||
if (!group)
|
if (!group)
|
||||||
return matchResultTemplateObject_; // = nullptr
|
return nullptr;
|
||||||
templateObject->setGroup(group);
|
templateObject->setGroup(group);
|
||||||
|
|
||||||
|
if (kind == ResultTemplateKind::Indices) {
|
||||||
|
/* The |indices| array only has a |groups| property. */
|
||||||
|
RootedValue groupsVal(cx, UndefinedValue());
|
||||||
|
if (!NativeDefineProperty(cx, templateObject, cx->names().groups,
|
||||||
|
groupsVal, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
AddTypePropertyId(cx, templateObject, NameToId(cx->names().groups), TypeSet::AnyObjectType());
|
||||||
|
matchResultTemplateObjects_[kind].set(templateObject);
|
||||||
|
return matchResultTemplateObjects_[kind];
|
||||||
|
}
|
||||||
|
|
||||||
/* Set dummy index property */
|
/* Set dummy index property */
|
||||||
RootedValue index(cx, Int32Value(0));
|
RootedValue index(cx, Int32Value(0));
|
||||||
if (!NativeDefineProperty(cx, templateObject, cx->names().index, index, nullptr, nullptr,
|
if (!NativeDefineProperty(cx, templateObject, cx->names().index, index, nullptr, nullptr,
|
||||||
JSPROP_ENUMERATE))
|
JSPROP_ENUMERATE))
|
||||||
{
|
{
|
||||||
return matchResultTemplateObject_; // = nullptr
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::UndefinedType());
|
||||||
|
|
||||||
/* Set dummy input property */
|
/* Set dummy input property */
|
||||||
RootedValue inputVal(cx, StringValue(cx->runtime()->emptyString));
|
RootedValue inputVal(cx, StringValue(cx->runtime()->emptyString));
|
||||||
if (!NativeDefineProperty(cx, templateObject, cx->names().input, inputVal, nullptr, nullptr,
|
if (!NativeDefineProperty(cx, templateObject, cx->names().input, inputVal, nullptr, nullptr,
|
||||||
JSPROP_ENUMERATE))
|
JSPROP_ENUMERATE))
|
||||||
{
|
{
|
||||||
return matchResultTemplateObject_; // = nullptr
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::StringType());
|
||||||
|
|
||||||
/* Set dummy groups property */
|
/* Set dummy groups property */
|
||||||
RootedValue groupsVal(cx, UndefinedValue());
|
RootedValue groupsVal(cx, UndefinedValue());
|
||||||
|
|
@ -1338,25 +1365,21 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext* cx)
|
||||||
cx, templateObject, cx->names().groups, groupsVal, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
cx, templateObject, cx->names().groups, groupsVal, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that the properties are in the right slots.
|
|
||||||
DebugOnly<Shape*> shape = templateObject->lastProperty();
|
|
||||||
MOZ_ASSERT(shape->slot() == 2 &&
|
|
||||||
shape->propidRef() == NameToId(cx->names().groups));
|
|
||||||
MOZ_ASSERT(shape->previous()->slot() == 1 &&
|
|
||||||
shape->previous()->propidRef() == NameToId(cx->names().input));
|
|
||||||
MOZ_ASSERT(shape->previous()->previous()->slot() == 0 &&
|
|
||||||
shape->previous()->previous()->propidRef() == NameToId(cx->names().index));
|
|
||||||
|
|
||||||
// Make sure type information reflects the indexed properties which might
|
|
||||||
// be added.
|
|
||||||
AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::StringType());
|
|
||||||
AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::UndefinedType());
|
|
||||||
AddTypePropertyId(cx, templateObject, NameToId(cx->names().groups), TypeSet::AnyObjectType());
|
AddTypePropertyId(cx, templateObject, NameToId(cx->names().groups), TypeSet::AnyObjectType());
|
||||||
|
|
||||||
matchResultTemplateObject_.set(templateObject);
|
if (kind == ResultTemplateKind::WithIndices) {
|
||||||
|
/* Set dummy indices property */
|
||||||
|
RootedValue indicesVal(cx, UndefinedValue());
|
||||||
|
if (!NativeDefineProperty(cx, templateObject, cx->names().indices,
|
||||||
|
indicesVal, nullptr, nullptr, JSPROP_ENUMERATE)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
AddTypePropertyId(cx, templateObject, NameToId(cx->names().indices), TypeSet::AnyObjectType());
|
||||||
|
}
|
||||||
|
|
||||||
return matchResultTemplateObject_;
|
matchResultTemplateObjects_[kind].set(templateObject);
|
||||||
|
|
||||||
|
return matchResultTemplateObjects_[kind];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1374,10 +1397,10 @@ RegExpCompartment::init(JSContext* cx)
|
||||||
void
|
void
|
||||||
RegExpCompartment::sweep(JSRuntime* rt)
|
RegExpCompartment::sweep(JSRuntime* rt)
|
||||||
{
|
{
|
||||||
if (matchResultTemplateObject_ &&
|
for (auto& templateObject : matchResultTemplateObjects_) {
|
||||||
IsAboutToBeFinalized(&matchResultTemplateObject_))
|
if (templateObject && IsAboutToBeFinalized(&templateObject)) {
|
||||||
{
|
templateObject.set(nullptr);
|
||||||
matchResultTemplateObject_.set(nullptr);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optimizableRegExpPrototypeShape_ &&
|
if (optimizableRegExpPrototypeShape_ &&
|
||||||
|
|
@ -1483,14 +1506,18 @@ ParseRegExpFlags(const CharT* chars, size_t length, RegExpFlag* flagsOut, char16
|
||||||
for (size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
*lastParsedOut = chars[i];
|
*lastParsedOut = chars[i];
|
||||||
switch (chars[i]) {
|
switch (chars[i]) {
|
||||||
case 'i':
|
case 'd':
|
||||||
if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
|
if (!HandleRegExpFlag(HasIndicesFlag, flagsOut))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
if (!HandleRegExpFlag(GlobalFlag, flagsOut))
|
if (!HandleRegExpFlag(GlobalFlag, flagsOut))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (!HandleRegExpFlag(MultilineFlag, flagsOut))
|
if (!HandleRegExpFlag(MultilineFlag, flagsOut))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,10 @@ enum RegExpFlag : uint8_t
|
||||||
StickyFlag = 0x08,
|
StickyFlag = 0x08,
|
||||||
UnicodeFlag = 0x10,
|
UnicodeFlag = 0x10,
|
||||||
DotAllFlag = 0x20,
|
DotAllFlag = 0x20,
|
||||||
|
HasIndicesFlag = 0x40,
|
||||||
|
|
||||||
NoFlags = 0x00,
|
NoFlags = 0x00,
|
||||||
AllFlags = 0x3f
|
AllFlags = 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
|
static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
|
||||||
|
|
@ -66,7 +67,8 @@ static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
|
||||||
MultilineFlag == REGEXP_MULTILINE_FLAG &&
|
MultilineFlag == REGEXP_MULTILINE_FLAG &&
|
||||||
StickyFlag == REGEXP_STICKY_FLAG &&
|
StickyFlag == REGEXP_STICKY_FLAG &&
|
||||||
UnicodeFlag == REGEXP_UNICODE_FLAG &&
|
UnicodeFlag == REGEXP_UNICODE_FLAG &&
|
||||||
DotAllFlag == REGEXP_DOTALL_FLAG,
|
DotAllFlag == REGEXP_DOTALL_FLAG &&
|
||||||
|
HasIndicesFlag == REGEXP_HASINDICES_FLAG,
|
||||||
"Flag values should be in sync with self-hosted JS");
|
"Flag values should be in sync with self-hosted JS");
|
||||||
|
|
||||||
enum RegExpRunStatus
|
enum RegExpRunStatus
|
||||||
|
|
@ -206,12 +208,13 @@ class RegExpShared : public gc::TenuredCell
|
||||||
|
|
||||||
JSAtom* getSource() const { return source; }
|
JSAtom* getSource() const { return source; }
|
||||||
RegExpFlag getFlags() const { return flags; }
|
RegExpFlag getFlags() const { return flags; }
|
||||||
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
|
bool hasIndices() const { return flags & HasIndicesFlag; }
|
||||||
bool global() const { return flags & GlobalFlag; }
|
bool global() const { return flags & GlobalFlag; }
|
||||||
|
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
|
||||||
bool multiline() const { return flags & MultilineFlag; }
|
bool multiline() const { return flags & MultilineFlag; }
|
||||||
bool sticky() const { return flags & StickyFlag; }
|
|
||||||
bool unicode() const { return flags & UnicodeFlag; }
|
|
||||||
bool dotAll() const { return flags & DotAllFlag; }
|
bool dotAll() const { return flags & DotAllFlag; }
|
||||||
|
bool unicode() const { return flags & UnicodeFlag; }
|
||||||
|
bool sticky() const { return flags & StickyFlag; }
|
||||||
|
|
||||||
bool isCompiled(CompilationMode mode, bool latin1,
|
bool isCompiled(CompilationMode mode, bool latin1,
|
||||||
ForceByteCodeEnum force = DontForceByteCode) const {
|
ForceByteCodeEnum force = DontForceByteCode) const {
|
||||||
|
|
@ -295,12 +298,27 @@ class RegExpCompartment
|
||||||
using Set = GCHashSet<ReadBarriered<RegExpShared*>, Key, RuntimeAllocPolicy>;
|
using Set = GCHashSet<ReadBarriered<RegExpShared*>, Key, RuntimeAllocPolicy>;
|
||||||
JS::WeakCache<Set> set_;
|
JS::WeakCache<Set> set_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ResultTemplateKind { Normal, WithIndices, Indices, NumKinds };
|
||||||
|
|
||||||
|
private:
|
||||||
/*
|
/*
|
||||||
* This is the template object where the result of re.exec() is based on,
|
* The template objects that the result of re.exec() is based on, if
|
||||||
* if there is a result. This is used in CreateRegExpMatchResult to set
|
* there is a result. These are used in CreateRegExpMatchResult.
|
||||||
* the input/index properties faster.
|
* There are three template objects, each of which is an ArrayObject
|
||||||
|
* with some additional properties. We decide which to use based on
|
||||||
|
* the |hasIndices| (/d) flag.
|
||||||
|
*
|
||||||
|
* Normal: Has |index|, |input|, and |groups| properties.
|
||||||
|
* Used for the result object if |hasIndices| is not set.
|
||||||
|
*
|
||||||
|
* WithIndices: Has |index|, |input|, |groups|, and |indices| properties.
|
||||||
|
* Used for the result object if |hasIndices| is set.
|
||||||
|
*
|
||||||
|
* Indices: Has a |groups| property. If |hasIndices| is set, used
|
||||||
|
* for the |.indices| property of the result object.
|
||||||
*/
|
*/
|
||||||
ReadBarriered<ArrayObject*> matchResultTemplateObject_;
|
ReadBarriered<ArrayObject*> matchResultTemplateObjects_[ResultTemplateKind::NumKinds];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The shape of RegExp.prototype object that satisfies following:
|
* The shape of RegExp.prototype object that satisfies following:
|
||||||
|
|
@ -323,7 +341,7 @@ class RegExpCompartment
|
||||||
*/
|
*/
|
||||||
ReadBarriered<Shape*> optimizableRegExpInstanceShape_;
|
ReadBarriered<Shape*> optimizableRegExpInstanceShape_;
|
||||||
|
|
||||||
ArrayObject* createMatchResultTemplateObject(JSContext* cx);
|
ArrayObject* createMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RegExpCompartment(Zone* zone);
|
explicit RegExpCompartment(Zone* zone);
|
||||||
|
|
@ -341,10 +359,10 @@ class RegExpCompartment
|
||||||
MutableHandleRegExpShared shared);
|
MutableHandleRegExpShared shared);
|
||||||
|
|
||||||
/* Get or create template object used to base the result of .exec() on. */
|
/* Get or create template object used to base the result of .exec() on. */
|
||||||
ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx) {
|
ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind = ResultTemplateKind::Normal) {
|
||||||
if (matchResultTemplateObject_)
|
if (matchResultTemplateObjects_[kind])
|
||||||
return matchResultTemplateObject_;
|
return matchResultTemplateObjects_[kind];
|
||||||
return createMatchResultTemplateObject(cx);
|
return createMatchResultTemplateObject(cx, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape* getOptimizableRegExpPrototypeShape() {
|
Shape* getOptimizableRegExpPrototypeShape() {
|
||||||
|
|
@ -451,12 +469,13 @@ class RegExpObject : public NativeObject
|
||||||
setSlot(FLAGS_SLOT, Int32Value(flags));
|
setSlot(FLAGS_SLOT, Int32Value(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
|
bool hasIndices() const { return getFlags() & HasIndicesFlag; }
|
||||||
bool global() const { return getFlags() & GlobalFlag; }
|
bool global() const { return getFlags() & GlobalFlag; }
|
||||||
|
bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
|
||||||
bool multiline() const { return getFlags() & MultilineFlag; }
|
bool multiline() const { return getFlags() & MultilineFlag; }
|
||||||
bool sticky() const { return getFlags() & StickyFlag; }
|
|
||||||
bool unicode() const { return getFlags() & UnicodeFlag; }
|
|
||||||
bool dotAll() const { return getFlags() & DotAllFlag; }
|
bool dotAll() const { return getFlags() & DotAllFlag; }
|
||||||
|
bool unicode() const { return getFlags() & UnicodeFlag; }
|
||||||
|
bool sticky() const { return getFlags() & StickyFlag; }
|
||||||
|
|
||||||
static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
|
static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue