bool
ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, T *re, JSLinearString *input,
                  const jschar *chars, size_t length,
                  size_t *lastIndex, RegExpExecType type, Value *rval)
{
    LifoAllocScope allocScope(&cx->tempLifoAlloc());
    MatchPairs *matchPairs = NULL;
    RegExpRunStatus status = re->execute(cx, chars, length, lastIndex, allocScope, &matchPairs);

    switch (status) {
    case RegExpRunStatus_Error:
        return false;
    case RegExpRunStatus_Success_NotFound:
        *rval = NullValue();
        return true;
    default:
        JS_ASSERT(status == RegExpRunStatus_Success);
        JS_ASSERT(matchPairs);
    }

    if (res)
        res->updateFromMatchPairs(cx, input, matchPairs);

    *lastIndex = matchPairs->pair(0).limit;

    if (type == RegExpTest) {
        *rval = BooleanValue(true);
        return true;
    }

    return CreateRegExpMatchResult(cx, input, chars, length, matchPairs, rval);
}
bool
MatchPairs::initArrayFrom(MatchPairs& copyFrom)
{
    MOZ_ASSERT(copyFrom.pairCount() > 0);

    if (!allocOrExpandArray(copyFrom.pairCount()))
        return false;

    PodCopy(pairs_, copyFrom.pairs_, pairCount_);

    return true;
}
Exemple #3
0
RegExpRunStatus
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
                      size_t *lastIndex, MatchPairs &matches)
{
    /* Protect inlined chars from root analysis poisoning. */
    SkipRoot skip(cx, &chars);

    /* Compile the code at point-of-use. */
    if (!compileIfNecessary(cx))
        return RegExpRunStatus_Error;

    /* Ensure sufficient memory for output vector. */
    if (!matches.initArray(pairCount()))
        return RegExpRunStatus_Error;

    /*
     * |displacement| emulates sticky mode by matching from this offset
     * into the char buffer and subtracting the delta off at the end.
     */
    size_t origLength = length;
    size_t start = *lastIndex;
    size_t displacement = 0;

    if (sticky()) {
        displacement = start;
        chars += displacement;
        length -= displacement;
        start = 0;
    }

    unsigned *outputBuf = matches.rawBuf();
    unsigned result;

#if ENABLE_YARR_JIT
    if (codeBlock.isFallBack())
        result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf);
    else
        result = codeBlock.execute(chars, start, length, (int *)outputBuf).start;
#else
    result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf);
