diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/ch02/listing_2_11/globals.js b/ch02/listing_2_11/globals.js new file mode 100644 index 0000000..7c7059d --- /dev/null +++ b/ch02/listing_2_11/globals.js @@ -0,0 +1,24 @@ +const fs = require('fs'); +const bytes = fs.readFileSync('./globals.wasm'); +let global_test = null; + +let importObject = { + js: { + log_i32: (value) => { console.log ("i32: " , value)}, + log_f32: (value) => { console.log ("f32: ", value)}, + log_f64: (value) => { console.log ("f64: ", value)}, + }, + env: { + import_i32: 5_000_000_000, + import_f32: 123.0123456789, + import_f64: 123.0123456789, + } +}; + +(async () => { + let obj = await WebAssembly.instantiate(new Uint8Array (bytes), importObject); + + ({globaltest: global_test} = obj.instance.exports); + + global_test(); +})(); \ No newline at end of file diff --git a/ch02/listing_2_11/globals.wasm b/ch02/listing_2_11/globals.wasm new file mode 100644 index 0000000..b4fcbd4 --- /dev/null +++ b/ch02/listing_2_11/globals.wasm Binary files differ diff --git a/ch02/listing_2_11/globals.wat b/ch02/listing_2_11/globals.wat new file mode 100644 index 0000000..0c5d53d --- /dev/null +++ b/ch02/listing_2_11/globals.wat @@ -0,0 +1,15 @@ +(module + (global $import_integer_32 (import "env" "import_i32") i32) + (global $import_float_32 (import "env" "import_f32") f32) + (global $import_float_64 (import "env" "import_f64") f64) + + (import "js" "log_i32" (func $log_i32 (param i32))) + (import "js" "log_f32" (func $log_f32 (param f32))) + (import "js" "log_f64" (func $log_f64 (param f64))) + + (func (export "globaltest") + (call $log_i32 (global.get $import_integer_32)) + (call $log_f32 (global.get $import_float_32)) + (call $log_f64 (global.get $import_float_64)) + ) +) \ No newline at end of file diff --git a/ch02/listing_2_16/AddInt.wat b/ch02/listing_2_16/AddInt.wat new file mode 100644 index 0000000..5f60bdb --- /dev/null +++ b/ch02/listing_2_16/AddInt.wat @@ -0,0 +1,9 @@ +(module + (func (export "AddInt") + (param $value_1 i32) (param $value_2 i32) + (result i32) + local.get $value_1 + local.get $value_2 + i32.add + ) +) \ No newline at end of file diff --git a/ch02/listing_2_16/SumSquared.js b/ch02/listing_2_16/SumSquared.js new file mode 100644 index 0000000..6c610a9 --- /dev/null +++ b/ch02/listing_2_16/SumSquared.js @@ -0,0 +1,15 @@ +const fs = require('fs'); +const bytes = fs.readFileSync(__dirname + '/SumSquared.wasm'); +const val1 = parseInt(process.argv[2]); +const val2 = parseInt(process.argv[3]); + +(async () => { + const obj = + await WebAssembly.instantiate(new Uint8Array (bytes)); + + let sum_sq = + obj.instance.exports.SumSquared(val1, val2); + console.log ( + `(${val1} + ${val2}) * (${val1} + ${val2}) = ${sum_sq}` + ); +})(); \ No newline at end of file diff --git a/ch02/listing_2_16/SumSquared.wasm b/ch02/listing_2_16/SumSquared.wasm new file mode 100644 index 0000000..04e96bc --- /dev/null +++ b/ch02/listing_2_16/SumSquared.wasm Binary files differ diff --git a/ch02/listing_2_16/SumSquared.wat b/ch02/listing_2_16/SumSquared.wat new file mode 100644 index 0000000..1e30a32 --- /dev/null +++ b/ch02/listing_2_16/SumSquared.wat @@ -0,0 +1,12 @@ +(module + (func (export "SumSquared") + (param $value_1 i32) (param $value_2 i32) + (result i32) + (local $sum i32) + + (i32.add (local.get $value_1) (local.get $value_2)) + local.set $sum + + (i32.mul (local.get $sum) (local.get $sum)) + ) +) \ No newline at end of file diff --git a/ch03/func_perform/func_perform.js b/ch03/func_perform/func_perform.js new file mode 100644 index 0000000..b0e1384 --- /dev/null +++ b/ch03/func_perform/func_perform.js @@ -0,0 +1,28 @@ +const fs = require('fs') +const bytes = fs.readFileSync(__dirname + '/func_perform.wasm'); + +let i = 0; +let importObject = { + js: { + external_call: function() { + i++; + return i; + } + } +}; + +(async () => { + const obj = await WebAssembly.instantiate(new Uint8Array(bytes), importObject); + ({wasm_call, js_call} = obj.instance.exports); + + let start = Date.now(); + wasm_call(); + let time = Date.now() - start; + console.log('wasm_call time: ' + time); + + start = Date.now(); + js_call(); + time = Date.now() - start; + console.log('js_call time: ' + time); + +}) (); \ No newline at end of file diff --git a/ch03/func_perform/func_perform.wasm b/ch03/func_perform/func_perform.wasm new file mode 100644 index 0000000..460982a --- /dev/null +++ b/ch03/func_perform/func_perform.wasm Binary files differ diff --git a/ch03/func_perform/func_perform.wat b/ch03/func_perform/func_perform.wat new file mode 100644 index 0000000..2983638 --- /dev/null +++ b/ch03/func_perform/func_perform.wat @@ -0,0 +1,36 @@ +(module + ;; external call to a JS function + (import "js" "external_call" (func $external_call (result i32))) + (global $i (mut i32) (i32.const 0)) + + (func $internal_call (result i32) ;; returns an i32 to calling func + global.get $i + i32.const 1 + i32.add + + global.set $i ;; 1st 4 lines increment $i + + global.get $i ;; return $i to calling func + ) + + ;; wasm_call will be called from JS + (func (export "wasm_call") + (loop $again + call $internal_call ;; returns $i on the stack + i32.const 4_000_000 ;; push 4,000,000 onto stack + i32.le_u ;; is $i <= 4,000,000 + br_if $again ;; if true, loop $again + ) + ) + + (func (export "js_call") + (loop $again + (call $external_call) ;; calls the imported $external call + i32.const 4_000_000 ;; push 4,000,000 onto stack + i32.le_u ;; is $i <= 4,000,000 + br_if $again ;; if true, loop $again + ) + ) + + +) ;; end of module \ No newline at end of file diff --git a/ch03/function_table/table.js b/ch03/function_table/table.js new file mode 100644 index 0000000..b821689 --- /dev/null +++ b/ch03/function_table/table.js @@ -0,0 +1,72 @@ +const fs = require('fs'); +const export_bytes = fs.readFileSync(__dirname + '/table_export.wasm'); +const test_bytes = fs.readFileSync(__dirname + '/table_test.wasm'); + +let i = 0; +let increment = () => { + i++; + return i; +} + +let decrement = () => { + i--; + return i; +} + +const importObject = { + js: { + tbl: null, + increment: increment, + decrement: decrement, + wasm_increment: null, + wasm_decrement: null + } +}; + +(async () => { + let table_exp_obj = await WebAssembly.instantiate( + new Uint8Array(export_bytes), + importObject + ); + + importObject.js.tbl = table_exp_obj.instance.exports.tbl; + + importObject.js.wasm_increment = + table_exp_obj.instance.exports.increment; + + importObject.js.wasm_decrement = + table_exp_obj.instance.exports.decrement; + + let obj = await WebAssembly.instantiate( + new Uint8Array(test_bytes), + importObject + ); + + // use destructuring + ({ js_table_test, js_import_test, + wasm_table_test, wasm_import_test} = obj.instance.exports); + + i = 0; + let start = Date.now(); + js_table_test(); + let time = Date.now() - start; + console.log('js_table_test time: ' + time); + + i = 0; + start = Date.now(); + js_import_test(); + time = Date.now() - start; + console.log('js_import_test time: ' + time); + + i = 0; + start = Date.now(); + wasm_table_test(); + time = Date.now() - start; + console.log('wasm_table_test time: ' + time); + + i = 0; + start = Date.now(); + wasm_import_test(); + time = Date.now() - start; + console.log('wasm_import_test time: ' + time); +})(); \ No newline at end of file diff --git a/ch03/function_table/table_export.wasm b/ch03/function_table/table_export.wasm new file mode 100644 index 0000000..3f5d93f --- /dev/null +++ b/ch03/function_table/table_export.wasm Binary files differ diff --git a/ch03/function_table/table_export.wat b/ch03/function_table/table_export.wat new file mode 100644 index 0000000..82eb5bd --- /dev/null +++ b/ch03/function_table/table_export.wat @@ -0,0 +1,28 @@ +(module + + ;; js increment function + (import "js" "increment" (func $js_increment (result i32))) + + ;; js decrement function + (import "js" "decrement" (func $js_decrement (result i32))) + + ;; exported table with 4 functions + (table $tbl (export "tbl") 4 anyfunc) + + (global $i (mut i32) (i32.const 0)) + + (func $increment (export "increment") (result i32) + (global.set $i (i32.add (global.get $i) (i32.const 1))) + global.get $i ;; $i = $i + 1 + ) + + (func $decrement (export "decrement") (result i32) + (global.set $i (i32.sub (global.get $i) (i32.const 1))) + global.get $i ;; $i = $i - 1 + ) + + ;; populate the table + ;; (i32.const 0) is the index of the first element. + (elem (i32.const 0) $js_increment $js_decrement $increment $decrement) + +) ;; end module \ No newline at end of file diff --git a/ch03/function_table/table_test.wasm b/ch03/function_table/table_test.wasm new file mode 100644 index 0000000..b46562b --- /dev/null +++ b/ch03/function_table/table_test.wasm Binary files differ diff --git a/ch03/function_table/table_test.wat b/ch03/function_table/table_test.wat new file mode 100644 index 0000000..1536425 --- /dev/null +++ b/ch03/function_table/table_test.wat @@ -0,0 +1,107 @@ +(module + (import "js" "tbl" (table $tbl 4 anyfunc)) + + ;; import increment function -- the JS function + (import "js" "increment" (func $increment (result i32))) + + ;; import decrement function -- ths JS function + (import "js" "decrement" (func $decrement (result i32))) + + ;; import wasm_increment + (import "js" "wasm_increment" (func $wasm_increment (result i32))) + + ;; import wasm_decrement + (import "js" "wasm_decrement" (func $wasm_decrement (result i32))) + + ;; table function type definitions all i32 and take no parameters + (type $returns_i32 (func (result i32))) + + ;; JS increment function in table at index 0 + (global $inc_ptr i32 (i32.const 0)) + + ;; JS decrement function in table at index 1 + (global $dec_ptr i32 (i32.const 1)) + + ;; wasm increment function in table at index 2 + (global $wasm_inc_ptr i32 (i32.const 2)) + + ;; wasm decrement function in table at index 3 + (global $wasm_dec_ptr i32 (i32.const 3)) + + ;; Test performance of indirect table call of JS func + (func (export "js_table_test") + (loop $inc_cycle + ;; indirect call to JS increment func + (call_indirect (type $returns_i32) (global.get $inc_ptr)) + i32.const 4_000_000 + + ;; is the value returned by call to $inc_ptr <= 4_000_000? + i32.le_u + br_if $inc_cycle ;; if so loop again + ) + + (loop $dec_cycle + ;; indirect call to JS increment func + (call_indirect (type $returns_i32) (global.get $dec_ptr)) + i32.const 4_000_000 + + ;; is the value returned by call to $inc_ptr <= 4_000_000? + i32.le_u + br_if $dec_cycle ;; if so loop again + ) + ) + + ;; Test performance of direct call to JS function + (func (export "js_import_test") + (loop $inc_cycle + call $increment + i32.const 4_000_000 + i32.le_u + br_if $inc_cycle + ) + + (loop $dec_cycle + call $decrement + i32.const 4_000_000 + i32.le_u + br_if $dec_cycle + ) + ) + + ;; Test performance of an indirect call to WASM + (func (export "wasm_table_test") + (loop $inc_cycle + ;; indirect call to WASM increment function + (call_indirect (type $returns_i32) (global.get $wasm_inc_ptr)) + i32.const 4_000_000 + i32.le_u + br_if $inc_cycle + ) + + (loop $dec_cycle + ;; indirect call to WASM increment function + (call_indirect (type $returns_i32) (global.get $wasm_dec_ptr)) + i32.const 4_000_000 + i32.le_u + br_if $dec_cycle + ) + ) + + (func (export "wasm_import_test") + (loop $inc_cycle + ;; direct call to WASM inc func + call $wasm_increment + i32.const 4_000_000 + i32.le_u + br_if $inc_cycle + ) + + (loop $dec_cycle + ;; direct call to WASM inc func + call $wasm_decrement + i32.const 4_000_000 + i32.le_u + br_if $dec_cycle + ) + ) +) ;; end of module \ No newline at end of file diff --git a/ch03/is_prime/is_prime.js b/ch03/is_prime/is_prime.js new file mode 100644 index 0000000..70caa98 --- /dev/null +++ b/ch03/is_prime/is_prime.js @@ -0,0 +1,12 @@ +const fs = require('fs'); +const bytes = fs.readFileSync(__dirname + '/is_prime.wasm'); +const value = parseInt(process.argv[2]); + +(async () => { + const obj = await WebAssembly.instantiate(new Uint8Array(bytes)); + if (!!obj.instance.exports.is_prime(value)) { + console.log(`${value} is prime!`); + } else { + console.log(`${value} is not prime`); + } +})(); \ No newline at end of file diff --git a/ch03/is_prime/is_prime.wasm b/ch03/is_prime/is_prime.wasm new file mode 100644 index 0000000..69cfebc --- /dev/null +++ b/ch03/is_prime/is_prime.wasm Binary files differ diff --git a/ch03/is_prime/is_prime.wat b/ch03/is_prime/is_prime.wat new file mode 100644 index 0000000..ec2df46 --- /dev/null +++ b/ch03/is_prime/is_prime.wat @@ -0,0 +1,72 @@ +(module + + (func $even_check (param $n i32) (result i32) + ;; returns 1 if $n is even and 0 if $n is odd + local.get $n + i32.const 2 + i32.rem_u + i32.const 0 + i32.eq ;; $n % 2 == 0 + ) + + (func $eq_2 (param $n i32) (result i32) + local.get $n + i32.const 2 + i32.eq ;; returns 1 if $n == 2 + ) + + (func $multiple_check (param $n i32) (param $m i32) (result i32) + ;; returns 1 if $n is a multiple of $m, returns 0 if it is not + local.get $n + local.get $m + i32.rem_u ;; get the remainder of $n / $m + i32.const 0 ;; is the remainder equal to 0, i.e. is $n a multiple of $m + i32.eq + ) + + (func $is_prime (export "is_prime") (param $n i32) (result i32) + ;; return 1 if the $n is prime and 0 if $n is not + (local $i i32) ;; loop counter + + ;; check if $n == 1. 1 is not prime + (if (i32.eq (local.get $n) (i32.const 1)) + (then + i32.const 0 + return + ) + ) + + ;; check if $n == 2, which is prime + (if (call $eq_2 (local.get $n)) + (then + i32.const 1 + return + ) + ) + + (block $not_prime + (call $even_check (local.get $n)) + br_if $not_prime ;; even numbers, other than 2, are not prime + + (local.set $i (i32.const 1)) + (loop $prime_test_loop + + ;; local.tee pops $i off stack and then pushes back on stack after calculation + (local.tee $i (i32.add (local.get $i) (i32.const 2))) ;; i += 2 + local.get $n + + i32.ge_u ;; $i >= $n + if ;; if $i >= $n, $n is prime + i32.const 1 + return + end + + (call $multiple_check (local.get $n) (local.get $i)) + br_if $not_prime ;; if $n is a multiple of $i it is not prime + br $prime_test_loop ;; branch back to top of loop + ) ;; loop $prime_test_loop + ) ;; block $not_prime + + i32.const 0 ;; return false (implicit return) + ) ;; func $is_prime +) ;; end module \ No newline at end of file