if (cx->regExpStatics.moreParens) JS_free(cx, cx->regExpStatics.moreParens);
JS_free(cx, cx->regExpStatics.moreParens);
find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep){    JSString *repstr;    size_t replen, skip;    jschar *dp, *ep;    JSSubString *sub;#if JS_HAS_REPLACE_LAMBDA    JSObject *lambda;    lambda = rdata->lambda;    if (lambda) {        uintN argc, i, j, m, n, p;        jsval *sp, *oldsp, rval;        void *mark;        JSStackFrame *fp;        JSBool ok;        /*         * 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 argv[-1] in str_replace.         *         * We need to clear moreParens in the top-of-stack cx->regExpStatics         * to it won't be possibly realloc'ed, leaving the bottom-of-stack         * moreParens pointing to freed memory.         */        JSRegExpStatics save = cx->regExpStatics;        cx->regExpStatics.moreParens = NULL;        /*         * In the lambda case, not only do we find the replacement string's         * length, we compute repstr and return it via rdata for use within         * do_replace.  The lambda is called with arguments ($&, $1, $2, ...,         * index, input), i.e., all the properties of a regexp match array.         * For $&, etc., we must create string jsvals from cx->regExpStatics.         * We grab up stack space to keep the newborn strings GC-rooted.         */        p = rdata->base.regexp->parenCount;        argc = 1 + p + 2;        sp = js_AllocStack(cx, 2 + argc, &mark);        if (!sp)            return JS_FALSE;        /* Push lambda and its 'this' parameter. */        *sp++ = OBJECT_TO_JSVAL(lambda);        *sp++ = OBJECT_TO_JSVAL(OBJ_GET_PARENT(cx, lambda));#define PUSH_REGEXP_STATIC(sub)                                               \    JS_BEGIN_MACRO                                                            \        JSString *str = js_NewStringCopyN(cx,                                 \                                          cx->regExpStatics.sub.chars,        \                                          cx->regExpStatics.sub.length,       \                                          0);                                 \        if (!str) {                                                           \            ok = JS_FALSE;                                                    \            goto lambda_out;                                                  \        }                                                                     \        *sp++ = STRING_TO_JSVAL(str);                                         \    JS_END_MACRO        /* Push $&, $1, $2, ... */        PUSH_REGEXP_STATIC(lastMatch);        i = 0;        m = cx->regExpStatics.parenCount;        n = JS_MIN(m, 9);        for (j = 0; i < n; i++, j++)            PUSH_REGEXP_STATIC(parens[j]);        for (j = 0; i < m; i++, j++)            PUSH_REGEXP_STATIC(moreParens[j]);#undef PUSH_REGEXP_STATIC        /* Make sure to push undefined for any unmatched parens. */        for (; i < p; i++)            *sp++ = JSVAL_VOID;        /* Push match index and input string. */        *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);        *sp++ = STRING_TO_JSVAL(rdata->base.str);        /* Lift current frame to include the args and do the call. */        fp = cx->fp;        oldsp = fp->sp;        fp->sp = sp;        ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL);        rval = fp->sp[-1];        fp->sp = oldsp;        if (ok) {            /*             * NB: we count on the newborn string root to hold any string             * created by this js_ValueToString that would otherwise be GC-             * able, until we use rdata->repstr in do_replace.             */            repstr = js_ValueToString(cx, rval);            if (!repstr) {                ok = JS_FALSE;            } else {                rdata->repstr = repstr;                *sizep = JSSTRING_LENGTH(repstr);            }        }      lambda_out:        js_FreeStack(cx, mark);        if (cx->regExpStatics.moreParens)            JS_free(cx, cx->regExpStatics.moreParens);        cx->regExpStatics = save;        return ok;    }#endif /* JS_HAS_REPLACE_LAMBDA */    repstr = rdata->repstr;    replen = JSSTRING_LENGTH(repstr);    for (dp = rdata->dollar, ep = rdata->dollarEnd; dp;         dp = js_strchr_limit(dp, '$', ep)) {        sub = interpret_dollar(cx, dp, rdata, &skip);        if (sub) {            replen += sub->length - skip;            dp += skip;        }        else            dp++;    }    *sizep = replen;    return JS_TRUE;}