#endif

    if (result == JSC::Yarr::offsetNoMatch)
        return RegExpRunStatus_Success_NotFound;

    matches.displace(displacement);
    matches.checkAgainst(origLength);
    *lastIndex = matches[0].limit;
    return RegExpRunStatus_Success;
}
Exemple #4
0
bool
MatchPairs::initArrayFrom(MatchPairs &copyFrom)
{
    JS_ASSERT(copyFrom.pairCount() > 0);

    if (!allocOrExpandArray(copyFrom.pairCount()))
        return false;

    for (size_t i = 0; i < pairCount_; i++) {
        JS_ASSERT(copyFrom[i].check());
        pairs_[i].start = copyFrom[i].start;
        pairs_[i].limit = copyFrom[i].limit;
    }

    return true;
}
Exemple #5
0
RegExpRunStatus
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex,
                      MatchPairs **output)
{
    const size_t origLength = length;
    size_t backingPairCount = RegExpCode::getOutputSize(pairCount());

    LifoAlloc &alloc = cx->tempLifoAlloc();
    MatchPairs *matchPairs = MatchPairs::create(alloc, pairCount(), backingPairCount);
    if (!matchPairs)
        return RegExpRunStatus_Error;

    /*
     * |displacement| emulates sticky mode by matching from this offset
     * into the char buffer and subtracting the delta off at the end.
     */
    size_t start = *lastIndex;
    size_t displacement = 0;

    if (sticky()) {
        displacement = *lastIndex;
        chars += displacement;
        length -= displacement;
        start = 0;
    }

    RegExpRunStatus status = code.execute(cx, chars, length, start,
                                          matchPairs->buffer(), backingPairCount);

    switch (status) {
      case RegExpRunStatus_Error:
        return status;
      case RegExpRunStatus_Success_NotFound:
        *output = matchPairs;
        return status;
      default:
        JS_ASSERT(status == RegExpRunStatus_Success);
    }

    matchPairs->displace(displacement);
    matchPairs->checkAgainst(origLength);

    *lastIndex = matchPairs->pair(0).limit;
    *output = matchPairs;

    return RegExpRunStatus_Success;
}
Exemple #6
0
bool
js::CreateRegExpMatchResult(JSContext *cx, HandleString input_, const jschar *chars, size_t length,
                            MatchPairs &matches, MutableHandleValue rval)
{
    RootedString input(cx, input_);

    /*
     * Create the (slow) result array for a match.
     *
     * Array contents:
     *  0:              matched string
     *  1..pairCount-1: paren matches
     *  input:          input string
     *  index:          start index for the match
     */
    RootedObject array(cx, NewDenseEmptyArray(cx));
    if (!array)
        return false;

    if (!input) {
        input = js_NewStringCopyN<CanGC>(cx, chars, length);
        if (!input)
            return false;
    }

    RegExpMatchBuilder builder(cx, array);
    RootedValue undefinedValue(cx, UndefinedValue());

    size_t numPairs = matches.length();
    JS_ASSERT(numPairs > 0);

    for (size_t i = 0; i < numPairs; ++i) {
        const MatchPair &pair = matches[i];

        RootedString captured(cx);
        if (pair.isUndefined()) {
            JS_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
            if (!builder.append(i, undefinedValue))
                return false;
        } else {
            captured = js_NewDependentString(cx, input, pair.start, pair.length());
            RootedValue value(cx, StringValue(captured));
            if (!captured || !builder.append(i, value))
                return false;
        }
    }

    if (!builder.setIndex(matches[0].start) || !builder.setInput(input))
        return false;

    rval.setObject(*array);
    return true;
}
Exemple #7
0
bool
js::CreateRegExpMatchResult(JSContext* cx, HandleString input, const MatchPairs& matches,
                            MutableHandleValue rval)
{
    MOZ_ASSERT(input);

    /*
     * Create the (slow) result array for a match.
     *
     * Array contents:
     *  0:              matched string
     *  1..pairCount-1: paren matches
     *  input:          input string
     *  index:          start index for the match
     */

    /* Get the templateObject that defines the shape and type of the output object */
    JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
    if (!templateObject)
        return false;

    size_t numPairs = matches.length();
    MOZ_ASSERT(numPairs > 0);

    RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
    if (!arr)
        return false;

    /* Store a Value for each pair. */
    for (size_t i = 0; i < numPairs; i++) {
        const MatchPair& pair = matches[i];

        if (pair.isUndefined()) {
            MOZ_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
            arr->setDenseInitializedLength(i + 1);
            arr->initDenseElement(i, UndefinedValue());
        } else {
            JSLinearString* str = NewDependentString(cx, input, pair.start, pair.length());
            if (!str)
                return false;
            arr->setDenseInitializedLength(i + 1);
            arr->initDenseElement(i, StringValue(str));
        }
    }

    /* Set the |index| property. (TemplateObject positions it in slot 0) */
    arr->setSlot(0, Int32Value(matches[0].start));

    /* Set the |input| property. (TemplateObject positions it in slot 1) */
    arr->setSlot(1, StringValue(input));

#ifdef DEBUG
    RootedValue test(cx);
    RootedId id(cx, NameToId(cx->names().index));
    if (!NativeGetProperty(cx, arr, id, &test))
        return false;
    MOZ_ASSERT(test == arr->getSlot(0));
    id = NameToId(cx->names().input);
    if (!NativeGetProperty(cx, arr, id, &test))
        return false;
    MOZ_ASSERT(test == arr->getSlot(1));
#endif

    rval.setObject(*arr);
    return true;
}
Exemple #8
0
bool
js::CreateRegExpMatchResult(JSContext *cx, HandleString input_, const jschar *chars, size_t length,
                            MatchPairs &matches, MutableHandleValue rval)
{
    RootedString input(cx, input_);
    RootedValue undefinedValue(cx, UndefinedValue());

    /*
     * Create the (slow) result array for a match.
     *
     * Array contents:
     *  0:              matched string
     *  1..pairCount-1: paren matches
     *  input:          input string
     *  index:          start index for the match
     */
    if (!input) {
        input = js_NewStringCopyN<CanGC>(cx, chars, length);
        if (!input)
            return false;
    }

    size_t numPairs = matches.length();
    JS_ASSERT(numPairs > 0);

    AutoValueVector elements(cx);
    if (!elements.reserve(numPairs))
        return false;

    /* Accumulate a Value for each pair, in a rooted vector. */
    for (size_t i = 0; i < numPairs; ++i) {
        const MatchPair &pair = matches[i];

        if (pair.isUndefined()) {
            JS_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
            elements.infallibleAppend(undefinedValue);
        } else {
            JSLinearString *str = js_NewDependentString(cx, input, pair.start, pair.length());
            if (!str)
                return false;
            elements.infallibleAppend(StringValue(str));
        }
    }

    /* Copy the rooted vector into the array object. */
    RootedObject array(cx, NewDenseCopiedArray(cx, elements.length(), elements.begin()));
    if (!array)
        return false;

    /* Set the |index| property. */
    RootedValue index(cx, Int32Value(matches[0].start));
    if (!DefinePropertyHelper(cx, array, cx->names().index, index))
        return false;

    /* Set the |input| property. */
    RootedValue inputVal(cx, StringValue(input));
    if (!DefinePropertyHelper(cx, array, cx->names().input, inputVal))
        return false;

    rval.setObject(*array);
    return true;
}
RegExpRunStatus
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
                      size_t *lastIndex, MatchPairs &matches)
{
    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());

    /* Compile the code at point-of-use. */
    if (!compileIfNecessary(cx, chars, length))
        return RegExpRunStatus_Error;

    /* Ensure sufficient memory for output vector. */
    if (!matches.initArray(pairCount()))
        return RegExpRunStatus_Error;

    /*
     * |displacement| emulates sticky mode by matching from this offset
     * into the char buffer and subtracting the delta off at the end.
     */
    size_t origLength = length;
    size_t start = *lastIndex;
    size_t displacement = 0;

    if (sticky()) {
        displacement = start;
        chars += displacement;
        length -= displacement;
        start = 0;
    }

