Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm-edit producers section #482

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/ast/src/types/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ type Byte = Number;

type SectionName =
| "custom"
| "custom:name"
| "custom:producers"
| "type"
| "import"
| "func"
Expand Down
2 changes: 2 additions & 0 deletions packages/helper-wasm-bytecode/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ const importTypes = {

const sections = {
custom: 0,
"custom:name": 0,
"custom:producers": 0,
type: 1,
import: 2,
func: 3,
Expand Down
3 changes: 3 additions & 0 deletions packages/helper-wasm-bytecode/src/section.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export function getSectionForNode(n: Node): ?SectionName {
case "Global":
return "global";

case "ProducerMetadata":
return "custom:producers";

// No section
default:
return;
Expand Down
25 changes: 18 additions & 7 deletions packages/helper-wasm-section/src/create.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow

import { encodeNode } from "@webassemblyjs/wasm-gen";
import { encodeNode, encodeUTF8Vec } from "@webassemblyjs/wasm-gen";
import { assert } from "mamacro";
import { overrideBytesInBuffer } from "@webassemblyjs/helper-buffer";
import constants from "@webassemblyjs/helper-wasm-bytecode";
import * as t from "@webassemblyjs/ast";
Expand Down Expand Up @@ -61,15 +62,20 @@ export function createEmptySection(
end = start;
}

// section id
start += 1;
// 1 byte for the empty vector
let size = 1;

if (section === "custom:producers") {
size += encodeUTF8Vec("producers").length;
}
assert(section !== "custom:name", "not implemented");

// the section starts after its header
start += size;

const sizeStartLoc = { line: -1, column: start };
const sizeEndLoc = { line: -1, column: start + 1 };

// 1 byte for the empty vector
const size = t.withLoc(t.numberLiteralFromRaw(1), sizeEndLoc, sizeStartLoc);

const vectorOfSizeStartLoc = { line: -1, column: sizeEndLoc.column };
const vectorOfSizeEndLoc = { line: -1, column: sizeEndLoc.column + 1 };

Expand All @@ -79,7 +85,12 @@ export function createEmptySection(
vectorOfSizeStartLoc
);

const sectionMetadata = t.sectionMetadata(section, start, size, vectorOfSize);
const sectionMetadata = t.sectionMetadata(
section,
start,
t.withLoc(t.numberLiteralFromRaw(size), sizeEndLoc, sizeStartLoc),
vectorOfSize
);

const sectionBytes = encodeNode(sectionMetadata);

Expand Down
23 changes: 23 additions & 0 deletions packages/helper-wasm-section/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ describe("create", () => {
assert.equal(res.sectionMetadata.vectorOfSize.value, 0);
assert.equal(res.sectionMetadata.vectorOfSize.loc.start.column, 10);
assert.equal(res.sectionMetadata.vectorOfSize.loc.end.column, 11);

assert.isUndefined(res.uint8Buffer[res.startOffset]);
});

it("should create an section and preserve section order", () => {
Expand Down Expand Up @@ -102,6 +104,27 @@ describe("create", () => {
assert.equal(12, getSectionMetadata(ast, "global").startOffset);
assert.equal(9, getSectionMetadata(ast, "type").startOffset);
});

it("should create a producers custom section", () => {
const sectionName = "custom:producers";

const actual = new Uint8Array(makeBuffer(encodeHeader(), encodeVersion(1)));
const ast = decode(actual);
const res = createEmptySection(ast, actual, sectionName);

const data = getSectionMetadata(ast, sectionName);

assert.isNotNull(data);
assert.equal(19, data.startOffset);
assert.equal(0, data.vectorOfSize.value);
assert.equal(11, data.size.value);

assert.isUndefined(res.uint8Buffer[res.startOffset]);
});

it.skip("should create a producers custom section after the name custom section", () => {
// FIXME(sven): implement it
});
});

describe("resize", () => {
Expand Down
8 changes: 7 additions & 1 deletion packages/wasm-edit/src/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ function applyAdd(ast: Program, uint8Buffer: Uint8Array, node: Node): State {
let sectionMetadata = getSectionMetadata(ast, sectionName);

// Section doesn't exists, we create an empty one
if (typeof sectionMetadata === "undefined") {
if (sectionMetadata === undefined) {
const res = createEmptySection(ast, uint8Buffer, sectionName);

uint8Buffer = res.uint8Buffer;
Expand Down Expand Up @@ -225,6 +225,12 @@ function applyAdd(ast: Program, uint8Buffer: Uint8Array, node: Node): State {
*/
const deltaBytes = newByteArray.length;

console.log("__________________________________________");
require("@webassemblyjs/wasm-parser").decode(uint8Buffer, { dump: true });
console.log("__________________________________________");

console.log(start, end, JSON.stringify(newByteArray));

uint8Buffer = overrideBytesInBuffer(uint8Buffer, start, end, newByteArray);

node.loc = {
Expand Down
37 changes: 34 additions & 3 deletions packages/wasm-edit/test/insert-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const { fromHexdump } = require("@webassemblyjs/helper-buffer");

const { add } = require("../lib");

function nameFromStr(str) {
return [str.length].concat(str.split("").map(s => s.charCodeAt(0)));
}

describe("insert a node", () => {
describe("ModuleImport", () => {
// (module
Expand Down Expand Up @@ -306,10 +310,8 @@ describe("insert a node", () => {
it("should insert type instructions with LEB128 padded type section size", () => {
const functype = t.typeInstruction(undefined, t.signature([], []));

let bin;

// (module)
bin = fromHexdump(`
let bin = fromHexdump(`
00000000 00 61 73 6d 01 00 00 00 01 81 80 80 80 00 00
00000010 06 81 80 80 80 00
`);
Expand All @@ -331,4 +333,33 @@ describe("insert a node", () => {

compareArrayBuffers(bin, expected);
});

describe("producers section", () => {
it("should insert a new entry and create section", () => {
const producer = t.producerMetadata(
[t.producerMetadataVersionedName("n1", "v1")], // language
[t.producerMetadataVersionedName("n2", "")], // processed-by
[] // sdk
);

// (module)
let bin = makeBuffer(encodeHeader(), encodeVersion(1));
console.log("before");
require("@webassemblyjs/wasm-parser").decode(bin, { dump: true });
bin = add(bin, [producer]);
console.log("after");
require("@webassemblyjs/wasm-parser").decode(bin, { dump: true });
return;

// (module)
const expected = makeBuffer(
encodeHeader(),
encodeVersion(1),
[constants.sections.custom, 0x01, ...nameFromStr("producers")],
[0]
);

compareArrayBuffers(bin, expected);
});
});
});
46 changes: 45 additions & 1 deletion packages/wasm-gen/src/encoder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,21 @@ export function encodeSectionMetadata(n: SectionMetadata): Array<Byte> {

out.push(sectionId);
out.push(...encodeU32(n.size.value));
out.push(...encodeU32(n.vectorOfSize.value));

/**
* If it's a custom section emit the name
* If it's a regular section emit the size of the vector of elements
*/
switch (n.section) {
case "custom:name":
out.push(...encodeUTF8Vec("name"));
break;
case "custom:producers":
out.push(...encodeUTF8Vec("producers"));
break;
default:
out.push(...encodeU32(n.vectorOfSize.value));
}

return out;
}
Expand Down Expand Up @@ -366,3 +380,33 @@ export function encodeElem(n: Elem): Array<Byte> {

return out;
}

export function encodeProducerMetadataVersionedName(
n: ProducerMetadataVersionedName
): Array<Byte> {
return [...encodeUTF8Vec(n.name), ...encodeUTF8Vec(n.version)];
}

export function encodeProducerMetadata(n: ProducerMetadata): Array<Byte> {
const out = [];

out.push(...encodeUTF8Vec("language"));
out.push(...encodeU32(n.language.length));
n.language.forEach(l => {
out.push(...encodeProducerMetadataVersionedName(l));
});

out.push(...encodeUTF8Vec("processed-by"));
out.push(...encodeU32(n.processedBy.length));
n.processedBy.forEach(l => {
out.push(...encodeProducerMetadataVersionedName(l));
});

out.push(...encodeUTF8Vec("sdk"));
out.push(...encodeU32(n.sdk.length));
n.sdk.forEach(l => {
out.push(...encodeProducerMetadataVersionedName(l));
});

return out;
}
7 changes: 7 additions & 0 deletions packages/wasm-gen/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export function encodeNode(n: Node): Array<Byte> {
case "Elem":
return encoder.encodeElem(n);

case "ProducerMetadataVersionedName":
return encoder.encodeProducerMetadataVersionedName(n);

case "ProducerMetadata":
return encoder.encodeProducerMetadata(n);

default:
throw new Error(
"Unsupported encoding for node of type: " + JSON.stringify(n.type)
Expand All @@ -55,3 +61,4 @@ export function encodeNode(n: Node): Array<Byte> {
}

export const encodeU32 = encoder.encodeU32;
export const encodeUTF8Vec = encoder.encodeUTF8Vec;
54 changes: 52 additions & 2 deletions packages/wasm-gen/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const t = require("@webassemblyjs/ast");
const { encodeNode } = require("../lib");
const encoder = require("../lib/encoder");

function nameFromStr(str) {
return [str.length].concat(str.split("").map(s => s.charCodeAt(0)));
}
function callIndirectInstructionIndex(index) {
return {
type: "CallIndirectInstruction",
Expand Down Expand Up @@ -80,13 +83,13 @@ const fixtures = [
},

{
name: "an empty ImportSection",
node: t.sectionMetadata(
"import",
0,
t.numberLiteralFromRaw(1),
t.numberLiteralFromRaw(0)
),
name: "an empty ImportSection",
expected: [0x02, 0x01, 0x00]
},

Expand Down Expand Up @@ -263,14 +266,61 @@ const fixtures = [
0x39
])
)
}
},

// TODO(sven): utf8 encoder fails here
// {
// name: "🤣见見",
// node: t.stringLiteral("🤣见見"),
// expected: [10, 0xf0, 0x9f, 0xa4, 0xa3, 0xe8, 0xa7, 0x81, 0xe8, 0xa6, 0x8b]
// }

{
name: "producerMetadata",
node: t.producerMetadata(
[t.producerMetadataVersionedName("n1", "v1")],
[t.producerMetadataVersionedName("n2", "")],
[]
),
expected: [].concat([
...nameFromStr("language"), // field_name
1, // field_value_count

// field_values
...nameFromStr("n1"), // name
...nameFromStr("v1"), // version

...nameFromStr("processed-by"), // field_name
1, // field_value_count

// field_values
...nameFromStr("n2"), // name
...nameFromStr(""), // version

...nameFromStr("sdk"), // field_name
0 // field_value_count
])
},

{
name: "producerMetadataVersionedName",
node: t.producerMetadataVersionedName("a", "b"),
expected: [].concat.apply(
[0x01, 97], // name
[0x01, 98] // version
)
},

{
name: "Producers empty section",
node: t.sectionMetadata(
"custom:producers",
0, // start
t.numberLiteralFromRaw(9), // size
t.numberLiteralFromRaw(0) // vectorOfSize
),
expected: [0x0, 9, ...nameFromStr("producers")]
}
];

describe("wasm gen", () => {
Expand Down
Loading