Beispiel #1
0
static bool
DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* imports)
{
    if (!d.readCStringIf(ImportSection))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected import section byte size");

    uint32_t numImports;
    if (!d.readVarU32(&numImports))
        return Fail(cx, d, "expected number of imports");

    if (numImports > MaxImports)
        return Fail(cx, d, "too many imports");

    for (uint32_t i = 0; i < numImports; i++) {
        if (!DecodeImport(cx, d, init, imports))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "import section byte size mismatch");

    return true;
}
Beispiel #2
0
static bool
DecodeExportTable(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
    uint32_t sectionStart;
    if (!d.startSection(ExportTableId, &sectionStart))
        return Fail(cx, d, "failed to start section");
    if (sectionStart == Decoder::NotStarted)
        return true;

    CStringSet dupSet(cx);
    if (!dupSet.init())
        return false;

    uint32_t numExports;
    if (!d.readVarU32(&numExports))
        return Fail(cx, d, "failed to read number of exports");

    if (numExports > MaxExports)
        return Fail(cx, d, "too many exports");

    for (uint32_t i = 0; i < numExports; i++) {
        if (!DecodeFunctionExport(cx, d, mg, &dupSet))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "export section byte size mismatch");

    return true;
}
Beispiel #3
0
static bool
DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
    if (!d.readCStringIf(DeclSection))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected decl section byte size");

    uint32_t numDecls;
    if (!d.readVarU32(&numDecls))
        return Fail(cx, d, "expected number of declarations");

    if (numDecls > MaxFuncs)
        return Fail(cx, d, "too many functions");

    if (!init->funcSigs.resize(numDecls))
        return false;

    for (uint32_t i = 0; i < numDecls; i++) {
        if (!DecodeSignatureIndex(cx, d, *init, &init->funcSigs[i]))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "decls section byte size mismatch");

    return true;
}
Beispiel #4
0
static bool
DecodeImportTable(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
{
    uint32_t sectionStart;
    if (!d.startSection(ImportTableId, &sectionStart))
        return Fail(cx, d, "failed to start section");
    if (sectionStart == Decoder::NotStarted)
        return true;

    uint32_t numImports;
    if (!d.readVarU32(&numImports))
        return Fail(cx, d, "failed to read number of imports");

    if (numImports > MaxImports)
        return Fail(cx, d, "too many imports");

    for (uint32_t i = 0; i < numImports; i++) {
        if (!DecodeImport(cx, d, init, importNames))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "import section byte size mismatch");

    return true;
}
Beispiel #5
0
static bool
DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
    if (!d.readCStringIf(ExportLabel))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected export section byte size");

    CStringSet dupSet(cx);
    if (!dupSet.init())
        return false;

    for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) {
        if (i >= MaxExports)
            return Fail(cx, d, "too many exports");

        if (d.readCStringIf(FuncLabel)) {
            if (!DecodeFunctionExport(cx, d, mg, &dupSet))
                return false;
        } else if (d.readCStringIf(MemoryLabel)) {
            if (!DecodeMemoryExport(cx, d, mg, &dupSet))
                return false;
        } else {
            return Fail(cx, d, "unexpected export subsection");
        }
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "export section byte size mismatch");

    return true;
}
Beispiel #6
0
static bool
DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
{
    if (!d.readCStringIf(ImportLabel))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected import section byte size");

    for (uint32_t i = 0; !d.readCStringIf(EndLabel); i++) {
        if (i >= MaxImports)
            return Fail(cx, d, "too many imports");

        if (!d.readCStringIf(FuncLabel))
            return Fail(cx, d, "expected 'func' import subsection");

        if (!DecodeImport(cx, d, init, importNames))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "import section byte size mismatch");

    return true;
}
Beispiel #7
0
static bool
DecodeFunctionBodies(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
    if (!mg.startFuncDefs())
        return false;

    uint32_t sectionStart;
    if (!d.startSection(FunctionBodiesId, &sectionStart))
        return Fail(cx, d, "failed to start section");

    if (sectionStart == Decoder::NotStarted) {
        if (mg.numFuncSigs() != 0)
            return Fail(cx, d, "expected function bodies");

        return mg.finishFuncDefs();
    }

    uint32_t numFuncBodies;
    if (!d.readVarU32(&numFuncBodies))
        return Fail(cx, d, "expected function body count");

    if (numFuncBodies != mg.numFuncSigs())
        return Fail(cx, d, "function body count does not match function signature count");

    for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
        if (!DecodeFunctionBody(cx, d, mg, funcIndex))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "function section byte size mismatch");

    return mg.finishFuncDefs();
}
Beispiel #8
0
static bool
DecodeTableSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
    if (!d.readCStringIf(TableLabel))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected table section byte size");

    if (!d.readVarU32(&init->numTableElems))
        return Fail(cx, d, "expected number of table elems");

    if (init->numTableElems > MaxTableElems)
        return Fail(cx, d, "too many table elements");

    Uint32Vector elems;
    if (!elems.resize(init->numTableElems))
        return false;

    for (uint32_t i = 0; i < init->numTableElems; i++) {
        uint32_t funcIndex;
        if (!d.readVarU32(&funcIndex))
            return Fail(cx, d, "expected table element");

        if (funcIndex >= init->funcSigs.length())
            return Fail(cx, d, "table element out of range");

        elems[i] = funcIndex;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "table section byte size mismatch");

    // Convert the single (heterogeneous) indirect function table into an
    // internal set of asm.js-like homogeneous tables indexed by signature.
    // Every element in the heterogeneous table is present in only one
    // homogeneous table (as determined by its signature). An element's index in
    // the heterogeneous table is the same as its index in its homogeneous table
    // and all other homogeneous tables are given an entry that will fault if
    // called for at that element's index.

    for (uint32_t elemIndex = 0; elemIndex < elems.length(); elemIndex++) {
        uint32_t funcIndex = elems[elemIndex];
        TableModuleGeneratorData& table = init->sigToTable[init->funcSigIndex(funcIndex)];
        if (table.numElems == 0) {
            table.numElems = elems.length();
            if (!table.elemFuncIndices.appendN(ModuleGenerator::BadIndirectCall, elems.length()))
                return false;
        }
    }

    for (uint32_t elemIndex = 0; elemIndex < elems.length(); elemIndex++) {
        uint32_t funcIndex = elems[elemIndex];
        init->sigToTable[init->funcSigIndex(funcIndex)].elemFuncIndices[elemIndex] = funcIndex;
    }

    return true;
}
Beispiel #9
0
static bool
DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
    if (!d.readCStringIf(SigSection))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected signature section byte size");

    uint32_t numSigs;
    if (!d.readVarU32(&numSigs))
        return Fail(cx, d, "expected number of signatures");

    if (numSigs > MaxSigs)
        return Fail(cx, d, "too many signatures");

    if (!init->sigs.resize(numSigs))
        return false;

    for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
        uint32_t numArgs;
        if (!d.readVarU32(&numArgs))
            return Fail(cx, d, "bad number of signature args");

        if (numArgs > MaxArgsPerFunc)
            return Fail(cx, d, "too many arguments in signature");

        ExprType result;
        if (!DecodeExprType(cx, d, &result))
            return false;

        ValTypeVector args;
        if (!args.resize(numArgs))
            return false;

        for (uint32_t i = 0; i < numArgs; i++) {
            if (!DecodeValType(cx, d, &args[i]))
                return false;
        }

        init->sigs[sigIndex] = Sig(Move(args), result);
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "decls section byte size mismatch");

    return true;
}
Beispiel #10
0
static bool
DecodeDataSegments(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap)
{
    uint32_t sectionStart;
    if (!d.startSection(DataSegmentsId, &sectionStart))
        return Fail(cx, d, "failed to start section");
    if (sectionStart == Decoder::NotStarted)
        return true;

    if (!heap)
        return Fail(cx, d, "data section requires a memory section");

    uint32_t numSegments;
    if (!d.readVarU32(&numSegments))
        return Fail(cx, d, "failed to read number of data segments");

    uint8_t* const heapBase = heap->dataPointer();
    uint32_t const heapLength = heap->byteLength();
    uint32_t prevEnd = 0;

    for (uint32_t i = 0; i < numSegments; i++) {
        uint32_t dstOffset;
        if (!d.readVarU32(&dstOffset))
            return Fail(cx, d, "expected segment destination offset");

        if (dstOffset < prevEnd)
            return Fail(cx, d, "data segments must be disjoint and ordered");

        uint32_t numBytes;
        if (!d.readVarU32(&numBytes))
            return Fail(cx, d, "expected segment size");

        if (dstOffset > heapLength || heapLength - dstOffset < numBytes)
            return Fail(cx, d, "data segment does not fit in memory");

        const uint8_t* src;
        if (!d.readBytesRaw(numBytes, &src))
            return Fail(cx, d, "data segment shorter than declared");

        memcpy(heapBase + dstOffset, src, numBytes);
        prevEnd = dstOffset + numBytes;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "data section byte size mismatch");

    return true;
}
Beispiel #11
0
static bool
DecodeMemory(JSContext* cx, Decoder& d, ModuleGenerator& mg, MutableHandle<ArrayBufferObject*> heap)
{
    uint32_t sectionStart;
    if (!d.startSection(MemoryId, &sectionStart))
        return Fail(cx, d, "failed to start section");
    if (sectionStart == Decoder::NotStarted)
        return true;

    uint32_t initialSizePages;
    if (!d.readVarU32(&initialSizePages))
        return Fail(cx, d, "expected initial memory size");

    CheckedInt<int32_t> initialSize = initialSizePages;
    initialSize *= PageSize;
    if (!initialSize.isValid())
        return Fail(cx, d, "initial memory size too big");

    uint32_t maxSizePages;
    if (!d.readVarU32(&maxSizePages))
        return Fail(cx, d, "expected initial memory size");

    CheckedInt<int32_t> maxSize = maxSizePages;
    maxSize *= PageSize;
    if (!maxSize.isValid())
        return Fail(cx, d, "initial memory size too big");

    uint8_t exported;
    if (!d.readFixedU8(&exported))
        return Fail(cx, d, "expected exported byte");

    if (exported) {
        UniqueChars fieldName = DuplicateString("memory");
        if (!fieldName || !mg.addMemoryExport(Move(fieldName)))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "memory section byte size mismatch");

    bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB;
    heap.set(ArrayBufferObject::createForWasm(cx, initialSize.value(), signalsForOOB));
    if (!heap)
        return false;

    mg.initHeapUsage(HeapUsage::Unshared);
    return true;
}
Beispiel #12
0
static bool
DecodeFunc(JSContext* cx, Decoder& d, ModuleGenerator& mg, uint32_t funcIndex)
{
    int64_t before = PRMJ_Now();

    FunctionGenerator fg;
    if (!mg.startFuncDef(d.currentOffset(), &fg))
        return false;

    if (!d.readCStringIf(FuncSubsection))
        return Fail(cx, d, "expected 'func' tag");

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected func section byte size");

    const DeclaredSig& sig = mg.funcSig(funcIndex);
    for (ValType type : sig.args()) {
        if (!fg.addLocal(type))
            return false;
    }

    uint32_t numVars;
    if (!d.readVarU32(&numVars))
        return Fail(cx, d, "expected number of local vars");

    for (uint32_t i = 0; i < numVars; i++) {
        ValType type;
        if (!DecodeValType(cx, d, &type))
            return false;
        if (!fg.addLocal(type))
            return false;
    }

    if (!DecodeFuncBody(cx, d, mg, fg, funcIndex))
        return false;

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "func section byte size mismatch");

    int64_t after = PRMJ_Now();
    unsigned generateTime = (after - before) / PRMJ_USEC_PER_MSEC;

    return mg.finishFuncDef(funcIndex, generateTime, &fg);
}
Beispiel #13
0
static bool
DecodeMemorySection(JSContext* cx, Decoder& d, ModuleGenerator& mg,
                    MutableHandle<ArrayBufferObject*> heap)
{
    if (!d.readCStringIf(MemoryLabel))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected memory section byte size");

    if (!d.readCStringIf(InitialLabel))
        return Fail(cx, d, "expected memory section initial field");

    uint32_t initialHeapSize;
    if (!d.readVarU32(&initialHeapSize))
        return Fail(cx, d, "expected initial memory size");

    if (initialHeapSize < PageSize || initialHeapSize % PageSize != 0)
        return Fail(cx, d, "initial memory size not a multiple of 0x10000");

    if (initialHeapSize > INT32_MAX)
        return Fail(cx, d, "initial memory size too big");

    if (!d.readCStringIf(EndLabel))
        return Fail(cx, d, "expected end field of memory section");

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "memory section byte size mismatch");

    bool signalsForOOB = CompileArgs(cx).useSignalHandlersForOOB;
    heap.set(ArrayBufferObject::createForWasm(cx, initialHeapSize, signalsForOOB));
    if (!heap)
        return false;

    mg.initHeapUsage(HeapUsage::Unshared);
    return true;
}
Beispiel #14
0
static bool
DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
{
    if (!d.readCStringIf(ExportSection))
        return true;

    uint32_t sectionStart;
    if (!d.startSection(&sectionStart))
        return Fail(cx, d, "expected export section byte size");

    uint32_t numExports;
    if (!d.readVarU32(&numExports))
        return Fail(cx, d, "expected number of exports");

    if (numExports > MaxExports)
        return Fail(cx, d, "too many exports");

    for (uint32_t i = 0; i < numExports; i++) {
        if (!DecodeExport(cx, d, mg, exportMap))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "export section byte size mismatch");

    CStringSet dupSet(cx);
    if (!dupSet.init())
        return false;
    for (const UniqueChars& prevName : exportMap->fieldNames) {
        CStringSet::AddPtr p = dupSet.lookupForAdd(prevName.get());
        if (p)
            return Fail(cx, d, "duplicate export");
        if (!dupSet.add(p, prevName.get()))
            return false;
    }

    return true;
}
Beispiel #15
0
static bool
DecodeCodeSection(JSContext* cx, Decoder& d, ModuleGenerator& mg)
{
    if (!mg.startFuncDefs())
        return false;

    uint32_t funcIndex = 0;
    while (d.readCStringIf(CodeSection)) {
        uint32_t sectionStart;
        if (!d.startSection(&sectionStart))
            return Fail(cx, d, "expected code section byte size");

        uint32_t numFuncs;
        if (!d.readVarU32(&numFuncs))
            return Fail(cx, d, "expected number of functions");

        if (funcIndex + numFuncs > mg.numFuncSigs())
            return Fail(cx, d, "more function definitions than declarations");

        for (uint32_t i = 0; i < numFuncs; i++) {
            if (!DecodeFunc(cx, d, mg, funcIndex++))
                return false;
        }

        if (!d.finishSection(sectionStart))
            return Fail(cx, d, "code section byte size mismatch");
    }

    if (funcIndex != mg.numFuncSigs())
        return Fail(cx, d, "fewer function definitions than declarations");

    if (!mg.finishFuncDefs())
        return false;

    return true;
}
Beispiel #16
0
 bool finishSection(const SectionRange& range, const char* name) {
     return d_.finishSection(range, name);
 }
