зеркало из https://github.com/mozilla/pjs.git
Merge.
This commit is contained in:
Коммит
46cc50ab96
|
@ -5522,8 +5522,19 @@ JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_ClearRegExpStatics(JSContext *cx)
|
JS_ClearRegExpStatics(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
JSRegExpStatics *res;
|
||||||
|
|
||||||
/* No locking required, cx is thread-private and input must be live. */
|
/* No locking required, cx is thread-private and input must be live. */
|
||||||
cx->regExpStatics.clear();
|
res = &cx->regExpStatics;
|
||||||
|
res->input = NULL;
|
||||||
|
res->multiline = JS_FALSE;
|
||||||
|
res->parenCount = 0;
|
||||||
|
res->lastMatch = res->lastParen = js_EmptySubString;
|
||||||
|
res->leftContext = res->rightContext = js_EmptySubString;
|
||||||
|
if (res->moreParens) {
|
||||||
|
cx->free(res->moreParens);
|
||||||
|
res->moreParens = NULL;
|
||||||
|
}
|
||||||
cx->runtime->gcPoke = JS_TRUE;
|
cx->runtime->gcPoke = JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1180,42 +1180,9 @@ namespace js {
|
||||||
class AutoGCRooter;
|
class AutoGCRooter;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JSRegExpStatics {
|
|
||||||
JSString *input; /* input string to match (perl $_, GC root) */
|
|
||||||
JSBool multiline; /* whether input contains newlines (perl $*) */
|
|
||||||
JSSubString lastMatch; /* last string matched (perl $&) */
|
|
||||||
JSSubString lastParen; /* last paren matched (perl $+) */
|
|
||||||
JSSubString leftContext; /* input to left of last match (perl $`) */
|
|
||||||
JSSubString rightContext; /* input to right of last match (perl $') */
|
|
||||||
js::Vector<JSSubString> parens; /* last set of parens matched (perl $1, $2) */
|
|
||||||
|
|
||||||
JSRegExpStatics(JSContext *cx) : parens(cx) {}
|
|
||||||
|
|
||||||
bool copy(const JSRegExpStatics& other) {
|
|
||||||
input = other.input;
|
|
||||||
multiline = other.multiline;
|
|
||||||
lastMatch = other.lastMatch;
|
|
||||||
lastParen = other.lastParen;
|
|
||||||
leftContext = other.leftContext;
|
|
||||||
rightContext = other.rightContext;
|
|
||||||
if (!parens.resize(other.parens.length()))
|
|
||||||
return false;
|
|
||||||
memcpy(parens.begin(), other.parens.begin(), sizeof(JSSubString) * parens.length());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
input = NULL;
|
|
||||||
multiline = false;
|
|
||||||
lastMatch = lastParen = leftContext = rightContext = js_EmptySubString;
|
|
||||||
parens.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JSContext
|
struct JSContext
|
||||||
{
|
{
|
||||||
explicit JSContext(JSRuntime *rt) :
|
explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {}
|
||||||
runtime(rt), regExpStatics(this), busyArrays(this) {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this flag is set, we were asked to call back the operation callback
|
* If this flag is set, we were asked to call back the operation callback
|
||||||
|
@ -1301,7 +1268,7 @@ struct JSContext
|
||||||
/* Storage to root recently allocated GC things and script result. */
|
/* Storage to root recently allocated GC things and script result. */
|
||||||
JSWeakRoots weakRoots;
|
JSWeakRoots weakRoots;
|
||||||
|
|
||||||
/* Regular expression class statics. */
|
/* Regular expression class statics (XXX not shared globally). */
|
||||||
JSRegExpStatics regExpStatics;
|
JSRegExpStatics regExpStatics;
|
||||||
|
|
||||||
/* State for object and array toSource conversion. */
|
/* State for object and array toSource conversion. */
|
||||||
|
|
|
@ -4865,10 +4865,11 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
|
||||||
|
|
||||||
const jschar *cp, *ep;
|
const jschar *cp, *ep;
|
||||||
size_t i, length, start;
|
size_t i, length, start;
|
||||||
|
JSSubString *morepar;
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
JSRegExpStatics *res;
|
JSRegExpStatics *res;
|
||||||
ptrdiff_t matchlen;
|
ptrdiff_t matchlen;
|
||||||
uintN num;
|
uintN num, morenum;
|
||||||
JSString *parstr, *matchstr;
|
JSString *parstr, *matchstr;
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
|
|
||||||
|
@ -4972,22 +4973,45 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
|
||||||
|
|
||||||
res = &cx->regExpStatics;
|
res = &cx->regExpStatics;
|
||||||
res->input = str;
|
res->input = str;
|
||||||
if (!res->parens.resize(re->parenCount)) {
|
res->parenCount = uint16(re->parenCount);
|
||||||
ok = JS_FALSE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (re->parenCount == 0) {
|
if (re->parenCount == 0) {
|
||||||
res->lastParen = js_EmptySubString;
|
res->lastParen = js_EmptySubString;
|
||||||
} else {
|
} else {
|
||||||
for (num = 0; num < re->parenCount; num++) {
|
for (num = 0; num < re->parenCount; num++) {
|
||||||
JSSubString *sub = &res->parens[num];
|
|
||||||
parsub = &result->parens[num];
|
parsub = &result->parens[num];
|
||||||
if (parsub->index == -1) {
|
if (num < 9) {
|
||||||
sub->chars = NULL;
|
if (parsub->index == -1) {
|
||||||
sub->length = 0;
|
res->parens[num].chars = NULL;
|
||||||
|
res->parens[num].length = 0;
|
||||||
|
} else {
|
||||||
|
res->parens[num].chars = gData.cpbegin + parsub->index;
|
||||||
|
res->parens[num].length = parsub->length;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sub->chars = gData.cpbegin + parsub->index;
|
morenum = num - 9;
|
||||||
sub->length = parsub->length;
|
morepar = res->moreParens;
|
||||||
|
if (!morepar) {
|
||||||
|
res->moreLength = 10;
|
||||||
|
morepar = (JSSubString*)
|
||||||
|
cx->malloc(10 * sizeof(JSSubString));
|
||||||
|
} else if (morenum >= res->moreLength) {
|
||||||
|
res->moreLength += 10;
|
||||||
|
morepar = (JSSubString*)
|
||||||
|
cx->realloc(morepar,
|
||||||
|
res->moreLength * sizeof(JSSubString));
|
||||||
|
}
|
||||||
|
if (!morepar) {
|
||||||
|
ok = JS_FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
res->moreParens = morepar;
|
||||||
|
if (parsub->index == -1) {
|
||||||
|
morepar[morenum].chars = NULL;
|
||||||
|
morepar[morenum].length = 0;
|
||||||
|
} else {
|
||||||
|
morepar[morenum].chars = gData.cpbegin + parsub->index;
|
||||||
|
morepar[morenum].length = parsub->length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (test)
|
if (test)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5185,9 +5209,14 @@ JS_FRIEND_API(void)
|
||||||
js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
|
js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
|
||||||
AutoValueRooter *tvr)
|
AutoValueRooter *tvr)
|
||||||
{
|
{
|
||||||
statics->copy(cx->regExpStatics);
|
*statics = cx->regExpStatics;
|
||||||
if (statics->input)
|
if (statics->input)
|
||||||
tvr->setString(statics->input);
|
tvr->setString(statics->input);
|
||||||
|
/*
|
||||||
|
* Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only
|
||||||
|
* moved it elsewhere (into statics->moreParens).
|
||||||
|
*/
|
||||||
|
cx->regExpStatics.moreParens = NULL;
|
||||||
JS_ClearRegExpStatics(cx);
|
JS_ClearRegExpStatics(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5196,7 +5225,8 @@ js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
|
||||||
AutoValueRooter *tvr)
|
AutoValueRooter *tvr)
|
||||||
{
|
{
|
||||||
/* Clear/free any new JSRegExpStatics data before clobbering. */
|
/* Clear/free any new JSRegExpStatics data before clobbering. */
|
||||||
cx->regExpStatics.copy(*statics);
|
JS_ClearRegExpStatics(cx);
|
||||||
|
cx->regExpStatics = *statics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5248,7 +5278,7 @@ regexp_static_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||||
sub = &res->rightContext;
|
sub = &res->rightContext;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sub = (size_t(slot) < res->parens.length()) ? &res->parens[slot] : &js_EmptySubString;
|
sub = REGEXP_PAREN_SUBSTRING(res, slot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str = js_NewStringCopyN(cx, sub->chars, sub->length);
|
str = js_NewStringCopyN(cx, sub->chars, sub->length);
|
||||||
|
|
|
@ -52,6 +52,19 @@
|
||||||
|
|
||||||
JS_BEGIN_EXTERN_C
|
JS_BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
struct JSRegExpStatics {
|
||||||
|
JSString *input; /* input string to match (perl $_, GC root) */
|
||||||
|
JSBool multiline; /* whether input contains newlines (perl $*) */
|
||||||
|
uint16 parenCount; /* number of valid elements in parens[] */
|
||||||
|
uint16 moreLength; /* number of allocated elements in moreParens */
|
||||||
|
JSSubString parens[9]; /* last set of parens matched (perl $1, $2) */
|
||||||
|
JSSubString *moreParens; /* null or realloc'd vector for $10, etc. */
|
||||||
|
JSSubString lastMatch; /* last string matched (perl $&) */
|
||||||
|
JSSubString lastParen; /* last paren matched (perl $+) */
|
||||||
|
JSSubString leftContext; /* input to left of last match (perl $`) */
|
||||||
|
JSSubString rightContext; /* input to right of last match (perl $') */
|
||||||
|
};
|
||||||
|
|
||||||
namespace js { class AutoValueRooter; }
|
namespace js { class AutoValueRooter; }
|
||||||
|
|
||||||
extern JS_FRIEND_API(void)
|
extern JS_FRIEND_API(void)
|
||||||
|
@ -83,6 +96,17 @@ typedef struct RECharSet {
|
||||||
} u;
|
} u;
|
||||||
} RECharSet;
|
} RECharSet;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This macro is safe because moreParens is guaranteed to be allocated and big
|
||||||
|
* enough to hold parenCount, or else be null when parenCount is 0.
|
||||||
|
*/
|
||||||
|
#define REGEXP_PAREN_SUBSTRING(res, num) \
|
||||||
|
(((jsuint)(num) < (jsuint)(res)->parenCount) \
|
||||||
|
? ((jsuint)(num) < 9) \
|
||||||
|
? &(res)->parens[num] \
|
||||||
|
: &(res)->moreParens[(num) - 9] \
|
||||||
|
: &js_EmptySubString)
|
||||||
|
|
||||||
typedef struct RENode RENode;
|
typedef struct RENode RENode;
|
||||||
|
|
||||||
struct JSRegExp {
|
struct JSRegExp {
|
||||||
|
|
|
@ -1719,13 +1719,13 @@ InterpretDollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData &rdata,
|
||||||
if (JS7_ISDEC(dc)) {
|
if (JS7_ISDEC(dc)) {
|
||||||
/* ECMA-262 Edition 3: 1-9 or 01-99 */
|
/* ECMA-262 Edition 3: 1-9 or 01-99 */
|
||||||
num = JS7_UNDEC(dc);
|
num = JS7_UNDEC(dc);
|
||||||
if (num > res->parens.length())
|
if (num > res->parenCount)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cp = dp + 2;
|
cp = dp + 2;
|
||||||
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
|
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
|
||||||
tmp = 10 * num + JS7_UNDEC(dc);
|
tmp = 10 * num + JS7_UNDEC(dc);
|
||||||
if (tmp <= res->parens.length()) {
|
if (tmp <= res->parenCount) {
|
||||||
cp++;
|
cp++;
|
||||||
num = tmp;
|
num = tmp;
|
||||||
}
|
}
|
||||||
|
@ -1736,7 +1736,7 @@ InterpretDollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData &rdata,
|
||||||
/* Adjust num from 1 $n-origin to 0 array-index-origin. */
|
/* Adjust num from 1 $n-origin to 0 array-index-origin. */
|
||||||
num--;
|
num--;
|
||||||
*skip = cp - dp;
|
*skip = cp - dp;
|
||||||
return (num < res->parens.length()) ? &res->parens[num] : &js_EmptySubString;
|
return REGEXP_PAREN_SUBSTRING(res, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
*skip = 2;
|
*skip = 2;
|
||||||
|
@ -1780,6 +1780,8 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
|
|
||||||
lambda = rdata.lambda;
|
lambda = rdata.lambda;
|
||||||
if (lambda) {
|
if (lambda) {
|
||||||
|
uintN i, m, n;
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1800,6 +1802,18 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
}
|
}
|
||||||
jsval* invokevp = rdata.invokevp;
|
jsval* invokevp = rdata.invokevp;
|
||||||
|
|
||||||
|
MUST_FLOW_THROUGH("lambda_out");
|
||||||
|
bool ok = false;
|
||||||
|
bool freeMoreParens = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the regExpStatics from the current regexp, since they may be
|
||||||
|
* clobbered by a RegExp usage in the lambda function. Note that all
|
||||||
|
* members of JSRegExpStatics are JSSubStrings, so not GC roots, save
|
||||||
|
* input, which is rooted otherwise via vp[1] in str_replace.
|
||||||
|
*/
|
||||||
|
JSRegExpStatics save = cx->regExpStatics;
|
||||||
|
|
||||||
/* Push lambda and its 'this' parameter. */
|
/* Push lambda and its 'this' parameter. */
|
||||||
jsval *sp = invokevp;
|
jsval *sp = invokevp;
|
||||||
*sp++ = OBJECT_TO_JSVAL(lambda);
|
*sp++ = OBJECT_TO_JSVAL(lambda);
|
||||||
|
@ -1807,13 +1821,27 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
|
|
||||||
/* Push $&, $1, $2, ... */
|
/* Push $&, $1, $2, ... */
|
||||||
if (!PushRegExpSubstr(cx, cx->regExpStatics.lastMatch, sp))
|
if (!PushRegExpSubstr(cx, cx->regExpStatics.lastMatch, sp))
|
||||||
return false;
|
goto lambda_out;
|
||||||
|
|
||||||
uintN i = 0;
|
i = 0;
|
||||||
for (uintN n = cx->regExpStatics.parens.length(); i < n; i++) {
|
m = cx->regExpStatics.parenCount;
|
||||||
if (!PushRegExpSubstr(cx, cx->regExpStatics.parens[i], sp))
|
n = JS_MIN(m, 9);
|
||||||
return false;
|
for (uintN j = 0; i < n; i++, j++) {
|
||||||
|
if (!PushRegExpSubstr(cx, cx->regExpStatics.parens[j], sp))
|
||||||
|
goto lambda_out;
|
||||||
}
|
}
|
||||||
|
for (uintN j = 0; i < m; i++, j++) {
|
||||||
|
if (!PushRegExpSubstr(cx, cx->regExpStatics.moreParens[j], sp))
|
||||||
|
goto lambda_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to clear moreParens in the top-of-stack cx->regExpStatics
|
||||||
|
* so it won't be possibly realloc'ed, leaving the bottom-of-stack
|
||||||
|
* moreParens pointing to freed memory.
|
||||||
|
*/
|
||||||
|
cx->regExpStatics.moreParens = NULL;
|
||||||
|
freeMoreParens = true;
|
||||||
|
|
||||||
/* Make sure to push undefined for any unmatched parens. */
|
/* Make sure to push undefined for any unmatched parens. */
|
||||||
for (; i < p; i++)
|
for (; i < p; i++)
|
||||||
|
@ -1824,7 +1852,7 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
*sp++ = STRING_TO_JSVAL(rdata.str);
|
*sp++ = STRING_TO_JSVAL(rdata.str);
|
||||||
|
|
||||||
if (!js_Invoke(cx, argc, invokevp, 0))
|
if (!js_Invoke(cx, argc, invokevp, 0))
|
||||||
return false;
|
goto lambda_out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NB: we count on the newborn string root to hold any string
|
* NB: we count on the newborn string root to hold any string
|
||||||
|
@ -1833,12 +1861,18 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
*/
|
*/
|
||||||
repstr = js_ValueToString(cx, *invokevp);
|
repstr = js_ValueToString(cx, *invokevp);
|
||||||
if (!repstr)
|
if (!repstr)
|
||||||
return false;
|
goto lambda_out;
|
||||||
|
|
||||||
rdata.repstr = repstr;
|
rdata.repstr = repstr;
|
||||||
*sizep = repstr->length();
|
*sizep = repstr->length();
|
||||||
|
|
||||||
return true;
|
ok = true;
|
||||||
|
|
||||||
|
lambda_out:
|
||||||
|
if (freeMoreParens)
|
||||||
|
cx->free(cx->regExpStatics.moreParens);
|
||||||
|
cx->regExpStatics = save;
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
repstr = rdata.repstr;
|
repstr = rdata.repstr;
|
||||||
|
@ -2178,11 +2212,10 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
|
||||||
* substring that was delimited.
|
* substring that was delimited.
|
||||||
*/
|
*/
|
||||||
if (re && sep->chars) {
|
if (re && sep->chars) {
|
||||||
JSRegExpStatics *res = &cx->regExpStatics;
|
for (uintN num = 0; num < cx->regExpStatics.parenCount; num++) {
|
||||||
for (uintN num = 0; num < res->parens.length(); num++) {
|
|
||||||
if (limited && len >= limit)
|
if (limited && len >= limit)
|
||||||
break;
|
break;
|
||||||
JSSubString *parsub = &res->parens[num];
|
JSSubString *parsub = REGEXP_PAREN_SUBSTRING(&cx->regExpStatics, num);
|
||||||
sub = js_NewStringCopyN(cx, parsub->chars, parsub->length);
|
sub = js_NewStringCopyN(cx, parsub->chars, parsub->length);
|
||||||
if (!sub || !splits.push(sub))
|
if (!sub || !splits.push(sub))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -534,7 +534,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||||
NS_STACK_CLASS class SafeCallGuard {
|
NS_STACK_CLASS class SafeCallGuard {
|
||||||
public:
|
public:
|
||||||
SafeCallGuard(JSContext *cx, nsIPrincipal *principal)
|
SafeCallGuard(JSContext *cx, nsIPrincipal *principal)
|
||||||
: cx(cx), statics(cx), tvr(cx) {
|
: cx(cx), tvr(cx) {
|
||||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||||
if (ssm) {
|
if (ssm) {
|
||||||
// Note: We pass null as the target frame pointer because we know that
|
// Note: We pass null as the target frame pointer because we know that
|
||||||
|
|
Загрузка…
Ссылка в новой задаче