wasm 访问html元素,wasm.html.markdown

---

language: WebAssembly

filename: learn-wasm.wast

contributors:

- ["Dean Shaff", "http://dean-shaff.github.io"]

---

```

;; learn-wasm.wast

(module

;; In WebAssembly, everything is included in a module. Moreover, everything

;; can be expressed as an s-expression. Alternatively, there is the

;; "stack machine" syntax, but that is not compatible with Binaryen

;; intermediate representation (IR) syntax.

;; The Binaryen IR format is *mostly* compatible with WebAssembly text format.

;; There are some small differences:

;; local_set -> local.set

;; local_get -> local.get

;; We have to enclose code in functions

;; Data Types

(func $data_types

;; WebAssembly has only four types:

;; i32 - 32 bit integer

;; i64 - 64 bit integer (not supported in JavaScript)

;; f32 - 32 bit floating point

;; f64 - 64 bit floating point

;; We can declare local variables with the "local" keyword

;; We have to declare all variables before we start doing anything

;; inside the function

(local $int_32 i32)

(local $int_64 i64)

(local $float_32 f32)

(local $float_64 f64)

;; These values remain uninitialized.

;; To set them to a value, we can use .const:

(local.set $int_32 (i32.const 16))

(local.set $int_32 (i64.const 128))

(local.set $float_32 (f32.const 3.14))

(local.set $float_64 (f64.const 1.28))

)

;; Basic operations

(func $basic_operations

;; In WebAssembly, everything is an s-expression, including

;; doing math, or getting the value of some variable

(local $add_result i32)

(local $mult_result f64)

(local.set $add_result (i32.add (i32.const 2) (i32.const 4)))

;; the value of add_result is now 6!

;; We have to use the right data type for each operation:

;; (local.set $mult_result (f32.mul (f32.const 2.0) (f32.const 4.0))) ;; WRONG! mult_result is f64!

(local.set $mult_result (f64.mul (f64.const 2.0) (f64.const 4.0)))

;; WebAssembly has some builtin operations, like basic math and bitshifting.

;; Notably, it does not have built in trigonometric functions.

;; In order to get access to these functions, we have to either

;; - implement them ourselves (not recommended)

;; - import them from elsewhere (later on)

)

;; Functions

;; We specify arguments with the `param` keyword, and specify return values

;; with the `result` keyword

;; The current value on the stack is the return value of a function

;; We can call other functions we've defined with the `call` keyword

(func $get_16 (result i32)

(i32.const 16)

)

(func $add (param $param0 i32) (param $param1 i32) (result i32)

(i32.add

(local.get $param0)

(local.get $param1)

)

)

(func $double_16 (result i32)

(i32.mul

(i32.const 2)

(call $get_16))

)

;; Up until now, we haven't be able to print anything out, nor do we have

;; access to higher level math functions (pow, exp, or trig functions).

;; Moreover, we haven't been able to use any of the WASM functions in Javascript!

;; The way we get those functions into WebAssembly

;; looks different whether we're in a Node.js or browser environment.

;; If we're in Node.js we have to do two steps. First we have to convert the

;; WASM text representation into actual webassembly. If we're using Binyaren,

;; we can do that with a command like the following:

;; wasm-as learn-wasm.wast -o learn-wasm.wasm

;; We can apply Binaryen optimizations to that file with a command like the

;; following:

;; wasm-opt learn-wasm.wasm -o learn-wasm.opt.wasm -O3 --rse

;; With our compiled WebAssembly, we can now load it into Node.js:

;; const fs = require('fs')

;; const instantiate = async function (inFilePath, _importObject) {

;; var importObject = {

;; console: {

;; log: (x) => console.log(x),

;; },

;; math: {

;; cos: (x) => Math.cos(x),

;; }

;; }

;; importObject = Object.assign(importObject, _importObject)

;;

;; var buffer = fs.readFileSync(inFilePath)

;; var module = await WebAssembly.compile(buffer)

;; var instance = await WebAssembly.instantiate(module, importObject)

;; return instance.exports

;; }

;;

;; const main = function () {

;; var wasmExports = await instantiate('learn-wasm.wasm')

;; wasmExports.print_args(1, 0)

;; }

;; The following snippet gets the functions from the importObject we defined

;; in the JavaScript instantiate async function, and then exports a function

;; "print_args" that we can call from Node.js

(import "console" "log" (func $print_i32 (param i32)))

(import "math" "cos" (func $cos (param f64) (result f64)))

(func $print_args (param $arg0 i32) (param $arg1 i32)

(call $print_i32 (local.get $arg0))

(call $print_i32 (local.get $arg1))

)

(export "print_args" (func $print_args))

;; Loading in data from WebAssembly memory.

;; Say that we want to apply the cosine function to a Javascript array.

;; We need to be able to access the allocated array, and iterate through it.

;; This example will modify the input array inplace.

;; f64.load and f64.store expect the location of a number in memory *in bytes*.

;; If we want to access the 3rd element of an array, we have to pass something

;; like (i32.mul (i32.const 8) (i32.const 2)) to the f64.store function.

;; In JavaScript, we would call `apply_cos64` as follows

;; (using the instantiate function from earlier):

;;

;; const main = function () {

;; var wasm = await instantiate('learn-wasm.wasm')

;; var n = 100

;; const memory = new Float64Array(wasm.memory.buffer, 0, n)

;; for (var i=0; i

;; memory[i] = i;

;; }

;; wasm.apply_cos64(n)

;; }

;;

;; This function will not work if we allocate a Float32Array on the JavaScript

;; side.

(memory (export "memory") 100)

(func $apply_cos64 (param $array_length i32)

;; declare the loop counter

(local $idx i32)

;; declare the counter that will allow us to access memory

(local $idx_bytes i32)

;; constant expressing the number of bytes in a f64 number.

(local $bytes_per_double i32)

;; declare a variable for storing the value loaded from memory

(local $temp_f64 f64)

(local.set $idx (i32.const 0))

(local.set $idx_bytes (i32.const 0)) ;; not entirely necessary

(local.set $bytes_per_double (i32.const 8))

(block

(loop

;; this sets idx_bytes to bytes offset of the value we're interested in.

(local.set $idx_bytes (i32.mul (local.get $idx) (local.get $bytes_per_double)))

;; get the value of the array from memory:

(local.set $temp_f64 (f64.load (local.get $idx_bytes)))

;; now apply the cosine function:

(local.set $temp_64 (call $cos (local.get $temp_64)))

;; now store the result at the same location in memory:

(f64.store

(local.get $idx_bytes)

(local.get $temp_64))

;; do it all in one step instead

(f64.store

(local.get $idx_bytes)

(call $cos

(f64.load

(local.get $idx_bytes))))

;; increment the loop counter

(local.set $idx (i32.add (local.get $idx) (i32.const 1)))

;; stop the loop if the loop counter is equal the array length

(br_if 1 (i32.eq (local.get $idx) (local.get $array_length)))

(br 0)

)

)

)

(export "apply_cos64" (func $apply_cos64))

;; Wasm is a stack-based language, but for returning values more complicated

;; than an int/float, a separate memory stack has to be manually managed. One

;; approach is to use a mutable global to store the stack_ptr. We give

;; ourselves 1MiB of memstack and grow it downwards.

;;

;; Below is a demonstration of how this C code **might** be written by hand

;;

;; typedef struct {

;; int a;

;; int b;

;; } sum_struct_t;

;;

;; sum_struct_t sum_struct_create(int a, int b) {

;; return (sum_struct_t){a, b};

;; }

;;

;; int sum_local() {

;; sum_struct_t s = sum_struct_create(40, 2);

;; return s.a + s.b;

;; }

;; Unlike C, we must manage our own memory stack. We reserve 1MiB

(global $memstack_ptr (mut i32) (i32.const 65536))

;; Structs can only be returned by reference

(func $sum_struct_create

(param $sum_struct_ptr i32)

(param $var$a i32)

(param $var$b i32)

;; c// sum_struct_ptr->a = a;

(i32.store

(get_local $sum_struct_ptr)

(get_local $var$a)

)

;; c// sum_struct_ptr->b = b;

(i32.store offset=4

(get_local $sum_struct_ptr)

(get_local $var$b)

)

)

(func $sum_local (result i32)

(local $var$sum_struct$a i32)

(local $var$sum_struct$b i32)

(local $local_memstack_ptr i32)

;; reserve memstack space

(i32.sub

(get_global $memstack_ptr)

(i32.const 8)

)

tee_local $local_memstack_ptr ;; tee both stores and returns given value

set_global $memstack_ptr

;; call the function, storing the result in the memstack

(call $sum_struct_create

((;$sum_struct_ptr=;) get_local $local_memstack_ptr)

((;$var$a=;) i32.const 40)

((;$var$b=;) i32.const 2)

)

;; retrieve values from struct

(set_local $var$sum_struct$a

(i32.load offset=0 (get_local $local_memstack_ptr))

)

(set_local $var$sum_struct$b

(i32.load offset=4 (get_local $local_memstack_ptr))

)

;; unreserve memstack space

(set_global $memstack_ptr

(i32.add

(get_local $local_memstack_ptr)

(i32.const 8)

)

)

(i32.add

(get_local $var$sum_struct$a)

(get_local $var$sum_struct$b)

)

)

(export "sum_local" (func $sum_local))

)

```

一键复制

编辑

Web IDE

原始数据

按行查看

历史

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值