Beispiel #17
0
static bool
DecodeSignatures(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
    uint32_t sectionStart;
    if (!d.startSection(SignaturesId, &sectionStart))
        return Fail(cx, d, "failed to start section");
    if (sectionStart == Decoder::NotStarted)
        return true;

    uint32_t numSigs;
    if (!d.readVarU32(&numSigs))
        return Fail(cx, d, "expected number of signatures");

    if (numSigs > MaxSigs)
        return Fail(cx, d, "too many signatures");

    if (!init->sigs.resize(numSigs))
        return false;
    if (!init->sigToTable.resize(numSigs))
        return false;

    SigSet dupSet(cx);
    if (!dupSet.init())
        return false;

    for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
        uint32_t numArgs;
        if (!d.readVarU32(&numArgs))
            return Fail(cx, d, "bad number of signature args");

        if (numArgs > MaxArgsPerFunc)
            return Fail(cx, d, "too many arguments in signature");

        ExprType result;
        if (!d.readExprType(&result))
            return Fail(cx, d, "bad expression type");

        if (!CheckExprType(cx, d, result))
            return false;

        ValTypeVector args;
        if (!args.resize(numArgs))
            return false;

        for (uint32_t i = 0; i < numArgs; i++) {
            if (!d.readValType(&args[i]))
                return Fail(cx, d, "bad value type");

            if (!CheckValType(cx, d, args[i]))
                return false;
        }

        init->sigs[sigIndex] = Sig(Move(args), result);

        SigSet::AddPtr p = dupSet.lookupForAdd(init->sigs[sigIndex]);
        if (p)
            return Fail(cx, d, "duplicate signature");

        if (!dupSet.add(p, &init->sigs[sigIndex]))
            return false;
    }

    if (!d.finishSection(sectionStart))
        return Fail(cx, d, "decls section byte size mismatch");

    return true;
}