From df527f271374bd12c525d8ce6ed96d4c2a263085 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 31 Oct 2019 16:10:35 +0100 Subject: [PATCH 1/2] Support basic dynamic linking with example --- assembly/hello-world/index.ts | 12 +++++++++++- assembly/lib/add.ts | 7 +++++++ package.json | 3 ++- src/cli.ts | 27 ++++++++++++++++++++++++++- src/lib.ts | 3 +++ test.yaml | 2 ++ 6 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 assembly/lib/add.ts diff --git a/assembly/hello-world/index.ts b/assembly/hello-world/index.ts index b63dcde..344dfa1 100644 --- a/assembly/hello-world/index.ts +++ b/assembly/hello-world/index.ts @@ -1,5 +1,14 @@ import * as env from '../env' +/** + * Examples for linking a library + */ +@external("env", "incr") +export declare function incr(a: u32): u32 + +@external("env", "add") +export declare function add(a: u32, b: u32): u32 + /* * Increments preStateRoot by one */ @@ -10,7 +19,8 @@ export function main(): void { var postStateRootPtr: u32 = __heap_base + 32 var numPtr: u32 = __heap_base + 64 - store(numPtr, 1, 31) + // Silly example of how you can use lib + store(numPtr, add(0, 1), 31) env.bignum_add256(preStateRootPtr, numPtr, postStateRootPtr) diff --git a/assembly/lib/add.ts b/assembly/lib/add.ts new file mode 100644 index 0000000..c5530ca --- /dev/null +++ b/assembly/lib/add.ts @@ -0,0 +1,7 @@ +export function incr(a: u32): u32 { + return a + 1 +} + +export function add(a: u32, b: u32): u32 { + return a + b +} diff --git a/package.json b/package.json index b6755b9..d18444d 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "docs": "typedoc --out docs --mode modules --theme markdown --excludeNotExported src", "asbuild:untouched": "asc assembly/hello-world/index.ts -b build/hello-world-untouched.wasm -t build/hello-world-untouched.wat --sourceMap --validate --debug", "asbuild:optimized": "asc assembly/hello-world/index.ts -b build/hello-world-optimized.wasm -t build/hello-world-optimized.wat --sourceMap --validate --optimize", - "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized" + "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", + "asbuild:lib": "asc assembly/lib/add.ts -b build/lib-add-optimized.wasm -t build/lib-add-optimized.wat --sourceMap --validate --optimize" }, "author": "s1na", "license": "Apache-2.0", diff --git a/src/cli.ts b/src/cli.ts index 742cda7..fdcf22c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -22,7 +22,10 @@ function main() { const wasmModule = new WebAssembly.Module(wasmFile) let preStateRoot = testCase.preStateRoot for (const block of testCase.blocks) { - const instance = new WebAssembly.Instance(wasmModule, getImports({ preStateRoot, blockData: block })) + let libExports = getLibExports(testCase.libs) + let imports = getImports({ preStateRoot, blockData: block }) + imports.env = { ...imports.env, ...libExports } + const instance = new WebAssembly.Instance(wasmModule, imports) setMemory(instance.exports.memory) let t = process.hrtime() instance.exports.main() @@ -34,4 +37,26 @@ function main() { } } +interface Exports { + [k: string]: Function +} + +function getLibExports(libs: string[]): Exports { + let libExports = {} + for (const lib of libs) { + const libFile = fs.readFileSync(lib) + const libModule = new WebAssembly.Module(libFile) + const libInstance = new WebAssembly.Instance(libModule, { env: { abort: () => { throw new Error('Wasm aborted') } } }) + const exports: { [k: string]: any } = {} + for (const fn in libInstance.exports) { + if (fn === 'memory' || fn.startsWith('_')) { + continue + } + exports[fn] = libInstance.exports[fn] + } + libExports = { ...libExports, ...exports } + } + return libExports +} + main() diff --git a/src/lib.ts b/src/lib.ts index 20c2597..7366d15 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -29,6 +29,7 @@ export interface ShardBlock { export interface TestCase { script: string + libs: string[] preStateRoot: Buffer blocks: Buffer[] postStateRoot: Buffer @@ -100,6 +101,7 @@ export const getImports = (env: EnvData) => { export function parseYaml (file: string): TestCase[] { const testCase = safeLoad(file) const scripts = testCase.beacon_state.execution_scripts + const libs = testCase.beacon_state.libraries || [] const shardBlocks = testCase.shard_blocks const testCases = [] for (let i = 0; i < scripts.length; i++) { @@ -118,6 +120,7 @@ export function parseYaml (file: string): TestCase[] { testCases.push({ script, + libs, preStateRoot, postStateRoot, blocks diff --git a/test.yaml b/test.yaml index a491ad2..d07530e 100644 --- a/test.yaml +++ b/test.yaml @@ -1,6 +1,8 @@ beacon_state: execution_scripts: - build/hello-world-optimized.wasm + libraries: + - build/lib-add-optimized.wasm shard_pre_state: exec_env_states: - "0000000000000000000000000000000000000000000000000000000000000001" From 9f4ed832066213555f126f155ba2fcd08b4cd3dc Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 4 Nov 2019 15:14:28 +0100 Subject: [PATCH 2/2] Put library imports under own namespace --- assembly/hello-world/index.ts | 4 ++-- src/cli.ts | 17 +++++++++-------- src/lib.ts | 6 ++++-- test.yaml | 3 ++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/assembly/hello-world/index.ts b/assembly/hello-world/index.ts index 344dfa1..1888808 100644 --- a/assembly/hello-world/index.ts +++ b/assembly/hello-world/index.ts @@ -3,10 +3,10 @@ import * as env from '../env' /** * Examples for linking a library */ -@external("env", "incr") +@external("add", "incr") export declare function incr(a: u32): u32 -@external("env", "add") +@external("add", "add") export declare function add(a: u32, b: u32): u32 /* diff --git a/src/cli.ts b/src/cli.ts index fdcf22c..6be08c3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -24,7 +24,7 @@ function main() { for (const block of testCase.blocks) { let libExports = getLibExports(testCase.libs) let imports = getImports({ preStateRoot, blockData: block }) - imports.env = { ...imports.env, ...libExports } + imports = { ...imports, ...libExports } const instance = new WebAssembly.Instance(wasmModule, imports) setMemory(instance.exports.memory) let t = process.hrtime() @@ -38,23 +38,24 @@ function main() { } interface Exports { - [k: string]: Function + // { libName: { exportName: Fn } } + [n: string]: { [f: string]: Function } } -function getLibExports(libs: string[]): Exports { - let libExports = {} - for (const lib of libs) { - const libFile = fs.readFileSync(lib) +function getLibExports(libs: { [k: string]: string }): Exports { + let libExports: Exports = {} + for (const libName in libs) { + const libFile = fs.readFileSync(libs[libName]) const libModule = new WebAssembly.Module(libFile) const libInstance = new WebAssembly.Instance(libModule, { env: { abort: () => { throw new Error('Wasm aborted') } } }) - const exports: { [k: string]: any } = {} + const exports: { [k: string]: Function } = {} for (const fn in libInstance.exports) { if (fn === 'memory' || fn.startsWith('_')) { continue } exports[fn] = libInstance.exports[fn] } - libExports = { ...libExports, ...exports } + libExports[libName] = exports } return libExports } diff --git a/src/lib.ts b/src/lib.ts index 7366d15..2aa9c7a 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -29,7 +29,7 @@ export interface ShardBlock { export interface TestCase { script: string - libs: string[] + libs: { [k: string]: string } // { name: file } preStateRoot: Buffer blocks: Buffer[] postStateRoot: Buffer @@ -101,7 +101,9 @@ export const getImports = (env: EnvData) => { export function parseYaml (file: string): TestCase[] { const testCase = safeLoad(file) const scripts = testCase.beacon_state.execution_scripts - const libs = testCase.beacon_state.libraries || [] + const libs = (testCase.beacon_state.libraries || []).reduce( + (a: { [k: string]: string }, v: { name: string, file: string }) => { a[v.name] = v.file; return a }, {} + ) const shardBlocks = testCase.shard_blocks const testCases = [] for (let i = 0; i < scripts.length; i++) { diff --git a/test.yaml b/test.yaml index d07530e..40e52fc 100644 --- a/test.yaml +++ b/test.yaml @@ -2,7 +2,8 @@ beacon_state: execution_scripts: - build/hello-world-optimized.wasm libraries: - - build/lib-add-optimized.wasm + - name: "add" + file: build/lib-add-optimized.wasm shard_pre_state: exec_env_states: - "0000000000000000000000000000000000000000000000000000000000000001"