Skip to content
Prev Previous commit
Next Next commit
added hello world for strings: hello-string
  • Loading branch information
Pannous committed Mar 25, 2018
commit d310f29850f80e2ac762c37ccd97ba1e0e19b2f5
37 changes: 37 additions & 0 deletions examples/hello-string/hello-string.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script type="text/javascript">

const encoder = new TextDecoder('utf-16le');
function toUTF16StringA(pointer, size) {
let arr = new Uint8Array(buffer.slice(pointer, pointer+ size*2)); // length *2 for utf16
console.log(encoder.decode(arr));
alert(encoder.decode(arr));
}
imports = { console: {logs: toUTF16StringA}}

async function run_wasm(wasm_file = 'hello-string.wasm'){
try{
fetch(wasm_file).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, imports)
).then(results => {
console.log(results)
});
// memory = new WebAssembly.Memory({initial: 16384, maximum: 65536});
}catch(ex){console.error(ex);alert(ex);}
}
window.onload=run_wasm

wasm=fetch('hello-string.wasm')
ready = function ({module,instance}){
console.log(instance)
// heap = instance.exports.memory.buffer
buffer = instance.exports.memory.buffer
instance.exports.main()
}
// module=WebAssembly.compileStreaming(wasm,imports).then(ready).catch(e=>alert(e))
module=WebAssembly.instantiateStreaming(wasm,imports).then(ready).catch(e=>alert(e))
// WebAssembly.instantiate(module)
// WebAssembly.instantiateStreaming(fetch('hello-string.wasm'),imports).catch(e=>alert(e))

</script>
30 changes: 30 additions & 0 deletions examples/hello-string/hello-string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// compile this file thus:
// asc -v || npm install --save-dev AssemblyScript/assemblyscript
// asc hello-string.ts -b test.wasm -t test.wast

// run compiled wasm file in node.js:
// node -i -e "\
// log_char = c => process.stdout.write(String.fromCodePoint(c));\
// binary = require('fs').readFileSync('test.wasm')\
// new WebAssembly.Instance(new WebAssembly.Module(binary),{console:{log_char}})"

namespace console {

// imported helper to print a string in node.js or browser
// export declare function logs(string_pointer: i32, length: i32): void;
export declare function logs(string_pointer: i32, size: i32, encoding: i16): void; // size=2*length for utf16

function log(text:string):void{
logs(<i32>text+4,size(text),16);// 4 offset for internal struct // Utf16
}
}

function size(pointer:string):i16{
return load<i16>(<i32>pointer)*2 // size=2*length for utf16
}

export function main():void{
console.log("Hello AssemblyScript 😻 !")
}

// main()
Binary file added examples/hello-string/hello-string.wasm
Binary file not shown.
45 changes: 45 additions & 0 deletions examples/hello-string/hello-string.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
(module
(type $v (func))
(type $iv (func (param i32)))
(type $ii (func (param i32) (result i32)))
(type $iiiv (func (param i32 i32 i32)))
(import "console" "logs" (func $hello-string/console.logs (param i32 i32 i32)))
(global $HEAP_BASE i32 (i32.const 60))
(memory $0 1)
(data (i32.const 4) "\19\00\00\00H\00e\00l\00l\00o\00 \00A\00s\00s\00e\00m\00b\00l\00y\00S\00c\00r\00i\00p\00t\00 \00=\d8;\de\t\00!\00")
(export "main" (func $hello-string/main))
(export "memory" (memory $0))
(func $hello-string/size (; 1 ;) (type $ii) (param $0 i32) (result i32)
(return
(i32.shr_s
(i32.shl
(i32.mul
(i32.load16_s
(get_local $0)
)
(i32.const 2)
)
(i32.const 16)
)
(i32.const 16)
)
)
)
(func $hello-string/console.log (; 2 ;) (type $iv) (param $0 i32)
(call $hello-string/console.logs
(i32.add
(get_local $0)
(i32.const 4)
)
(call $hello-string/size
(get_local $0)
)
(i32.const 16)
)
)
(func $hello-string/main (; 3 ;) (type $v)
(call $hello-string/console.log
(i32.const 4)
)
)
)
13 changes: 13 additions & 0 deletions examples/hello-string/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# install https://github.com/AssemblyScript/assemblyscript if not present
# asc -v || npm install --save-dev AssemblyScript/assemblyscript

# compile Typescript to native WebAssembly
asc hello-string.ts -b hello-string.wasm -t hello-string.wast

# load and run the binary in node.js
wasmx hello-string.wasm

# in firefox:
# firefox hello-string.html

# todo : chrome needs to fetch() from (local) server
110 changes: 110 additions & 0 deletions examples/hello-string/wasmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env node
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this file? Did you write it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, in-lining the node code as in hello-world.sh would be a bit too much with all the imports

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use it for emcc generated code as well, thus the demangle and strange imports

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes no sense here, so I'll remove the clutter


file=arg=process.argv[2]

backtrace=function (print=1){
try{throw new Error()}catch(ex){if(print)console.error(trimStack(ex,1)); else return trimStack(ex)}
}

demangle=function (line){ // todo: proper cpp demangle lol
// return line
if(!line.match("at "))return line
var [at,name,fun]=line.trim().split(' ')
if(!name)return line
type=name.match(/E(.*)/)
type=type||name.match(/PK(.*)/)
type=type?type[1]||"":""
name=name.replace(/plE/g,'E')// constructor
name=name.replace(/E.*?$/g,'')
name=name.replace(/PK.*?$/g,'')
name=name.replace(/_Z\d/,'')
name=name.replace(/_ZN\d/,'')
name=name.replace(/\d/g,'.')
name=name.replace("_","")
// if(!type)
// return " at "+name
type=type.replace("v","")
type=type.replace("PK","*")
type=type.replace("i","int,")
type=type.replace("f","float,")
type=type.replace("c","char,")
type=type.replace(/,$/,'')
return file.replace(".wasm"," ")+name+"("+type+")"
}

trimStack=function (ex,more=0) {
// console.error(ex)
let keep = true
let stack = ex.stack?ex.stack.split("\n"):(ex.message||"").split("\n")
let caller = trimStack.caller.name;
ex.stack = stack.filter(x => {
if(caller&&x.match(caller))return 0
if (x.match("Object.<anonymous>")) keep = false
if (x.match("Module._compile")) keep = false
if (x.match("modulus.exports")) keep = false// todo
if(!keep && x.match("at "))more--
return keep||more>0
}).map(demangle).join("\n")//.replace(/at _/g,"at ")
return ex
}


// console.log(file)
// console.log()
binary = require('fs').readFileSync(file)
module = new WebAssembly.Module(binary)

// memory = new WebAssembly.Memory({initial: 256, maximum: 256});
// table = new WebAssembly.Table({initial: 10, maximum:10, element: "anyfunc"});

memory = new WebAssembly.Memory({initial: 16384, maximum: 65536});
table = new WebAssembly.Table({initial: 256, element: "anyfunc"});
buffer=new Buffer(memory.buffer) // node only!

nop = x=>0
log = x => console.log(x)

if(typeof(TextDecoder)!='undefined'){// WEB
const encoder = new TextDecoder('utf-16le');
string =function toUTF16StringA(pointer, size) {
let arr = new Uint8Array(heap.subarray(pointer, pointer + size));
console.log(encoder.decode(arr));
}
}else{ // NODE.js
string = function(pointer,length=-1, encoding=0){
if(length<=0)while(buffer[pointer+ ++length]); // auto determine length
if(encoding) encoding='utf16le'
else encoding='utf8' // todo better
decoded = buffer.slice(pointer,pointer+length).toString(encoding)
return decoded
}
}

// logs = (x,len) => console.log(string(x,len))
logs = function(pointer,len,encoding){ console.log(string(pointer,len,encoding)) }
logc = x => process.stdout.write(x?String.fromCodePoint(x):"\n"),

imports={
console:{log_char: c => process.stdout.write(String.fromCodePoint(c)),
logc, _logc:logc, logs, _logs:logs, logi: log, _logi:log, log, _log:log,
}, global:{NaN,Infinity},
env: {memory,table,abort:nop, nullFunc_X: log, abortStackOverflow:nop,
DYNAMICTOP_PTR: 100,
// STACKTOP:0,STACK_MAX:1000,enlargeMemory:log,getTotalMemory:log,abortOnCannotGrowMemory:log,
tempDoublePtr: 0, ABORT: 2, memoryBase: 0, tableBase: 0,
logc, _logc:logc, logs, _logs:logs, logi: log, _logi:log, log, _log:log,
logx: x => console.log(hex(x)),
_raise:x=>{throw new Error(string(x))},
backtrace:x=>console.error(backtrace()),
},
}
try{
instance= new WebAssembly.Instance(module,imports)
args=process.argv.slice(3,process.argv.length)
let main = instance.exports.main || instance.exports._main
if(instance.exports.memory)
buffer = new Buffer(instance.exports.memory.buffer) // node only
if (main) console.log(">>>", result=main(process.argc,args)||0)
}catch(ex){console.error(trimStack(ex));}

// console.log(Module.getValue(buffer+i*nByte, 'i32'));