зеркало из https://github.com/mozilla/gecko-dev.git
Bug 997590 (part 2) - Create RegExpStaticsObjects lazily. r=sstangl.
--HG-- extra : rebase_source : 9cffd8ad8d3e66bb523cb1c127ca066847e34ee6
This commit is contained in:
Родитель
237a8118d3
Коммит
29c4ea7751
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче