Bug 1120169 - Implement RegExp.prototype.{global, ignoreCase, multiline, source, sticky, unicode}. r=till

This commit is contained in:
Tooru Fujisawa 2015-02-10 02:04:30 +09:00
Родитель 8fe2b690ec
Коммит df97a41a15
13 изменённых файлов: 330 добавлений и 168 удалений

Просмотреть файл

@ -233,29 +233,20 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
}
/*
* Only extract the 'flags' out of sourceObj; do not reuse the
* RegExpShared since it may be from a different compartment.
* Extract the 'source' and the 'flags' out of sourceObj; do not reuse
* the RegExpShared since it may be from a different compartment.
*/
RootedAtom sourceAtom(cx);
RegExpFlag flags;
{
RegExpGuard g(cx);
if (!RegExpToShared(cx, sourceObj, &g))
return false;
sourceAtom = g->getSource();
flags = g->getFlags();
}
/*
* 'toSource' is a permanent read-only property, so this is equivalent
* to executing RegExpObject::getSource on the unwrapped object.
*/
RootedValue v(cx);
if (!GetProperty(cx, sourceObj, sourceObj, cx->names().source, &v))
return false;
// For proxies like CPOWs, we can't assume the result of a property get
// for 'source' is atomized.
Rooted<JSAtom*> sourceAtom(cx, AtomizeString(cx, v.toString()));
RegExpObject *reobj = builder.build(sourceAtom, flags);
if (!reobj)
return false;
@ -431,8 +422,138 @@ regexp_flags(JSContext *cx, unsigned argc, JS::Value *vp)
return true;
}
/* ES6 draft rev32 21.2.5.4. */
MOZ_ALWAYS_INLINE bool
regexp_global_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
/* Steps 4-6. */
args.rval().setBoolean(reObj->global());
return true;
}
static bool
regexp_global(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-3. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_global_impl>(cx, args);
}
/* ES6 draft rev32 21.2.5.5. */
MOZ_ALWAYS_INLINE bool
regexp_ignoreCase_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
/* Steps 4-6. */
args.rval().setBoolean(reObj->ignoreCase());
return true;
}
static bool
regexp_ignoreCase(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-3. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_ignoreCase_impl>(cx, args);
}
/* ES6 draft rev32 21.2.5.7. */
MOZ_ALWAYS_INLINE bool
regexp_multiline_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
/* Steps 4-6. */
args.rval().setBoolean(reObj->multiline());
return true;
}
static bool
regexp_multiline(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-3. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_multiline_impl>(cx, args);
}
/* ES6 draft rev32 21.2.5.10. */
MOZ_ALWAYS_INLINE bool
regexp_source_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
/* Step 5. */
RootedAtom src(cx, reObj->getSource());
if (!src)
return false;
args.rval().setString(src);
return true;
}
static bool
regexp_source(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-4. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_source_impl>(cx, args);
}
/* ES6 draft rev32 21.2.5.12. */
MOZ_ALWAYS_INLINE bool
regexp_sticky_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
/* Steps 4-6. */
args.rval().setBoolean(reObj->sticky());
return true;
}
static bool
regexp_sticky(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-3. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_sticky_impl>(cx, args);
}
/* ES6 draft rev32 21.2.5.15. */
MOZ_ALWAYS_INLINE bool
regexp_unicode_impl(JSContext *cx, CallArgs args)
{
MOZ_ASSERT(IsRegExp(args.thisv()));
/* Steps 4-6. */
/* FIXME: When the /u flags is supported, return correct value. */
args.rval().setBoolean(false);
return true;
}
static bool
regexp_unicode(JSContext *cx, unsigned argc, JS::Value *vp)
{
/* Steps 1-3. */
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsRegExp, regexp_unicode_impl>(cx, args);
}
static const JSPropertySpec regexp_properties[] = {
JS_PSG("flags", regexp_flags, 0),
JS_PSG("global", regexp_global, 0),
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
JS_PSG("multiline", regexp_multiline, 0),
JS_PSG("source", regexp_source, 0),
JS_PSG("sticky", regexp_sticky, 0),
JS_PSG("unicode", regexp_unicode, 0),
JS_PS_END
};

Просмотреть файл

