0.0.9 • Published 5 years ago

@richardanaya/seed v0.0.9

Weekly downloads
1
License
MIT
Repository
-
Last release
5 years ago

Seed

This is my minimalistic web assembly work setup. The TLDR is that I have a whole bunch of helpers that help you create a giant array of bytes. This helps you develop much more closer to how web assembly apps exist at a low level

If you check this project out and just want to get the dependencies to setup:

make setup

Go into any example directory:

make
make serve

Then open a browser to http://localhost:9999

Check the console for output!

If you are using this as a npm module

npm install @richardanaya/seed

Very Simple Modules

If all you are doing is writing a single exported "main" function that takes in inputs, returns an output, and exposes "memory". Try this to save boiler plate:

var fs = require('fs');
let seed = require("@richardanaya/seed");
// helpers and lists of bytes as constants from seed!
let {makeSimple,int,I32,I32_CONST,END} = seed;

const app = makeSimple([],[I32],[   // main() -> i32
  vec([]),                          // no local variables
  [I32_CONST, int(42)],             // return 42
  END
])

fs.writeFileSync('out.wasm',Buffer.from(app))

Simplest Module Possible

If you are trying to create the most simplest module from scratch. This has no functions

var fs = require('fs');
let seed = require("@richardanaya/seed");
// helpers and lists of bytes as constants from seed!
let {flatten,MAGIC_NUMBER,VERSION_1} = seed;

let app = [
  MAGIC_NUMBER,
  VERSION_1,
]

// this is just a nested array of bytes:
// [[[0, 97, 115, 109]][[1, 0, 0, 0]]]

fs.writeFileSync('out.wasm',Buffer.from(flatten(app)))

Not very useful!

main() From Scratch

var fs = require('fs');
let seed = require("@richardanaya/seed");
// helpers and lists of bytes as constants from seed!
let {flatten,str,vec,bytevec,int,uint,I32,FUNC,DESC_FUNCTION,END,I32_CONST,SECTION_TYPE,
  SECTION_FUNCTION,SECTION_EXPORT,SECTION_CODE,MAGIC_NUMBER,VERSION_1} = seed;

// we're going to create the peices needed for this function: main() -> i32 { return 42 }
// web assembly puts these pieces in various sections you'll see below

// every function web assembly has an index, this if the first
let main_function_index = 0
// function signature for our function takes in nothing and returns an int32
let main_function_signature = [FUNC,vec([]),vec([I32])]
// we want "main" to be the export name of our function
let main_export = [str("main"),DESC_FUNCTION,main_function_index]
// here's the byte code of our function
let main_function_code = bytevec([
  vec([]),              // no local variables
  [I32_CONST, int(42)], // return 42
  END
])

// function signatures go in this section
let type_section =      [SECTION_TYPE,bytevec(vec([main_function_signature]))];

// we only have one function (main), and its going to use the first type
let functions_section = [SECTION_FUNCTION,bytevec(vec([int(main_function_index)]))];

// let's mark our main fnction as exported
let export_section =    [SECTION_EXPORT,bytevec(vec([main_export]))]

// we only have our main function code
let code_section =      [SECTION_CODE,bytevec(vec([main_function_code]))]

// put it all together as a module
let app = [
  MAGIC_NUMBER,
  VERSION_1,
  type_section,
  functions_section,
  export_section,
  code_section
]

// don't forget this is just a giant nested array of bytes! nothing magic

fs.writeFileSync('out.wasm',Buffer.from(flatten(app)))

Memory Allocator

Let's make a very simple memory allocator.

...
// malloc(length:i32) -> i32 { ... }
let main_function_index = 0
let main_export = [str("malloc"),DESC_FUNCTION,main_function_index]
let main_function_signature = [FUNC,vec([I32]),vec([I32])]
let main_function_code = bytevec([
  vec([
    [1, I32] // current_heap:i32
  ]),
  // current_heap = global.heap
  [GLOBAL_GET, int(0)],
  [LOCAL_SET,  int(1)],
  // memory[0] = length
  [LOCAL_GET,  int(1)],
  [GLOBAL_GET, int(0)],
  [I32_STORE,  int(0), int(0)],
  // global.heap = current_heap + 1 + length
  [LOCAL_GET,  int(1)],
  [I32_CONST,  int(1)],
  [I32_ADD],
  [LOCAL_GET,  int(0)],
  [I32_ADD],
  [GLOBAL_SET, int(0)],
  // return current_heap + 1
  [LOCAL_GET,  int(1)],
  [I32_CONST,  int(1)],
  [I32_ADD],
  END
])

// create a heap global set to zero
let heap_global = [I32,MUTABLE,I32_CONST, int(0),END]
let heap_export = [str("heap"),DESC_GLOBAL,0]

//lets make memory at least 2 pages and at most 10 pages long
let memory = [LIMIT_MIN_MAX,uint(2),uint(10)]
let memory_export = [str("memory"),DESC_MEMORY,0]

// function signatures go in this section
let type_section = [SECTION_TYPE,bytevec(vec([main_function_signature]))];

// we only have one function (main), and its going to use the first type
let functions_section = [SECTION_FUNCTION,bytevec(vec([int(main_function_index)]))];

// have standard memory
let memory_section = [SECTION_MEMORY,bytevec(vec([memory]))]

// we have one global
let globals_section = [SECTION_GLOBAL,bytevec(vec([heap_global]))]

// export main, memory, and our heap global
let export_section = [SECTION_EXPORT,bytevec(vec([main_export,memory_export,heap_export]))]

// we only have our main function code
let code_section = [SECTION_CODE,bytevec(vec([main_function_code]))]

// put it all together as a module
let app = [
  MAGIC_NUMBER,
  VERSION_1,
  type_section,
  functions_section,
  memory_section,
  globals_section,
  export_section,
  code_section
]
...
0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago