Skip to content

Commit

Permalink
Split JS into modules
Browse files Browse the repository at this point in the history
  • Loading branch information
sliminality committed Jun 7, 2018
1 parent 213f17f commit 88c901f
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 211 deletions.
204 changes: 0 additions & 204 deletions examples/bin/runWasm.js

This file was deleted.

3 changes: 2 additions & 1 deletion examples/buffer/testBuffer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @format

const { default: main, getMemory } = require('../bin/runWasm');
const { default: main } = require('../js/runWasm');
const { getMemory } = require('../js/tracer.js');
const BUFFER_SIZE = 10;

main(process.argv)
Expand Down
8 changes: 4 additions & 4 deletions examples/enter-exit-count/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ wat:

# Execute a `.wasm` file in Node.js.
node:
node ../bin/runWasm.js $(FILE).wasm $(FUNCTION1) $(ARGS)
node ../bin/runWasm.js $(FILE).wasm $(FUNCTION2) $(ARGS)
node ../js/runWasm.js $(FILE).wasm $(FUNCTION1) $(ARGS)
node ../js/runWasm.js $(FILE).wasm $(FUNCTION2) $(ARGS)

output:
node ../bin/runWasm.js output.wasm $(FUNCTION1) $(ARGS)
node ../bin/runWasm.js output.wasm $(FUNCTION2) $(ARGS)
node ../js/runWasm.js output.wasm $(FUNCTION1) $(ARGS)
node ../js/runWasm.js output.wasm $(FUNCTION2) $(ARGS)
2 changes: 1 addition & 1 deletion examples/function-calls/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ wat:

# Execute a `.wasm` file in Node.js.
node:
node ../bin/runWasm.js $(EXAMPLE).wasm $(FUNCTION) $(ARGS)
node ../js/runWasm.js $(EXAMPLE).wasm $(FUNCTION) $(ARGS)
74 changes: 74 additions & 0 deletions examples/js/names.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// @format
// Functionality for parsing the names section of a WebAssembly Module.

const assert = require('assert');
const { TextDecoder } = require('util');

// TODO: Clean this up.
function getNames(module) {
const nameSections = WebAssembly.Module.customSections(module, 'name');
if (nameSections.length === 0) {
console.log('No name sections provided');
return;
}
const [names] = nameSections;
const data = new DataView(names);
const decoder = new TextDecoder('utf-8');

const PAYLOAD_SIZE_OFFSET = 1;
const { results, bytesRead: metadataSize } = readVarUint32(
data,
PAYLOAD_SIZE_OFFSET,
2,
);
const [payloadLen, entryCount] = results;

let entryId = 0;
let entryOffset = PAYLOAD_SIZE_OFFSET + metadataSize;
const nameMap = new Map();

while (entryId < entryCount) {
const { results, bytesRead } = readVarUint32(data, entryOffset, 2);
const [namingId, nameSize] = results;
assert.equal(namingId, entryId, 'Correctly identified entry id');

const nameOffset = entryOffset + bytesRead;
const name = decoder.decode(new Uint8Array(names, nameOffset, nameSize));
nameMap.set(namingId, name);

entryOffset = nameOffset + nameSize;
entryId += 1;
}

return nameMap;
}

// TODO: Wrap this in a generator.
function readVarUint32(view, offset = 0, intsToRead = 1) {
const results = [];
let bytesRead = 0;

for (let i = 0; i < intsToRead; i += 1) {
let value = 0;
let j = 0;

while (true) {
const byte = view.getUint8(offset + bytesRead);
const shift = j * 7;
value |= (byte & 0x7f) << shift;
bytesRead += 1;
j += 1;

// Last byte (in little endian) starts with a 0.
if ((byte & 0x80) === 0) {
break;
}
}

results.push(value);
}

return { results, bytesRead };
}

module.exports = { getNames };
77 changes: 77 additions & 0 deletions examples/js/runWasm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// @format

// Execute a .wasm file in Node.js.
// `node runWasm.js arithmetic.wasm add1 10`

const fs = require('fs');
const assert = require('assert');
const { getNames } = require('./names.js');
const { readBuffer } = require('./tracer.js');

assert('WebAssembly' in global, 'WebAssembly global object not detected');

// Compile and run a WebAssembly module, given a path.
// Based on:
// https://gist.github.com/kanaka/3c9caf38bc4da2ecec38f41ba24b77df
// https://gist.github.com/kanaka/3c9caf38bc4da2ecec38f41ba24b77df#gistcomment-2564224
function compileAndRun(bytes, func, ...args) {
return WebAssembly.compile(bytes)
.then(module => {
const instance = new WebAssembly.Instance(module, {
memory: new WebAssembly.Memory({ initial: 256 }),
table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' }),
});
const names = getNames(module);
return { instance, names };
})
.then(({ instance, names }) => {
const { exports } = instance;
assert(exports, 'no exports found');
assert(
func in exports,
`${func} not found in wasm exports: ${Object.keys(exports)}`,
);

console.log(
'Invoking exported function',
func,
'with arguments',
args,
'...',
);

const result = exports[func](...args);

return { result, exports, names };
});
}

function validateArgs(_, __, wasmFile, funcName, args) {
assert(wasmFile && funcName, 'Usage: ./runwasm.js prog.wasm func INT_ARG...');
const parsedArgs = args.split(' ').map(x => parseInt(x, 10));
return [wasmFile, funcName, ...parsedArgs];
}

function main(argv) {
const [wasmFile, funcName, ...args] = validateArgs(...argv);
const bytes = fs.readFileSync(wasmFile);

return compileAndRun(bytes, funcName, ...args)
.then(({ result, exports, names }) => {
console.log('Result of function call:', result);
readBuffer(exports, names);
return { result, exports, names };
})
.catch(console.error);
}

if (module.parent) {
// Module is being imported, rather than invoked standalone.
module.exports = {
compileAndRun,
};
module.exports.default = main;
} else {
// Script is invoked from the terminal, compile and log result.
main(process.argv).catch(console.error);
}
Loading

0 comments on commit 88c901f

Please sign in to comment.