@ -1,6 +1,5 @@
load(libdir + "asserts.js");
var g = newGlobal();
var a = g.RegExp("x");
assertThrowsInstanceOf(function () { Object.defineProperty(a, "ignoreCase", {value: undefined}); },
g.TypeError);
Object.defineProperty(a, "ignoreCase", {value: undefined});
a.toString();

Просмотреть файл

@ -267,50 +267,6 @@ expectDescriptor(pd, expected);
o = /foo/im;
pd = Object.getOwnPropertyDescriptor(o, "source");
expected =
{
value: "foo",
writable: false,
enumerable: false,
configurable: false
};
expectDescriptor(pd, expected);
pd = Object.getOwnPropertyDescriptor(o, "global");
expected =
{
value: false,
writable: false,
enumerable: false,
configurable: false
};
expectDescriptor(pd, expected);
pd = Object.getOwnPropertyDescriptor(o, "ignoreCase");
expected =
{
value: true,
writable: false,
enumerable: false,
configurable: false
};
expectDescriptor(pd, expected);
pd = Object.getOwnPropertyDescriptor(o, "multiline");
expected =
{
value: true,
writable: false,
enumerable: false,
configurable: false
};
expectDescriptor(pd, expected);
pd = Object.getOwnPropertyDescriptor(o, "lastIndex");
expected =
{

Просмотреть файл

@ -16,7 +16,7 @@ print(BUGNUMBER + ": " + summary);
**************/
var actual = Object.getOwnPropertyNames(/a/);
var expected = ["lastIndex", "source", "global", "ignoreCase", "multiline"];
var expected = ["lastIndex"];
for (var i = 0; i < expected.length; i++)
{

Просмотреть файл

@ -47,33 +47,18 @@ var choices = [{ msg: "RegExp.prototype",
{ msg: "/(?:)/",
get: Function("return /(?:)/;") }];
function checkRegExp(r, msg, lastIndex, global, ignoreCase, multiline)
function checkRegExp(r, msg, lastIndex)
{
var expect;
expect = { value: lastIndex, enumerable: false, configurable: false, writable: true };
checkDataProperty(r, "lastIndex", expect, msg);
// check source specially: its value is under-defined in the spec
var d = Object.getOwnPropertyDescriptor(r, "source");
assertEq(d.writable, false, "bad writable: " + msg);
assertEq(d.enumerable, false, "bad enumerable: " + msg);
assertEq(d.configurable, false, "bad configurable: " + msg);
expect = { value: global, enumerable: false, configurable: false, writable: false };
checkDataProperty(r, "global", expect, msg);
expect = { value: ignoreCase, enumerable: false, configurable: false, writable: false };
checkDataProperty(r, "ignoreCase", expect, msg);
expect = { value: multiline, enumerable: false, configurable: false, writable: false };
checkDataProperty(r, "multiline", expect, msg);
}
checkRegExp(RegExp.prototype, "RegExp.prototype", 0, false, false, false);
checkRegExp(new RegExp(), "new RegExp()", 0, false, false, false);
checkRegExp(/(?:)/, "/(?:)/", 0, false, false, false);
checkRegExp(Function("return /(?:)/;")(), 'Function("return /(?:)/;")()', 0, false, false, false);
checkRegExp(RegExp.prototype, "RegExp.prototype", 0);
checkRegExp(new RegExp(), "new RegExp()", 0);
checkRegExp(/(?:)/, "/(?:)/", 0);
checkRegExp(Function("return /(?:)/;")(), 'Function("return /(?:)/;")()', 0);
for (var i = 0; i < choices.length; i++)
{
@ -81,67 +66,60 @@ for (var i = 0; i < choices.length; i++)
var msg = choice.msg;
var r = choice.get();
checkRegExp(r, msg, 0, false, false, false);
checkRegExp(r, msg, 0);
}
// Now test less generic regular expressions
checkRegExp(/a/gim, "/a/gim", 0, true, true, true);
checkRegExp(/a/gim, "/a/gim", 0);
var r;
do
{
r = /abcd/mg;
checkRegExp(r, "/abcd/mg initially", 0, true, false, true);
checkRegExp(r, "/abcd/mg initially", 0);
r.exec("abcdefg");
checkRegExp(r, "/abcd/mg step 1", 4, true, false, true);
checkRegExp(r, "/abcd/mg step 1", 4);
r.exec("abcdabcd");
checkRegExp(r, "/abcd/mg step 2", 8, true, false, true);
checkRegExp(r, "/abcd/mg step 2", 8);
r.exec("abcdabcd");
checkRegExp(r, "/abcd/mg end", 0, true, false, true);
checkRegExp(r, "/abcd/mg end", 0);
r = /cde/ig;
checkRegExp(r, "/cde/ig initially", 0, true, true, false);
checkRegExp(r, "/cde/ig initially", 0);
var obj = r.lastIndex = { valueOf: function() { return 2; } };
checkRegExp(r, "/cde/ig after lastIndex", obj, true, true, false);
checkRegExp(r, "/cde/ig after lastIndex", obj);
r.exec("aaacdef");
checkRegExp(r, "/cde/ig after exec", 6, true, true, false);
checkRegExp(r, "/cde/ig after exec", 6);
Object.defineProperty(r, "lastIndex", { value: 3 });
checkRegExp(r, "/cde/ig after define 3", 3, true, true, false);
checkRegExp(r, "/cde/ig after define 3", 3);
Object.defineProperty(r, "lastIndex", { value: obj });
checkRegExp(r, "/cde/ig after lastIndex", obj, true, true, false);
checkRegExp(r, "/cde/ig after lastIndex", obj);
// Tricky bits of testing: make sure that redefining lastIndex doesn't change
// the slot where the lastIndex property is initially stored, even if
// the redefinition also changes writability.
r = /a/g;
checkRegExp(r, "/a/g initially", 0, true, false, false);
checkRegExp(r, "/a/g initially", 0);
Object.defineProperty(r, "lastIndex", { value: 2 });
r.exec("aabbbba");
checkRegExp(r, "/a/g after first exec", 7, true, false, false);
checkRegExp(r, "/a/g after first exec", 7);
assertEq(r.lastIndex, 7);
r.lastIndex = 2;
checkRegExp(r, "/a/g after assign", 2, true, false, false);
checkRegExp(r, "/a/g after assign", 2);
r.exec("aabbbba");
assertEq(r.lastIndex, 7); // check in reverse order
checkRegExp(r, "/a/g after second exec", 7, true, false, false);
checkRegExp(r, "/a/g after second exec", 7);
r = /c/g;
r.lastIndex = 2;
checkRegExp(r, "/c/g initially", 2, true, false, false);
checkRegExp(r, "/c/g initially", 2);
Object.defineProperty(r, "lastIndex", { writable: false });
assertEq(Object.getOwnPropertyDescriptor(r, "lastIndex").writable, false);
try { r.exec("aabbbba"); } catch (e) { /* swallow error if thrown */ }
assertEq(Object.getOwnPropertyDescriptor(r, "lastIndex").writable, false);
assertEq(Object.getOwnPropertyDescriptor(r, "source").writable, false);
assertEq(Object.getOwnPropertyDescriptor(r, "global").value, true);
assertEq(Object.getOwnPropertyDescriptor(r, "global").writable, false);
assertEq(Object.getOwnPropertyDescriptor(r, "ignoreCase").value, false);
assertEq(Object.getOwnPropertyDescriptor(r, "ignoreCase").writable, false);
assertEq(Object.getOwnPropertyDescriptor(r, "multiline").value, false);
assertEq(Object.getOwnPropertyDescriptor(r, "multiline").writable, false);
}
while (Math.random() > 17); // fake loop to discourage RegExp object caching

Просмотреть файл

@ -5,34 +5,6 @@
* http://creativecommons.org/licenses/publicdomain/
*/
assertEq(testLenientAndStrict('var r = /foo/; r.source = "bar"; r.source',
returns("foo"), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; delete r.source',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; r.global = true; r.global',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; delete r.global',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; r.ignoreCase = true; r.ignoreCase',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; delete r.ignoreCase',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; r.multiline = true; r.multiline',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; delete r.multiline',
returns(false), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var r = /foo/; r.lastIndex = 42; r.lastIndex',
returns(42), returns(42)),
true);

Просмотреть файл

@ -0,0 +1,61 @@
var BUGNUMBER = 1130860;
var summary = "RegExp constructor shouldn't invoke source/flags getters on argument RegExp instance.";
print(BUGNUMBER + ": " + summary);
// same-compartment
var a = /foo/;
var flagsCalled = false;
var sourceCalled = false;
Object.defineProperty(a, "source", { get: () => {
sourceCalled = true;
return "bar";
}});
Object.defineProperty(a, "flags", { get: () => {
flagsCalled = true;
return "i";
}});
assertEq(a.source, "bar");
assertEq(a.flags, "i");
assertEq(sourceCalled, true);
assertEq(flagsCalled, true);
sourceCalled = false;
flagsCalled = false;
assertEq(new RegExp(a).source, "foo");
assertEq(sourceCalled, false);
assertEq(flagsCalled, false);
// cross-compartment
var g = newGlobal();
var b = g.eval(`
var b = /foo2/;
var flagsCalled = false;
var sourceCalled = false;
Object.defineProperty(b, "source", { get: () => {
sourceCalled = true;
return "bar2";
}});
Object.defineProperty(b, "flags", { get: () => {
flagsCalled = true;
return "i";
}});
b;
`);
assertEq(b.source, "bar2");
assertEq(b.flags, "i");
assertEq(g.eval("sourceCalled;"), true);
assertEq(g.eval("flagsCalled;"), true);
g.eval(`
sourceCalled = false;
flagsCalled = false;
`);
assertEq(new RegExp(b).source, "foo2");
assertEq(g.eval("sourceCalled;"), false);
assertEq(g.eval("flagsCalled;"), false);
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,25 @@
var BUGNUMBER = 1120169;
var summary = "Implement RegExp.prototype.{global, ignoreCase, multiline, sticky, unicode} - property descriptor";
print(BUGNUMBER + ": " + summary);
var getters = [
"flags",
"global",
"ignoreCase",
"multiline",
"source",
"sticky",
"unicode",
];
for (var name of getters) {
var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, name);
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq("writable" in desc, false);
assertEq("get" in desc, true);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,52 @@
var BUGNUMBER = 1120169;
var summary = "Implement RegExp.prototype.{global, ignoreCase, multiline, sticky, unicode}";
print(BUGNUMBER + ": " + summary);
var props = [
"global",
"ignoreCase",
"multiline",
"sticky",
"unicode",
];
testThrows(RegExp.prototype);
test(/foo/iymg, [true, true, true, true, false]);
test(RegExp(""), [false, false, false, false, false]);
test(RegExp("", "mygi"), [true, true, true, true, false]);
// When the /u flag is supported, remove the following line and uncomment the
// next line.
assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError);
// test(RegExp("", "mygiu"), [true, true, true, true, true]);
testThrowsGeneric();
testThrowsGeneric(1);
testThrowsGeneric("");
testThrowsGeneric({});
testThrowsGeneric(new Proxy({}, {get(){ return true; }}));
function test(obj, expects) {
for (var i = 0; i < props.length; i++) {
assertEq(obj[props[i]], expects[i]);
}
}
function testThrows(obj) {
for (var prop of props) {
assertThrowsInstanceOf(obj[prop], TypeError);
}
}
function testThrowsGeneric(obj) {
for (var prop of props) {
assertThrowsInstanceOf(() => genericGet(obj, prop), TypeError);
}
}
function genericGet(obj, prop) {
return Object.getOwnPropertyDescriptor(RegExp.prototype, prop).get.call(obj);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,22 @@
var BUGNUMBER = 1120169;
var summary = "Implement RegExp.prototype.source";
print(BUGNUMBER + ": " + summary);
assertEq(/foo/.source, "foo");
assertEq(/foo/iymg.source, "foo");
assertEq(/\//.source, "\\/");
assertEq(RegExp("/").source, "\\/");
assertThrowsInstanceOf(() => genericSource(), TypeError);
assertThrowsInstanceOf(() => genericSource(1), TypeError);
assertThrowsInstanceOf(() => genericSource(""), TypeError);
assertThrowsInstanceOf(() => genericSource({}), TypeError);
assertThrowsInstanceOf(() => genericSource(new Proxy(/foo/, {get(){ return true; }})), TypeError);
function genericSource(obj) {
return Object.getOwnPropertyDescriptor(RegExp.prototype, "source").get.call(obj);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -27,7 +27,7 @@ for (var constructor of constructors) {
assertEq(obj instanceof constructor, false);
assertEq(Object.getPrototypeOf(obj), RegExp.prototype);
assertEq(Object.getOwnPropertyNames(obj).join(","),
"0,lastIndex,source,global,ignoreCase,multiline,sticky");
"0,lastIndex");
assertEq(obj.length, undefined);
// Or any JS function.

Просмотреть файл

@ -3,7 +3,7 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
function testRegExp(b) {
function testRegExp(b, c=b) {
var a = deserialize(serialize(b));
assertEq(a === b, false);
assertEq(Object.getPrototypeOf(a), RegExp.prototype);
@ -11,11 +11,11 @@ function testRegExp(b) {
for (p in a)
throw new Error("cloned RegExp should have no enumerable properties");
assertEq(a.source, b.source);
assertEq(a.global, b.global);
assertEq(a.ignoreCase, b.ignoreCase);
assertEq(a.multiline, b.multiline);
assertEq(a.sticky, b.sticky);
assertEq(a.source, c.source);
assertEq(a.global, c.global);
assertEq(a.ignoreCase, c.ignoreCase);
assertEq(a.multiline, c.multiline);
assertEq(a.sticky, c.sticky);
assertEq("expando" in a, false);
}
@ -27,7 +27,11 @@ testRegExp(RegExp.prototype);
var re = /\bx\b/gi;
re.expando = true;
testRegExp(re);
// `source` and the flag accessors are defined on RegExp.prototype, so they're
// not available after re.__proto__ has been changed. We solve that by passing
// in an additional copy of the same RegExp to compare the
// serialized-then-deserialized clone with."
re.__proto__ = {};
testRegExp(re);
testRegExp(re, /\bx\b/gi);
reportCompare(0, 0, 'ok');

Просмотреть файл

@ -337,27 +337,9 @@ RegExpObject::assignInitialShape(ExclusiveContext *cx, Handle<RegExpObject*> sel
MOZ_ASSERT(self->empty());
JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
JS_STATIC_ASSERT(SOURCE_SLOT == LAST_INDEX_SLOT + 1);
JS_STATIC_ASSERT(GLOBAL_FLAG_SLOT == SOURCE_SLOT + 1);
JS_STATIC_ASSERT(IGNORE_CASE_FLAG_SLOT == GLOBAL_FLAG_SLOT + 1);
JS_STATIC_ASSERT(MULTILINE_FLAG_SLOT == IGNORE_CASE_FLAG_SLOT + 1);
JS_STATIC_ASSERT(STICKY_FLAG_SLOT == MULTILINE_FLAG_SLOT + 1);
/* The lastIndex property alone is writable but non-configurable. */
if (!self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT))
return nullptr;
/* Remaining instance properties are non-writable and non-configurable. */
unsigned attrs = JSPROP_PERMANENT | JSPROP_READONLY;
if (!self->addDataProperty(cx, cx->names().source, SOURCE_SLOT, attrs))
return nullptr;
if (!self->addDataProperty(cx, cx->names().global, GLOBAL_FLAG_SLOT, attrs))
return nullptr;
if (!self->addDataProperty(cx, cx->names().ignoreCase, IGNORE_CASE_FLAG_SLOT, attrs))
return nullptr;
if (!self->addDataProperty(cx, cx->names().multiline, MULTILINE_FLAG_SLOT, attrs))
return nullptr;
return self->addDataProperty(cx, cx->names().sticky, STICKY_FLAG_SLOT, attrs);
return self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT);
}
bool
@ -370,16 +352,6 @@ RegExpObject::init(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags)
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().lastIndex))->slot() ==
LAST_INDEX_SLOT);
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().source))->slot() ==
SOURCE_SLOT);
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().global))->slot() ==
GLOBAL_FLAG_SLOT);
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().ignoreCase))->slot() ==
IGNORE_CASE_FLAG_SLOT);
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().multiline))->slot() ==
MULTILINE_FLAG_SLOT);
MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().sticky))->slot() ==
STICKY_FLAG_SLOT);
/*
* If this is a re-initialization with an existing RegExpShared, 'flags'