#ifndef JS_YARR
    // Reset the Irregexp backtrack stack if it grows during execution.
    irregexp::RegExpStackScope stackScope(cx->runtime());
#endif

    if (canStringMatch) {
        int res = StringFindPattern(chars+start, length-start, source->chars(), source->length());
        if (res == -1)
            return RegExpRunStatus_Success_NotFound;

        matches[0].start = res + start;
        matches[0].limit = res + start + source->length();

        matches.displace(displacement);
        matches.checkAgainst(origLength);
        *lastIndex = matches[0].limit;
        return RegExpRunStatus_Success;
    }

#ifdef JS_YARR

    unsigned result;

    // Yarr wants plain integers for its output buffer (whatever).
    JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(int));
    JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(unsigned));

#ifdef JS_ION
    if (codeBlock.isFallBack()) {
        AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
        result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw());
    } else {
        AutoTraceLog logJIT(logger, TraceLogger::YarrJIT);
        result = codeBlock.execute(chars, start, length, (int *) matches.pairsRaw()).start;
    }
#else // JS_ION
    {
        AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
        result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw());
    }
#endif // JS_ION

    if (result == JSC::Yarr::offsetError) {
        reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError);
        return RegExpRunStatus_Error;
    }

    if (result == JSC::Yarr::offsetNoMatch)
        return RegExpRunStatus_Success_NotFound;

#else // JS_YARR

    if (hasByteCode()) {
        AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
        RegExpRunStatus result =
            irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
        if (result == RegExpRunStatus_Success) {
            matches.displace(displacement);
            matches.checkAgainst(origLength);
            *lastIndex = matches[0].limit;
        }
        return result;
    }

#ifdef JS_ION
    while (true) {
        RegExpRunStatus result;
        {
            AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
            result = irregexp::ExecuteCode(cx, jitCode, chars, start, length, &matches);
        }

        if (result == RegExpRunStatus_Error) {
            // The RegExp engine might exit with an exception if an interrupt
            // was requested. Check this case and retry until a clean result is
            // obtained.
            bool interrupted;
            {
                JSRuntime::AutoLockForInterrupt lock(cx->runtime());
                interrupted = cx->runtime()->interrupt;
            }

            if (interrupted) {
                if (!InvokeInterruptCallback(cx))
                    return RegExpRunStatus_Error;
                continue;
            }

            js_ReportOverRecursed(cx);
            return RegExpRunStatus_Error;
        }

        if (result == RegExpRunStatus_Success_NotFound)
            return RegExpRunStatus_Success_NotFound;

        JS_ASSERT(result == RegExpRunStatus_Success);
        break;
    }
#else // JS_ION
    MOZ_CRASH();
#endif // JS_ION

#endif // JS_YARR

    matches.displace(displacement);
    matches.checkAgainst(origLength);
    *lastIndex = matches[0].limit;
    return RegExpRunStatus_Success;
}
Exemple #10
0
RegExpRunStatus
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
                      size_t *lastIndex, MatchPairs &matches)
{
    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());

    {
        /* Compile the code at point-of-use. */
        AutoTraceLog logCompile(logger, TraceLogger::YarrCompile);
        if (!compileIfNecessary(cx))
            return RegExpRunStatus_Error;
    }

    /* Ensure sufficient memory for output vector. */
    if (!matches.initArray(pairCount()))
        return RegExpRunStatus_Error;

    /*
     * |displacement| emulates sticky mode by matching from this offset
     * into the char buffer and subtracting the delta off at the end.
     */
    size_t origLength = length;
    size_t start = *lastIndex;
    size_t displacement = 0;

    if (sticky()) {
        displacement = start;
        chars += displacement;
        length -= displacement;
        start = 0;
    }

    unsigned *outputBuf = matches.rawBuf();
    unsigned result;

#if ENABLE_YARR_JIT
    if (codeBlock.isFallBack()) {
        AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
        result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf);
    } else {
        AutoTraceLog logJIT(logger, TraceLogger::YarrJIT);
        result = codeBlock.execute(chars, start, length, (int *)outputBuf).start;
    }
#else
    {
        AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
        result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, outputBuf);
    }
#endif

    if (result == JSC::Yarr::offsetError) {
        reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError);
        return RegExpRunStatus_Error;
    }

    if (result == JSC::Yarr::offsetNoMatch)
        return RegExpRunStatus_Success_NotFound;

    matches.displace(displacement);
    matches.checkAgainst(origLength);
    *lastIndex = matches[0].limit;
    return RegExpRunStatus_Success;
}