Example #1
0
const _maybeRegisterType = (builder, type) => {
    const typeSection = builder._getSection("Type");
    if (typeof(type) === "number") {
        // Type numbers already refer to the type section, no need to register them.
        if (builder._checked) {
            assert.isNotUndef(typeSection, `Can not use type ${type} if a type section is not present`);
            assert.isNotUndef(typeSection.data[type], `Type ${type} does not exist in type section`);
        }
        return type;
    }
    assert.hasObjectProperty(type, "params", `Expected type to be a number or object with 'params' and optionally 'ret' fields`);
    const [params, ret] = _normalizeFunctionSignature(type.params, type.ret);
    assert.isNotUndef(typeSection, `Can not add type if a type section is not present`);
    // Try reusing an equivalent type from the type section.
    types:
    for (let i = 0; i !== typeSection.data.length; ++i) {
        const t = typeSection.data[i];
        if (t.ret === ret && params.length === t.params.length) {
            for (let j = 0; j !== t.params.length; ++j) {
                if (params[j] !== t.params[j])
                    continue types;
            }
            type = i;
            break;
        }
    }
    if (typeof(type) !== "number") {
        // Couldn't reuse a pre-existing type, register this type in the type section.
        typeSection.data.push({ params: params, ret: ret });
        type = typeSection.data.length - 1;
    }
    return type;
};
Example #2
0
 End: () => {
     // We now have enough information to remap the export section's "type" and "index" according to the Code section we are currently ending.
     const typeSection = builder._getSection("Type");
     const importSection = builder._getSection("Import");
     const exportSection = builder._getSection("Export");
     const startSection = builder._getSection("Start");
     const codeSection = s;
     if (exportSection) {
         for (const e of exportSection.data) {
             if (e.kind !== "Function" || typeof(e.type) !== "undefined")
                 continue;
             switch (typeof(e.index)) {
             default: throw new Error(`Unexpected export index "${e.index}"`);
             case "string": {
                 const index = builder._getFunctionFromIndexSpace(e.index);
                 assert.isNumber(index, `Export section contains undefined function "${e.index}"`);
                 e.index = index;
             } // Fallthrough.
             case "number": {
                 const index = builder._getFunctionFromIndexSpace(e.index);
                 if (builder._checked)
                     assert.isNotUndef(index, `Export "${e.field}" does not correspond to a defined value in the function index space`);
             } break;
             case "undefined":
                 throw new Error(`Unimplemented: Function().End() with undefined export index`); // FIXME
             }
             if (typeof(e.type) === "undefined") {
                 // This must be a function export from the Code section (re-exports were handled earlier).
                 let functionIndexSpaceOffset = 0;
                 if (importSection) {
                     for (const {kind} of importSection.data) {
                         if (kind === "Function")
                             ++functionIndexSpaceOffset;
                     }
                 }
                 const functionIndex = e.index - functionIndexSpaceOffset;
                 e.type = codeSection.data[functionIndex].type;
             }
         }
     }
     if (startSection) {
         const start = startSection.data[0];
         let mapped = builder._getFunctionFromIndexSpace(start);
         if (!builder._checked) {
             if (typeof(mapped) === "undefined")
                 mapped = start; // In unchecked mode, simply use what was provided if it's nonsensical.
             assert.isA(start, "number"); // It can't be too nonsensical, otherwise we can't create a binary.
             startSection.data[0] = start;
         } else {
             if (typeof(mapped) === "undefined")
                 throw new Error(`Start section refers to non-existant function '${start}'`);
             if (typeof(start) === "string" || typeof(start) === "object")
                 startSection.data[0] = mapped;
             // FIXME in checked mode, test that the type is acceptable for start function. We probably want _registerFunctionToIndexSpace to also register types per index. https://bugs.webkit.org/show_bug.cgi?id=165658
         }
     }
     return _errorHandlingProxyFor(builder);
 },
Example #3
0
    return (field, index, type) => {
        assert.isString(field, `Export function field should be a string, got "${field}"`);
        const typeSection = builder._getSection("Type");
        if (typeof(type) !== "undefined") {
            // Exports can leave the type unspecified, letting the Code builder patch them up later.
            type = _maybeRegisterType(builder, type);
        }

        // We can't check much about "index" here because the Code section succeeds the Export section. More work is done at Code().End() time.
        switch (typeof(index)) {
        case "string": break; // Assume it's a function name which will be revealed in the Code section.
        case "number": break; // Assume it's a number in the "function index space".
        case "object":
            // Re-exporting an import.
            assert.hasObjectProperty(index, "module", `Re-exporting "${field}" from an import`);
            assert.hasObjectProperty(index, "field", `Re-exporting "${field}" from an import`);
            break;
        case "undefined":
            // Assume it's the same as the field (i.e. it's not being renamed).
            index = field;
            break;
        default: throw new Error(`Export section's index must be a string or a number, got ${index}`);
        }

        const correspondingImport = builder._getFunctionFromIndexSpace(index);
        const importSection = builder._getSection("Import");
        if (typeof(index) === "object") {
            // Re-exporting an import using its module+field name.
            assert.isNotUndef(correspondingImport, `Re-exporting "${field}" couldn't find import from module "${index.module}" field "${index.field}"`);
            index = correspondingImport;
            if (typeof(type) === "undefined")
                type = importSection.data[index].type;
            if (builder._checked)
                assert.eq(type, importSection.data[index].type, `Re-exporting import "${importSection.data[index].field}" as "${field}" has mismatching type`);
        } else if (typeof(correspondingImport) !== "undefined") {
            // Re-exporting an import using its index.
            let exportedImport;
            for (const i of importSection.data) {
                if (i.module === correspondingImport.module && i.field === correspondingImport.field) {
                    exportedImport = i;
                    break;
                }
            }
            if (typeof(type) === "undefined")
                type = exportedImport.type;
            if (builder._checked)
                assert.eq(type, exportedImport.type, `Re-exporting import "${exportedImport.field}" as "${field}" has mismatching type`);
        }
        section.data.push({ field: field, type: type, kind: "Function", index: index });
        return _errorHandlingProxyFor(nextBuilder);
    };