Bug 997590 (part 2) - Create RegExpStaticsObjects lazily. r=sstangl.

--HG--
extra : rebase_source : 9cffd8ad8d3e66bb523cb1c127ca066847e34ee6
This commit is contained in:
Nicholas Nethercote 2014-04-22 20:13:24 -07:00
Родитель 237a8118d3
Коммит 29c4ea7751
12 изменённых файлов: 149 добавлений и 48 удалений

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

@ -199,7 +199,9 @@ static bool
CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
{
if (args.length() == 0) {
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
Rooted<JSAtom*> empty(cx, cx->runtime()->emptyString);
RegExpObject *reobj = builder.build(empty, res->getFlags());
if (!reobj)
@ -284,7 +286,9 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
if (!js::RegExpShared::checkSyntax(cx, nullptr, escapedSourceStr))
return false;
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
RegExpObject *reobj = builder.build(escapedSourceStr, RegExpFlag(flags | res->getFlags()));
if (!reobj)
return false;
@ -387,7 +391,9 @@ static const JSFunctionSpec regexp_methods[] = {
name(JSContext *cx, unsigned argc, Value *vp) \
{ \
CallArgs args = CallArgsFromVp(argc, vp); \
RegExpStatics *res = cx->global()->getRegExpStatics(); \
RegExpStatics *res = cx->global()->getRegExpStatics(cx); \
if (!res) \
return false; \
code; \
}
@ -413,7 +419,9 @@ DEFINE_STATIC_GETTER(static_paren9_getter, return res->createParen(cx, 9,
static bool \
name(JSContext *cx, unsigned argc, Value *vp) \
{ \
RegExpStatics *res = cx->global()->getRegExpStatics(); \
RegExpStatics *res = cx->global()->getRegExpStatics(cx); \
if (!res) \
return false; \
code; \
return true; \
}
@ -422,7 +430,9 @@ static bool
static_input_setter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
RootedString str(cx, ToString<CanGC>(cx, args.get(0)));
if (!str)
@ -437,7 +447,9 @@ static bool
static_multiline_setter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
bool b = ToBoolean(args.get(0));
res->setMultiline(cx, b);
@ -521,9 +533,14 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
if (!reobj->getShared(cx, &re))
return RegExpRunStatus_Error;
RegExpStatics *res = (staticsUpdate == UpdateRegExpStatics)
? cx->global()->getRegExpStatics()
: nullptr;
RegExpStatics *res;
if (staticsUpdate == UpdateRegExpStatics) {
res = cx->global()->getRegExpStatics(cx);
if (!res)
return RegExpRunStatus_Error;
} else {
res = nullptr;
}
/* Step 3. */
Rooted<JSLinearString*> input(cx, string->ensureLinear(cx));

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

@ -6910,7 +6910,10 @@ Parser<ParseHandler>::newRegExp()
RegExpFlag flags = tokenStream.currentToken().regExpFlags();
Rooted<RegExpObject*> reobj(context);
RegExpStatics *res = context->global()->getRegExpStatics();
RegExpStatics *res = context->global()->getRegExpStatics(context);
if (!res)
return null();
reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
if (!reobj)
return null();

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

@ -9423,11 +9423,17 @@ IonBuilder::jsop_regexp(RegExpObject *reobj)
bool mustClone = true;
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global());
if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {
RegExpStatics *res = script()->global().getRegExpStatics();
DebugOnly<uint32_t> origFlags = reobj->getFlags();
DebugOnly<uint32_t> staticsFlags = res->getFlags();
JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
#ifdef DEBUG
// Only compare the statics if the one on script()->global() has been
// instantiated.
if (script()->global().hasRegExpStatics()) {
RegExpStatics *res = script()->global().getAlreadyCreatedRegExpStatics();
MOZ_ASSERT(res);
uint32_t origFlags = reobj->getFlags();
uint32_t staticsFlags = res->getFlags();
JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
}
#endif
if (!reobj->global() && !reobj->sticky())
mustClone = false;

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

@ -5735,7 +5735,10 @@ JS_NewRegExpObject(JSContext *cx, HandleObject obj, char *bytes, size_t length,
if (!chars)
return nullptr;
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return nullptr;
RegExpObject *reobj = RegExpObject::create(cx, res, chars, length,
RegExpFlag(flags), nullptr);
js_free(chars);
@ -5748,29 +5751,42 @@ JS_NewUCRegExpObject(JSContext *cx, HandleObject obj, jschar *chars, size_t leng
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return nullptr;
return RegExpObject::create(cx, res, chars, length,
RegExpFlag(flags), nullptr);
}
JS_PUBLIC_API(void)
JS_PUBLIC_API(bool)
JS_SetRegExpInput(JSContext *cx, HandleObject obj, HandleString input, bool multiline)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, input);
obj->as<GlobalObject>().getRegExpStatics()->reset(cx, input, !!multiline);
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return false;
res->reset(cx, input, !!multiline);
return true;
}
JS_PUBLIC_API(void)
JS_PUBLIC_API(bool)
JS_ClearRegExpStatics(JSContext *cx, HandleObject obj)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
JS_ASSERT(obj);
obj->as<GlobalObject>().getRegExpStatics()->clear();
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return false;
res->clear();
return true;
}
JS_PUBLIC_API(bool)
@ -5780,7 +5796,9 @@ JS_ExecuteRegExp(JSContext *cx, HandleObject obj, HandleObject reobj, jschar *ch
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return false;
return ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), NullPtr(), chars, length, indexp,
test, rval);

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

@ -4543,11 +4543,11 @@ extern JS_PUBLIC_API(JSObject *)
JS_NewUCRegExpObject(JSContext *cx, JS::HandleObject obj, jschar *chars, size_t length,
unsigned flags);
extern JS_PUBLIC_API(void)
extern JS_PUBLIC_API(bool)
JS_SetRegExpInput(JSContext *cx, JS::HandleObject obj, JS::HandleString input,
bool multiline);
extern JS_PUBLIC_API(void)
extern JS_PUBLIC_API(bool)
JS_ClearRegExpStatics(JSContext *cx, JS::HandleObject obj);
extern JS_PUBLIC_API(bool)

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

@ -2115,7 +2115,10 @@ js::str_match(JSContext *cx, unsigned argc, Value *vp)
if (!g.normalizeRegExp(cx, false, 1, args))
return false;
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
Rooted<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return false;
@ -2156,7 +2159,9 @@ js::str_search(JSContext *cx, unsigned argc, Value *vp)
const jschar *chars = linearStr->chars();
size_t length = linearStr->length();
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
/* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
size_t i = 0;
@ -2829,16 +2834,26 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
break;
}
RegExpStatics *res;
/* If unmatched, return the input string. */
if (!lastIndex) {
if (startIndex > 0)
cx->global()->getRegExpStatics()->updateLazily(cx, flatStr, &re, lazyIndex);
if (startIndex > 0) {
res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
res->updateLazily(cx, flatStr, &re, lazyIndex);
}
rval.setString(str);
return true;
}
/* The last successful match updates the RegExpStatics. */
cx->global()->getRegExpStatics()->updateLazily(cx, flatStr, &re, lazyIndex);
res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
res->updateLazily(cx, flatStr, &re, lazyIndex);
/* Include any remaining part of the string. */
if (lastIndex < charsLen) {
@ -2866,7 +2881,10 @@ StrReplaceRegExp(JSContext *cx, ReplaceData &rdata, MutableHandleValue rval)
rdata.leftIndex = 0;
rdata.calledBack = false;
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
RegExpShared &re = rdata.g.regExp();
// The spec doesn't describe this function very clearly, so we go ahead and
@ -3283,7 +3301,10 @@ SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Ma
/* Step 13(c)(iii)(6-7). */
if (Matcher::returnsCaptures) {
RegExpStatics *res = cx->global()->getRegExpStatics();
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return nullptr;
const MatchPairs &matches = res->getMatches();
for (size_t i = 0; i < matches.parenCount(); i++) {
/* Steps 13(c)(iii)(7)(a-c). */
@ -3494,7 +3515,10 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
aobj = SplitHelper(cx, linearStr, limit, matcher, type);
}
} else {
SplitRegExpMatcher matcher(*re, cx->global()->getRegExpStatics());
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
SplitRegExpMatcher matcher(*re, res);
aobj = SplitHelper(cx, linearStr, limit, matcher, type);
}
if (!aobj)

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

@ -565,12 +565,6 @@ GlobalObject::create(JSContext *cx, const Class *clasp)
if (!global->setDelegate(cx))
return nullptr;
/* Construct a regexp statics object for this global object. */
JSObject *res = RegExpStatics::create(cx, global);
if (!res)
return nullptr;
global->initSlot(REGEXP_STATICS, ObjectValue(*res));
return global;
}
@ -783,6 +777,41 @@ GlobalObject::getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject *> gl
return forOfPIC;
}
bool
GlobalObject::hasRegExpStatics() const
{
return !getSlot(REGEXP_STATICS).isUndefined();
}
RegExpStatics *
GlobalObject::getRegExpStatics(ExclusiveContext *cx) const
{
MOZ_ASSERT(cx);
Rooted<GlobalObject*> self(cx, const_cast<GlobalObject*>(this));
JSObject *resObj = nullptr;
const Value &val = this->getSlot(REGEXP_STATICS);
if (!val.isObject()) {
MOZ_ASSERT(val.isUndefined());
resObj = RegExpStatics::create(cx, self);
if (!resObj)
return nullptr;
self->initSlot(REGEXP_STATICS, ObjectValue(*resObj));
} else {
resObj = &val.toObject();
}
return static_cast<RegExpStatics*>(resObj->getPrivate(/* nfixed = */ 1));
}
RegExpStatics *
GlobalObject::getAlreadyCreatedRegExpStatics() const
{
const Value &val = this->getSlot(REGEXP_STATICS);
MOZ_ASSERT(val.isObject());
return static_cast<RegExpStatics*>(val.toObject().getPrivate(/* nfixed = */ 1));
}
bool
GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal)

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

@ -592,10 +592,9 @@ class GlobalObject : public JSObject
bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal);
RegExpStatics *getRegExpStatics() const {
JSObject &resObj = getSlot(REGEXP_STATICS).toObject();
return static_cast<RegExpStatics *>(resObj.getPrivate(/* nfixed = */ 1));
}
bool hasRegExpStatics() const;
RegExpStatics *getRegExpStatics(ExclusiveContext *cx) const;
RegExpStatics *getAlreadyCreatedRegExpStatics() const;
JSObject *getThrowTypeError() const {
JS_ASSERT(functionObjectClassesInitialized());

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

@ -106,7 +106,10 @@ RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
* the clone -- if the |RegExpStatics| provides more flags we'll
* need a different |RegExpShared|.
*/
RegExpStatics *res = other->getProto()->getParent()->as<GlobalObject>().getRegExpStatics();
RegExpStatics *res = other->getProto()->getParent()->as<GlobalObject>().getRegExpStatics(cx);
if (!res)
return nullptr;
RegExpFlag origFlags = other->getFlags();
RegExpFlag staticsFlags = res->getFlags();
if ((origFlags & staticsFlags) != staticsFlags) {

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

@ -15,8 +15,8 @@ using namespace js;
/*
* RegExpStatics allocates memory -- in order to keep the statics stored
* per-global and not leak, we create a js::Class to wrap the C++ instance and
* provide an appropriate finalizer. We store an instance of that js::Class in
* a global reserved slot.
* provide an appropriate finalizer. We lazily create and store an instance of
* that js::Class in a global reserved slot.
*/
static void
@ -53,7 +53,7 @@ const Class RegExpStaticsObject::class_ = {
};
JSObject *
RegExpStatics::create(JSContext *cx, GlobalObject *parent)
RegExpStatics::create(ExclusiveContext *cx, GlobalObject *parent)
{
JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsObject::class_, nullptr, parent);
if (!obj)
@ -74,7 +74,7 @@ RegExpStatics::markFlagsSet(JSContext *cx)
// type changes on RegExp.prototype, so mark a state change to trigger
// recompilation of all such code (when recompiling, a stub call will
// always be performed).
JS_ASSERT(this == cx->global()->getRegExpStatics());
JS_ASSERT_IF(cx->global()->hasRegExpStatics(), this == cx->global()->getRegExpStatics(cx));
types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_REGEXP_FLAGS_SET);
}

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

@ -47,7 +47,7 @@ class RegExpStatics
public:
RegExpStatics() : bufferLink(nullptr), copied(false) { clear(); }
static JSObject *create(JSContext *cx, GlobalObject *parent);
static JSObject *create(ExclusiveContext *cx, GlobalObject *parent);
private:
bool executeLazy(JSContext *cx);

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

@ -17,6 +17,8 @@ class RegExpStaticsObject : public JSObject
static const Class class_;
size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) {
// XXX: should really call RegExpStatics::sizeOfIncludingThis() here
// instead, but the extra memory it would measure is insignificant.
return mallocSizeOf(getPrivate());
}
};