mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 701332: Don't expose RegExp privates. (r=Waldo)
This commit is contained in:
parent
3b0417b8c4
commit
ccc7d0d4ac
@ -159,11 +159,11 @@ ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, T *re, JSLinearString *inpu
|
||||
}
|
||||
|
||||
bool
|
||||
js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpPrivate *rep, JSLinearString *input,
|
||||
js::ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpMatcher *matcher, JSLinearString *input,
|
||||
const jschar *chars, size_t length,
|
||||
size_t *lastIndex, RegExpExecType type, Value *rval)
|
||||
{
|
||||
return ExecuteRegExpImpl(cx, res, rep, input, chars, length, lastIndex, type, rval);
|
||||
return ExecuteRegExpImpl(cx, res, matcher, input, chars, length, lastIndex, type, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -278,7 +278,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder,
|
||||
if (!escapedSourceStr)
|
||||
return false;
|
||||
|
||||
if (!RegExpPrivateCode::checkSyntax(cx, NULL, escapedSourceStr))
|
||||
if (!CheckRegExpSyntax(cx, escapedSourceStr))
|
||||
return false;
|
||||
|
||||
RegExpStatics *res = cx->regExpStatics();
|
||||
@ -515,15 +515,10 @@ ExecuteRegExp(JSContext *cx, Native native, uintN argc, Value *vp)
|
||||
return ok;
|
||||
|
||||
RegExpObject *reobj = obj->asRegExp();
|
||||
RegExpPrivate *rep = reobj->getOrCreatePrivate(cx);
|
||||
if (!rep)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Code execution under this call could swap out the guts of |reobj|, so we
|
||||
* have to take a defensive refcount here.
|
||||
*/
|
||||
AutoRefCount<RegExpPrivate> arc(cx, NeedsIncRef<RegExpPrivate>(rep));
|
||||
RegExpMatcher matcher(cx);
|
||||
if (!matcher.reset(reobj))
|
||||
return false;
|
||||
|
||||
RegExpStatics *res = cx->regExpStatics();
|
||||
|
||||
@ -548,7 +543,7 @@ ExecuteRegExp(JSContext *cx, Native native, uintN argc, Value *vp)
|
||||
return false;
|
||||
|
||||
/* Steps 6-7 (with sticky extension). */
|
||||
if (!rep->global() && !rep->sticky())
|
||||
if (!matcher.global() && !matcher.sticky())
|
||||
i = 0;
|
||||
|
||||
/* Step 9a. */
|
||||
@ -561,13 +556,13 @@ ExecuteRegExp(JSContext *cx, Native native, uintN argc, Value *vp)
|
||||
/* Steps 8-21. */
|
||||
RegExpExecType execType = (native == regexp_test) ? RegExpTest : RegExpExec;
|
||||
size_t lastIndexInt(i);
|
||||
if (!ExecuteRegExp(cx, res, rep, linearInput, chars, length, &lastIndexInt, execType,
|
||||
if (!ExecuteRegExp(cx, res, &matcher, linearInput, chars, length, &lastIndexInt, execType,
|
||||
&args.rval())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Step 11 (with sticky extension). */
|
||||
if (rep->global() || (!args.rval().isNull() && rep->sticky())) {
|
||||
if (matcher.global() || (!args.rval().isNull() && matcher.sticky())) {
|
||||
if (args.rval().isNull())
|
||||
reobj->zeroLastIndex();
|
||||
else
|
||||
|
@ -64,7 +64,7 @@ ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpObject *reobj, JSLinearSt
|
||||
size_t *lastIndex, RegExpExecType type, Value *rval);
|
||||
|
||||
bool
|
||||
ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpPrivate *rep, JSLinearString *input,
|
||||
ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpMatcher *matcher, JSLinearString *input,
|
||||
const jschar *chars, size_t length,
|
||||
size_t *lastIndex, RegExpExecType type, Value *rval);
|
||||
|
||||
|
@ -122,11 +122,18 @@ struct FlatClosureData;
|
||||
struct Class;
|
||||
|
||||
class RegExpObject;
|
||||
class RegExpPrivate;
|
||||
class RegExpMatcher;
|
||||
class RegExpObjectBuilder;
|
||||
class RegExpStatics;
|
||||
class MatchPairs;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class RegExpPrivate;
|
||||
class RegExpPrivateCode;
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
enum RegExpFlag
|
||||
{
|
||||
IgnoreCaseFlag = 0x01,
|
||||
@ -232,7 +239,7 @@ typedef HashMap<jsbytecode *, BreakpointSite *, DefaultHasher<jsbytecode *>, Run
|
||||
class Debugger;
|
||||
class WatchpointMap;
|
||||
|
||||
typedef HashMap<JSAtom *, RegExpPrivate *, DefaultHasher<JSAtom *>, RuntimeAllocPolicy>
|
||||
typedef HashMap<JSAtom *, detail::RegExpPrivate *, DefaultHasher<JSAtom *>, RuntimeAllocPolicy>
|
||||
RegExpPrivateCache;
|
||||
|
||||
typedef JSNative Native;
|
||||
|
@ -1271,38 +1271,33 @@ class FlatMatch
|
||||
*/
|
||||
class RegExpPair
|
||||
{
|
||||
JSContext *cx;
|
||||
AutoRefCount<RegExpPrivate> rep_;
|
||||
RegExpObject *reobj_;
|
||||
JSContext *cx;
|
||||
mutable RegExpMatcher matcher_;
|
||||
RegExpObject *reobj_;
|
||||
|
||||
explicit RegExpPair(RegExpPair &);
|
||||
void operator=(const RegExpPair &);
|
||||
explicit RegExpPair(RegExpPair &) MOZ_DELETE;
|
||||
void operator=(const RegExpPair &) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit RegExpPair(JSContext *cx) : cx(cx), rep_(cx) {}
|
||||
explicit RegExpPair(JSContext *cx) : cx(cx), matcher_(cx) {}
|
||||
|
||||
bool resetWithObject(JSContext *cx, RegExpObject *reobj) {
|
||||
JS_ASSERT(cx == this->cx);
|
||||
bool reset(RegExpObject *reobj) {
|
||||
reobj_ = reobj;
|
||||
RegExpPrivate *rep = reobj_->asRegExp()->getOrCreatePrivate(cx);
|
||||
if (!rep)
|
||||
return false;
|
||||
rep_.reset(NeedsIncRef<RegExpPrivate>(rep));
|
||||
return true;
|
||||
return matcher_.reset(reobj);
|
||||
}
|
||||
|
||||
void resetWithPrivate(AlreadyIncRefed<RegExpPrivate> rep) {
|
||||
bool reset(JSLinearString *patstr, JSString *opt) {
|
||||
reobj_ = NULL;
|
||||
rep_.reset(rep);
|
||||
return matcher_.reset(patstr, opt);
|
||||
}
|
||||
|
||||
bool null() const { return rep_.null(); }
|
||||
bool null() const { return matcher_.null(); }
|
||||
|
||||
RegExpObject *reobj() const { return reobj_; }
|
||||
|
||||
RegExpPrivate *getPrivate() const {
|
||||
RegExpMatcher *getMatcher() const {
|
||||
JS_ASSERT(!null());
|
||||
return rep_.get();
|
||||
return &matcher_;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1356,7 +1351,8 @@ class RegExpGuard
|
||||
init(uintN argc, Value *vp, bool convertVoid = false)
|
||||
{
|
||||
if (argc != 0 && ValueIsRegExp(vp[2])) {
|
||||
rep.resetWithObject(cx, vp[2].toObject().asRegExp());
|
||||
if (!rep.reset(vp[2].toObject().asRegExp()))
|
||||
return false;
|
||||
} else {
|
||||
if (convertVoid && (argc == 0 || vp[2].isUndefined())) {
|
||||
fm.patstr = cx->runtime->emptyString;
|
||||
@ -1440,10 +1436,9 @@ class RegExpGuard
|
||||
}
|
||||
JS_ASSERT(patstr);
|
||||
|
||||
AlreadyIncRefed<RegExpPrivate> re = RegExpPrivate::create(cx, patstr, opt, NULL);
|
||||
if (!re)
|
||||
if (!rep.reset(patstr, opt))
|
||||
return NULL;
|
||||
rep.resetWithPrivate(re);
|
||||
|
||||
return &rep;
|
||||
}
|
||||
|
||||
@ -1480,21 +1475,21 @@ static bool
|
||||
DoMatch(JSContext *cx, RegExpStatics *res, JSString *str, const RegExpPair ®ExpPair,
|
||||
DoMatchCallback callback, void *data, MatchControlFlags flags, Value *rval)
|
||||
{
|
||||
RegExpPrivate *rep = regExpPair.getPrivate();
|
||||
RegExpMatcher *matcher = regExpPair.getMatcher();
|
||||
JSLinearString *linearStr = str->ensureLinear(cx);
|
||||
if (!linearStr)
|
||||
return false;
|
||||
const jschar *chars = linearStr->chars();
|
||||
size_t length = linearStr->length();
|
||||
|
||||
if (rep->global()) {
|
||||
if (matcher->global()) {
|
||||
/* global matching ('g') */
|
||||
RegExpExecType type = (flags & TEST_GLOBAL_BIT) ? RegExpTest : RegExpExec;
|
||||
if (RegExpObject *reobj = regExpPair.reobj())
|
||||
reobj->zeroLastIndex();
|
||||
|
||||
for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
|
||||
if (!ExecuteRegExp(cx, res, rep, linearStr, chars, length, &i, type, rval))
|
||||
if (!ExecuteRegExp(cx, res, matcher, linearStr, chars, length, &i, type, rval))
|
||||
return false;
|
||||
if (!Matched(type, *rval))
|
||||
break;
|
||||
@ -1508,7 +1503,7 @@ DoMatch(JSContext *cx, RegExpStatics *res, JSString *str, const RegExpPair ®E
|
||||
RegExpExecType type = (flags & TEST_SINGLE_BIT) ? RegExpTest : RegExpExec;
|
||||
bool callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
|
||||
size_t i = 0;
|
||||
if (!ExecuteRegExp(cx, res, rep, linearStr, chars, length, &i, type, rval))
|
||||
if (!ExecuteRegExp(cx, res, matcher, linearStr, chars, length, &i, type, rval))
|
||||
return false;
|
||||
if (callbackOnSingle && Matched(type, *rval) && !callback(cx, res, 0, data))
|
||||
return false;
|
||||
@ -1583,7 +1578,7 @@ js::str_match(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!DoMatch(cx, res, str, *rep, MatchCallback, arg, MATCH_ARGS, &rval))
|
||||
return false;
|
||||
|
||||
if (rep->getPrivate()->global())
|
||||
if (rep->getMatcher()->global())
|
||||
vp->setObjectOrNull(array.object());
|
||||
else
|
||||
*vp = rval;
|
||||
@ -1619,7 +1614,7 @@ js::str_search(JSContext *cx, uintN argc, Value *vp)
|
||||
RegExpStatics *res = cx->regExpStatics();
|
||||
/* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
|
||||
size_t i = 0;
|
||||
if (!ExecuteRegExp(cx, res, rep->getPrivate(), linearStr, chars, length, &i, RegExpTest, vp))
|
||||
if (!ExecuteRegExp(cx, res, rep->getMatcher(), linearStr, chars, length, &i, RegExpTest, vp))
|
||||
return false;
|
||||
|
||||
if (vp->isTrue())
|
||||
@ -2407,11 +2402,11 @@ SplitHelper(JSContext *cx, JSLinearString *str, uint32 limit, Matcher splitMatch
|
||||
*/
|
||||
class SplitRegExpMatcher {
|
||||
RegExpStatics *res;
|
||||
RegExpPrivate *rep;
|
||||
RegExpMatcher *matcher;
|
||||
|
||||
public:
|
||||
static const bool returnsCaptures = true;
|
||||
SplitRegExpMatcher(RegExpPrivate *rep, RegExpStatics *res) : res(res), rep(rep) {}
|
||||
SplitRegExpMatcher(RegExpMatcher *matcher, RegExpStatics *res) : res(res), matcher(matcher) {}
|
||||
|
||||
inline bool operator()(JSContext *cx, JSLinearString *str, size_t index,
|
||||
SplitMatchResult *result) {
|
||||
@ -2422,7 +2417,7 @@ class SplitRegExpMatcher {
|
||||
;
|
||||
const jschar *chars = str->chars();
|
||||
size_t length = str->length();
|
||||
if (!ExecuteRegExp(cx, res, rep, str, chars, length, &index, RegExpTest, &rval))
|
||||
if (!ExecuteRegExp(cx, res, matcher, str, chars, length, &index, RegExpTest, &rval))
|
||||
return false;
|
||||
if (!rval.isTrue()) {
|
||||
result->setFailure();
|
||||
@ -2486,14 +2481,13 @@ js::str_split(JSContext *cx, uintN argc, Value *vp)
|
||||
}
|
||||
|
||||
/* Step 8. */
|
||||
AutoRefCount<RegExpPrivate> rep(cx);
|
||||
RegExpMatcher matcher(cx);
|
||||
JSLinearString *sepstr = NULL;
|
||||
bool sepUndefined = (argc == 0 || vp[2].isUndefined());
|
||||
if (!sepUndefined) {
|
||||
if (ValueIsRegExp(vp[2])) {
|
||||
RegExpObject *reobj = vp[2].toObject().asRegExp();
|
||||
rep.reset(NeedsIncRef<RegExpPrivate>(reobj->getOrCreatePrivate(cx)));
|
||||
if (!rep)
|
||||
if (!matcher.reset(reobj))
|
||||
return false;
|
||||
} else {
|
||||
JSString *sep = js_ValueToString(cx, vp[2]);
|
||||
@ -2533,12 +2527,12 @@ js::str_split(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
/* Steps 11-15. */
|
||||
JSObject *aobj;
|
||||
if (rep) {
|
||||
aobj = SplitHelper(cx, strlin, limit,
|
||||
SplitRegExpMatcher(rep.get(), cx->regExpStatics()), type);
|
||||
} else {
|
||||
if (matcher.null()) {
|
||||
// NB: sepstr is anchored through its storage in vp[2].
|
||||
aobj = SplitHelper(cx, strlin, limit, SplitStringMatcher(sepstr), type);
|
||||
} else {
|
||||
aobj = SplitHelper(cx, strlin, limit,
|
||||
SplitRegExpMatcher(&matcher, cx->regExpStatics()), type);
|
||||
}
|
||||
if (!aobj)
|
||||
return false;
|
||||
|
@ -6982,11 +6982,12 @@ mjit::Compiler::jsop_regexp()
|
||||
}
|
||||
|
||||
/*
|
||||
* Force creation of the RegExpPrivate in the script's RegExpObject so we take it in the
|
||||
* getNewObject template copy.
|
||||
* Force creation of the RegExpPrivate in the script's RegExpObject
|
||||
* so that we grab it in the getNewObject template copy. Note that
|
||||
* JIT code is discarded on every GC, which permits us to burn in
|
||||
* the pointer to the RegExpPrivate refcount.
|
||||
*/
|
||||
RegExpPrivate *rep = reobj->getOrCreatePrivate(cx);
|
||||
if (!rep)
|
||||
if (!reobj->makePrivateNow(cx))
|
||||
return false;
|
||||
|
||||
RegisterID result = frame.allocReg();
|
||||
@ -6999,7 +7000,7 @@ mjit::Compiler::jsop_regexp()
|
||||
OOL_STUBCALL(stubs::RegExp, REJOIN_FALLTHROUGH);
|
||||
|
||||
/* Bump the refcount on the wrapped RegExp. */
|
||||
size_t *refcount = rep->addressOfRefCount();
|
||||
size_t *refcount = reobj->addressOfPrivateRefCount();
|
||||
masm.add32(Imm32(1), AbsoluteAddress(refcount));
|
||||
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
|
||||
|
@ -93,7 +93,7 @@ class MatchPairs
|
||||
|
||||
int *buffer() { return buffer_; }
|
||||
|
||||
friend class RegExpPrivate;
|
||||
friend class detail::RegExpPrivate;
|
||||
|
||||
public:
|
||||
/*
|
||||
|
@ -89,6 +89,13 @@ HasRegExpMetaChars(const jschar *chars, size_t length)
|
||||
return false;
|
||||
}
|
||||
|
||||
inline size_t *
|
||||
RegExpObject::addressOfPrivateRefCount() const
|
||||
{
|
||||
JS_ASSERT(getPrivate());
|
||||
return getPrivate()->addressOfRefCount();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpObject::setPrivate(RegExpPrivate *rep)
|
||||
{
|
||||
@ -178,6 +185,16 @@ RegExpObject::init(JSContext *cx, JSLinearString *source, RegExpFlag flags)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpMatcher::reset(JSLinearString *patstr, JSString *opt)
|
||||
{
|
||||
AlreadyIncRefed<RegExpPrivate> priv = RegExpPrivate::create(cx, patstr, opt, NULL);
|
||||
if (!priv)
|
||||
return false;
|
||||
arc.reset(priv);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpObject::setLastIndex(const Value &v)
|
||||
{
|
||||
@ -228,8 +245,9 @@ RegExpObject::setSticky(bool enabled)
|
||||
|
||||
/* RegExpPrivate inlines. */
|
||||
|
||||
inline AlreadyIncRefed<RegExpPrivate>
|
||||
RegExpPrivate::create(JSContext *cx, JSLinearString *source, RegExpFlag flags, TokenStream *ts)
|
||||
inline AlreadyIncRefed<detail::RegExpPrivate>
|
||||
detail::RegExpPrivate::create(JSContext *cx, JSLinearString *source, RegExpFlag flags,
|
||||
TokenStream *ts)
|
||||
{
|
||||
typedef AlreadyIncRefed<RegExpPrivate> RetType;
|
||||
|
||||
@ -284,7 +302,7 @@ RegExpPrivate::create(JSContext *cx, JSLinearString *source, RegExpFlag flags, T
|
||||
|
||||
/* This function should be deleted once bad Android platforms phase out. See bug 604774. */
|
||||
inline bool
|
||||
RegExpPrivateCode::isJITRuntimeEnabled(JSContext *cx)
|
||||
detail::RegExpPrivateCode::isJITRuntimeEnabled(JSContext *cx)
|
||||
{
|
||||
#if defined(ANDROID) && defined(JS_TRACER) && defined(JS_METHODJIT)
|
||||
return cx->traceJitEnabled || cx->methodJitEnabled;
|
||||
@ -294,8 +312,8 @@ RegExpPrivateCode::isJITRuntimeEnabled(JSContext *cx)
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpPrivateCode::compile(JSContext *cx, JSLinearString &pattern, TokenStream *ts,
|
||||
uintN *parenCount, RegExpFlag flags)
|
||||
detail::RegExpPrivateCode::compile(JSContext *cx, JSLinearString &pattern, TokenStream *ts,
|
||||
uintN *parenCount, RegExpFlag flags)
|
||||
{
|
||||
#if ENABLE_YARR_JIT
|
||||
/* Parse the pattern. */
|
||||
@ -344,7 +362,7 @@ RegExpPrivateCode::compile(JSContext *cx, JSLinearString &pattern, TokenStream *
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpPrivate::compile(JSContext *cx, TokenStream *ts)
|
||||
detail::RegExpPrivate::compile(JSContext *cx, TokenStream *ts)
|
||||
{
|
||||
if (!sticky())
|
||||
return code.compile(cx, *source, ts, &parenCount, getFlags());
|
||||
@ -371,8 +389,8 @@ RegExpPrivate::compile(JSContext *cx, TokenStream *ts)
|
||||
}
|
||||
|
||||
inline RegExpRunStatus
|
||||
RegExpPrivateCode::execute(JSContext *cx, const jschar *chars, size_t length, size_t start,
|
||||
int *output, size_t outputCount)
|
||||
detail::RegExpPrivateCode::execute(JSContext *cx, const jschar *chars, size_t length, size_t start,
|
||||
int *output, size_t outputCount)
|
||||
{
|
||||
int result;
|
||||
#if ENABLE_YARR_JIT
|
||||
@ -400,13 +418,13 @@ RegExpPrivateCode::execute(JSContext *cx, const jschar *chars, size_t length, si
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpPrivate::incref(JSContext *cx)
|
||||
detail::RegExpPrivate::incref(JSContext *cx)
|
||||
{
|
||||
++refCount;
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpPrivate::decref(JSContext *cx)
|
||||
detail::RegExpPrivate::decref(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_OPT_ASSERT_IF(cx->runtime->gcHelperThread.getThread(),
|
||||
@ -423,7 +441,13 @@ RegExpPrivate::decref(JSContext *cx)
|
||||
cache->remove(ptr);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
this->~RegExpPrivate();
|
||||
memset(this, 0xcd, sizeof(*this));
|
||||
cx->free_(this);
|
||||
#else
|
||||
cx->delete_(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -54,6 +54,8 @@ using namespace nanojit;
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
using js::detail::RegExpPrivate;
|
||||
using js::detail::RegExpPrivateCode;
|
||||
|
||||
JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
|
||||
JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
|
||||
|
@ -65,6 +65,9 @@ enum RegExpRunStatus
|
||||
|
||||
class RegExpObject : public ::JSObject
|
||||
{
|
||||
typedef detail::RegExpPrivate RegExpPrivate;
|
||||
typedef detail::RegExpPrivateCode RegExpPrivateCode;
|
||||
|
||||
static const uintN LAST_INDEX_SLOT = 0;
|
||||
static const uintN SOURCE_SLOT = 1;
|
||||
static const uintN GLOBAL_FLAG_SLOT = 2;
|
||||
@ -131,6 +134,10 @@ class RegExpObject : public ::JSObject
|
||||
return RegExpFlag(flags);
|
||||
}
|
||||
|
||||
/* JIT only. */
|
||||
|
||||
inline size_t *addressOfPrivateRefCount() const;
|
||||
|
||||
/* Flags. */
|
||||
|
||||
inline void setIgnoreCase(bool enabled);
|
||||
@ -147,6 +154,20 @@ class RegExpObject : public ::JSObject
|
||||
/* Clear out lazy |RegExpPrivate|. */
|
||||
inline void purge(JSContext *x);
|
||||
|
||||
/*
|
||||
* Trigger an eager creation of the associated RegExpPrivate. Note
|
||||
* that a GC may purge it away.
|
||||
*/
|
||||
bool makePrivateNow(JSContext *cx) {
|
||||
return !!makePrivate(cx);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegExpObjectBuilder;
|
||||
friend class RegExpMatcher;
|
||||
|
||||
inline bool init(JSContext *cx, JSLinearString *source, RegExpFlag flags);
|
||||
|
||||
RegExpPrivate *getOrCreatePrivate(JSContext *cx) {
|
||||
if (RegExpPrivate *rep = getPrivate())
|
||||
return rep;
|
||||
@ -154,11 +175,6 @@ class RegExpObject : public ::JSObject
|
||||
return makePrivate(cx);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RegExpObjectBuilder;
|
||||
|
||||
inline bool init(JSContext *cx, JSLinearString *source, RegExpFlag flags);
|
||||
|
||||
/* The |RegExpPrivate| is lazily created at the time of use. */
|
||||
RegExpPrivate *getPrivate() const {
|
||||
return static_cast<RegExpPrivate *>(JSObject::getPrivate());
|
||||
@ -189,12 +205,16 @@ class RegExpObject : public ::JSObject
|
||||
/* Either builds a new RegExpObject or re-initializes an existing one. */
|
||||
class RegExpObjectBuilder
|
||||
{
|
||||
typedef detail::RegExpPrivate RegExpPrivate;
|
||||
|
||||
JSContext *cx;
|
||||
RegExpObject *reobj_;
|
||||
|
||||
bool getOrCreate();
|
||||
bool getOrCreateClone(RegExpObject *proto);
|
||||
|
||||
RegExpObject *build(AlreadyIncRefed<RegExpPrivate> rep);
|
||||
|
||||
public:
|
||||
RegExpObjectBuilder(JSContext *cx, RegExpObject *reobj = NULL)
|
||||
: cx(cx), reobj_(reobj)
|
||||
@ -202,9 +222,6 @@ class RegExpObjectBuilder
|
||||
|
||||
RegExpObject *reobj() { return reobj_; }
|
||||
|
||||
/* Note: In case of failure, |rep| will be decrefed. */
|
||||
RegExpObject *build(AlreadyIncRefed<RegExpPrivate> rep);
|
||||
|
||||
RegExpObject *build(JSLinearString *str, RegExpFlag flags);
|
||||
RegExpObject *build(RegExpObject *other);
|
||||
|
||||
@ -212,6 +229,8 @@ class RegExpObjectBuilder
|
||||
RegExpObject *clone(RegExpObject *other, RegExpObject *proto);
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* Abstracts away the gross |RegExpPrivate| backend details. */
|
||||
class RegExpPrivateCode
|
||||
{
|
||||
@ -356,6 +375,55 @@ class RegExpPrivate
|
||||
bool sticky() const { return flags & StickyFlag; }
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
/*
|
||||
* Wraps the RegExpObject's internals in a recount-safe interface for
|
||||
* use in RegExp execution. This is used in situations where we'd like
|
||||
* to avoid creating a full-fledged RegExpObject. This interface is
|
||||
* provided in lieu of exposing the RegExpPrivate directly.
|
||||
*
|
||||
* Note: this exposes precisely the execute interface of a RegExpObject.
|
||||
*/
|
||||
class RegExpMatcher
|
||||
{
|
||||
typedef detail::RegExpPrivate RegExpPrivate;
|
||||
|
||||
JSContext *cx;
|
||||
AutoRefCount<RegExpPrivate> arc;
|
||||
|
||||
public:
|
||||
explicit RegExpMatcher(JSContext *cx)
|
||||
: cx(cx), arc(cx)
|
||||
{ }
|
||||
|
||||
bool null() const {
|
||||
return arc.null();
|
||||
}
|
||||
bool global() const {
|
||||
return arc.get()->global();
|
||||
}
|
||||
bool sticky() const {
|
||||
return arc.get()->sticky();
|
||||
}
|
||||
|
||||
bool reset(RegExpObject *reobj) {
|
||||
RegExpPrivate *priv = reobj->getOrCreatePrivate(cx);
|
||||
if (!priv)
|
||||
return false;
|
||||
arc.reset(NeedsIncRef<RegExpPrivate>(priv));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool reset(JSLinearString *patstr, JSString *opt);
|
||||
|
||||
RegExpRunStatus execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
|
||||
LifoAllocScope &allocScope, MatchPairs **output) {
|
||||
JS_ASSERT(!arc.null());
|
||||
return arc.get()->execute(cx, chars, length, lastIndex, allocScope, output);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse regexp flags. Report an error and return false if an invalid
|
||||
* sequence of flags is encountered (repeat/invalid flag).
|
||||
@ -371,6 +439,12 @@ ValueIsRegExp(const Value &v);
|
||||
inline bool
|
||||
IsRegExpMetaChar(jschar c);
|
||||
|
||||
inline bool
|
||||
CheckRegExpSyntax(JSContext *cx, JSLinearString *str)
|
||||
{
|
||||
return detail::RegExpPrivateCode::checkSyntax(cx, NULL, str);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(JSObject *) JS_FASTCALL
|
||||
|
Loading…
Reference in New Issue
Block a user