AlreadyIncRefed<RegExpPrivate>
RegExpPrivate::createTestOptimized(JSContext *cx, JSAtom *cacheKey, RegExpFlag flags)
{
    typedef AlreadyIncRefed<RegExpPrivate> RetType;

    RetType cached;
    if (!cacheLookup(cx, cacheKey, flags, RegExpPrivateCache_TestOptimized, &cached))
        return RetType(NULL);

    if (cached)
        return cached;

    /* Strip off the greedy star characters, create a new RegExpPrivate, and cache. */
    JS_ASSERT(cacheKey->length() > JS_ARRAY_LENGTH(GreedyStarChars));
    JSDependentString *stripped =
      JSDependentString::new_(cx, cacheKey, cacheKey->chars() + JS_ARRAY_LENGTH(GreedyStarChars),
                              cacheKey->length() - JS_ARRAY_LENGTH(GreedyStarChars));
    if (!stripped)
        return RetType(NULL);

    RegExpPrivate *priv = createUncached(cx, cacheKey, flags, NULL);
    if (!priv)
        return RetType(NULL);

    if (!cacheInsert(cx, cacheKey, RegExpPrivateCache_TestOptimized, priv)) {
        priv->decref(cx);
        return RetType(NULL);
    }

    return RetType(priv);
}
RegExpObject *
RegExpObjectBuilder::clone(RegExpObject *other, RegExpObject *proto)
{
    if (!getOrCreateClone(proto))
        return NULL;

    /*
     * Check that the RegExpPrivate for the original is okay to use in
     * the clone -- if the |RegExpStatics| provides more flags we'll
     * need a different |RegExpPrivate|.
     */
    RegExpStatics *res = cx->regExpStatics();
    RegExpFlag origFlags = other->getFlags();
    RegExpFlag staticsFlags = res->getFlags();
    if ((origFlags & staticsFlags) != staticsFlags) {
        RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags);
        return build(other->getSource(), newFlags);
    }

    RegExpPrivate *toShare = other->getOrCreatePrivate(cx);
    if (!toShare)
        return NULL;

    toShare->incref(cx);
    return build(AlreadyIncRefed<RegExpPrivate>(toShare));
}
RegExpObject *
RegExpObjectBuilder::build(RegExpObject *other)
{
    RegExpPrivate *rep = other->getOrCreatePrivate(cx);
    if (!rep)
        return NULL;

    /* Now, incref it for the RegExpObject being built. */
    rep->incref(cx);
    return build(AlreadyIncRefed<RegExpPrivate>(rep));
}
RegExpPrivate *
RegExpPrivate::createUncached(JSContext *cx, JSLinearString *source, RegExpFlag flags,
                              TokenStream *tokenStream)
{
    RegExpPrivate *priv = cx->new_<RegExpPrivate>(source, flags);
    if (!priv)
        return NULL;

    if (!priv->compile(cx, tokenStream)) {
        Foreground::delete_(priv);
        return NULL;
    }

    return priv;
}
Example #5
0
/*
 * Compile a new |RegExpPrivate| for the |RegExpObject|.
 *
 * Per ECMAv5 15.10.4.1, we act on combinations of (pattern, flags) as
 * arguments:
 *
 *  RegExp, undefined => flags := pattern.flags
 *  RegExp, _ => throw TypeError
 *  _ => pattern := ToString(pattern) if defined(pattern) else ''
 *       flags := ToString(flags) if defined(flags) else ''
 */
static bool
CompileRegExpObject(JSContext *cx, RegExpObject *obj, uintN argc, Value *argv, Value *rval)
{
    if (argc == 0) {
        if (!ResetRegExpObjectWithStatics(cx, obj, cx->runtime->emptyString))
            return false;
        *rval = ObjectValue(*obj);
        return true;
    }

    Value sourceValue = argv[0];
    if (ValueIsRegExp(sourceValue)) {
        /*
         * If we get passed in a |RegExpObject| source we return a new
         * object with the same |RegExpPrivate|.
         *
         * Note: the regexp static flags are not taken into consideration here.
         */
        JSObject &sourceObj = sourceValue.toObject();
        if (argc >= 2 && !argv[1].isUndefined()) {
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
            return false;
        }

        RegExpPrivate *rep = sourceObj.asRegExp()->getPrivate();
        if (!rep)
            return false;

        rep->incref(cx);
        if (!ResetRegExpObject(cx, obj, AlreadyIncRefed<RegExpPrivate>(rep)))
            return false;
        *rval = ObjectValue(*obj);
        return true;
    }

    JSString *sourceStr;
    if (sourceValue.isUndefined()) {
        sourceStr = cx->runtime->emptyString;
    } else {
        /* Coerce to string and compile. */
        sourceStr = js_ValueToString(cx, sourceValue);
        if (!sourceStr)
            return false;
    }

    RegExpFlag flags = RegExpFlag(0);
    if (argc > 1 && !argv[1].isUndefined()) {
        JSString *flagStr = js_ValueToString(cx, argv[1]);
        if (!flagStr)
            return false;
        argv[1].setString(flagStr);
        if (!ParseRegExpFlags(cx, flagStr, &flags))
            return false;
    }

    JSString *escapedSourceStr = EscapeNakedForwardSlashes(cx, sourceStr);
    if (!escapedSourceStr)
        return false;

    if (!ResetRegExpObjectWithStatics(cx, obj, escapedSourceStr, flags))
        return false;
    *rval = ObjectValue(*obj);
    return true;
}