Instructions

WebAssembly computation is performed by executing individual instructions.

Numeric Instructions

Numeric instructions are defined in terms of the generic numeric operators. The mapping of numeric instructions to their underlying operators is expressed by the following definition:

opiN(i1,,ik)=iopN(i1,,ik)opfN(z1,,zk)=fopN(z1,,zk)

And for conversion operators:

cvtopt1,t2sx?(c)=cvtop|t1|,|t2|sx?(c)

Where the underlying operators are partial, the corresponding instruction will trap when the result is not defined. Where the underlying operators are non-deterministic, because they may return one of multiple possible NaN values, so are the corresponding instructions.

Note

For example, the result of instruction i32.add applied to operands i1,i2 invokes addi32(i1,i2), which maps to the generic iadd32(i1,i2) via the above definition. Similarly, i64.trunc_f32_s applied to z invokes truncf32,i64s(z), which maps to the generic trunc32,64s(z).

t.const c

  1. Push the value t.const c to the stack.

Note

No formal reduction rule is required for this instruction, since const instructions already are values.

t.unop

  1. Assert: due to validation, a value of value type t is on the top of the stack.

  2. Pop the value t.const c1 from the stack.

  3. If unopt(c1) is defined, then:

    1. Let c be a possible result of computing unopt(c1).

    2. Push the value t.const c to the stack.

  4. Else:

    1. Trap.

(t.const c1) t.unop(t.const c)(ifcunopt(c1))(t.const c1) t.unoptrap(ifunopt(c1)={})

t.binop

  1. Assert: due to validation, two values of value type t are on the top of the stack.

  2. Pop the value t.const c2 from the stack.

  3. Pop the value t.const c1 from the stack.

  4. If binopt(c1,c2) is defined, then:

    1. Let c be a possible result of computing binopt(c1,c2).

    2. Push the value t.const c to the stack.

  5. Else:

    1. Trap.

(t.const c1) (t.const c2) t.binop(t.const c)(ifcbinopt(c1,c2))(t.const c1) (t.const c2) t.binoptrap(ifbinopt(c1,c2)={})

t.testop

  1. Assert: due to validation, a value of value type t is on the top of the stack.

  2. Pop the value t.const c1 from the stack.

  3. Let c be the result of computing testopt(c1).

  4. Push the value i32.const c to the stack.

(t.const c1) t.testop(i32.const c)(ifc=testopt(c1))

t.relop

  1. Assert: due to validation, two values of value type t are on the top of the stack.

  2. Pop the value t.const c2 from the stack.

  3. Pop the value t.const c1 from the stack.

  4. Let c be the result of computing relopt(c1,c2).

  5. Push the value i32.const c to the stack.

(t.const c1) (t.const c2) t.relop(i32.const c)(ifc=relopt(c1,c2))

t2.cvtop_t1_sx?

  1. Assert: due to validation, a value of value type t1 is on the top of the stack.

  2. Pop the value t1.const c1 from the stack.

  3. If cvtopt1,t2sx?(c1) is defined:

    1. Let c2 be a possible result of computing cvtopt1,t2sx?(c1).

    2. Push the value t2.const c2 to the stack.

  4. Else:

    1. Trap.

(t1.const c1) t2.cvtop_t1_sx?(t2.const c2)(ifc2cvtopt1,t2sx?(c1))(t1.const c1) t2.cvtop_t1_sx?trap(ifcvtopt1,t2sx?(c1)={})

Reference Instructions

ref.null x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Push the value ref.null deftype to the stack.

F;(ref.null x)F;(ref.null deftype)(ifdeftype=F.module.types[x])

Note

No formal reduction rule is required for the case ref.null absheaptype, since the instruction form is already a value.

ref.func x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.funcaddrs[x] exists.

  3. Let a be the function address F.module.funcaddrs[x].

  4. Push the value ref.func a to the stack.

F;(ref.func x)F;(ref.func a)(ifa=F.module.funcaddrs[x])

ref.is_null

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Push the value i32.const 1 to the stack.

  4. Else:

    1. Push the value i32.const 0 to the stack.

ref ref.is_null(i32.const 1)(ifref=ref.null ht)ref ref.is_null(i32.const 0)(otherwise)

ref.as_non_null

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Trap.

  4. Push the value ref back to the stack.

ref ref.as_non_nulltrap(ifref=ref.null ht)ref ref.as_non_nullref(otherwise)

ref.eq

  1. Assert: due to validation, two reference values are on the top of the stack.

  2. Pop the value ref2 from the stack.

  3. Pop the value ref1 from the stack.

  4. If ref1 is the same as ref2, then:

    1. Push the value i32.const 1 to the stack.

  5. Else:

    1. Push the value i32.const 0 to the stack.

ref1 ref2 ref.eq(i32.const 1)(ifref1=(ref.null ht1)ref2=(ref.null ht2))ref1 ref2 ref.eq(i32.const 1)(ifref1=ref2)ref1 ref2 ref.eq(i32.const 0)(otherwise)

ref.test rt

  1. Let F be the current frame.

  2. Let rt1 be the reference type closF.module(rt).

  3. Assert: due to validation, rt1 is closed.

  4. Assert: due to validation, a reference value is on the top of the stack.

  5. Pop the value ref from the stack.

  6. Assert: due to validation, the reference value is valid with some reference type.

  7. Let rt2 be the reference type of ref.

  8. If the reference type rt2 matches rt1, then:

    1. Push the value i32.const 1 to the stack.

  9. Else:

    1. Push the value i32.const 0 to the stack.

S;F;ref (ref.test rt)(i32.const 1)(ifSref:rtrtclosF.module(rt))S;F;ref (ref.test rt)(i32.const 0)(otherwise)

ref.cast rt

  1. Let F be the current frame.

  2. Let rt1 be the reference type closF.module(rt).

  3. Assert: due to validation, rt1 is closed.

  4. Assert: due to validation, a reference value is on the top of the stack.

  5. Pop the value ref from the stack.

  6. Assert: due to validation, the reference value is valid with some reference type.

  7. Let rt2 be the reference type of ref.

  8. If the reference type rt2 matches rt1, then:

    1. Push the value ref back to the stack.

  9. Else:

    1. Trap.

S;F;ref (ref.cast rt)ref(ifSref:rtrtclosF.module(rt))S;F;ref (ref.cast rt)trap(otherwise)

ref.i31

  1. Assert: due to validation, a value of type i32 is on the top of the stack.

  2. Pop the value i32.const i from the stack.

  3. Let j be the result of computing wrap32,31(i).

  4. Push the reference value (ref.i31 j) to the stack.

(i32.const i) ref.i31(ref.i31 wrap32,31(i))

i31.get_sx

  1. Assert: due to validation, a value of type (ref null i31) is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null t, then:

    1. Trap.

  4. Assert: due to validation, a ref is a scalar reference.

  5. Let ref.i31 i be the reference value ref.

  6. Let j be the result of computing extend31,32sx(i).

  7. Push the value i32.const j to the stack.

(ref.i31 i) i31.get_sx(i32.const extend31,32sx(i))(ref.null t) i31.get_sxtrap

struct.new x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is a structure type.

  5. Let struct ft be the expanded structure type of deftype.

  6. Let n be the length of the field type sequence ft.

  7. Assert: due to validation, n values are on the top of the stack.

  8. Pop the n values val from the stack.

  9. For every value vali in val and corresponding field type fti in ft:

    1. Let fieldvali be the result of computing packfti(vali)).

  10. Let fieldval the concatenation of all field values fieldvali.

  11. Let si be the structure instance {type deftype,fields fieldval}.

  12. Let a be the length of S.structs.

  13. Append si to S.structs.

  14. Push the structure reference ref.struct a to the stack.

S;F;valn (struct.new x)S;F;(ref.struct |S.structs|)(ifexpand(F.module.types[x])=struct ftnsi={type F.module.types[x],fields (packft(val))n}S=Swithstructs=S.structs si)

struct.new_default x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is a structure type.

  5. Let struct ft be the expanded structure type of deftype.

  6. Let n be the length of the field type sequence ft.

  7. For every field type fti in ft:

    1. Let ti be the value type unpack(fti).

    2. Assert: due to validation, defaultti is defined.

    3. Push the value defaultti to the stack.

  8. Execute the instruction (struct.new x).

F;(struct.new_default x)(defaultunpack(ft)))n (struct.new x)(ifexpand(F.module.types[x])=struct ftn)

struct.get_sx? x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is a structure type with at least y+1 fields.

  5. Let struct ft be the expanded structure type of deftype.

  6. Let fty be the y-th field type of ft.

  7. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  8. Pop the value ref from the stack.

  9. If ref is ref.null t, then:

    1. Trap.

  10. Assert: due to validation, a ref is a structure reference.

  11. Let ref.struct a be the reference value ref.

  12. Assert: due to validation, the structure instance S.structs[a] exists and has at least y+1 fields.

  13. Let fieldval be the field value S.structs[a].fields[y].

  14. Let val be the result of computing unpackftysx?(fieldval)).

  15. Push the value val to the stack.

S;F;(ref.struct a) (struct.get_sx? x y)val(ifexpand(F.module.types[x])=struct ftnval=unpackftn[y]sx?(S.structs[a].fields[y]))S;F;(ref.null t) (struct.get_sx? x y)trap

struct.set x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is a structure type with at least y+1 fields.

  5. Let struct ft be the expanded structure type of deftype.

  6. Let fty be the y-th field type of ft.

  7. Assert: due to validation, a value is on the top of the stack.

  8. Pop the value val from the stack.

  9. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  10. Pop the value ref from the stack.

  11. If ref is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, a ref is a structure reference.

  2. Let ref.struct a be the reference value ref.

  3. Assert: due to validation, the structure instance S.structs[a] exists and has at least y+1 fields.

  4. Let fieldval be the result of computing packfty(val)).

  5. Replace the field value S.structs[a].fields[y] with fieldval.

S;F;(ref.struct a) val (struct.set x y)S;ϵ(ifexpand(F.module.types[x])=struct ftnS=Swithstructs[a].fields[y]=packftn[y](val))S;F;(ref.null t) val (struct.set x y)trap

array.new x

  1. Assert: due to validation, a value of type i32 is on the top of the stack.

  2. Pop the value (i32.const n) from the stack.

  3. Assert: due to validation, a value is on the top of the stack.

  4. Pop the value val from the stack.

  5. Push the value val to the stack n times.

  6. Execute the instruction (array.new_fixed x n).

val (i32.const n) (array.new x)valn (array.new_fixed x n)

array.new_default x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type of deftype.

  6. Assert: due to validation, a value of type i32 is on the top of the stack.

  7. Pop the value i32.const n from the stack.

  8. Let t be the value type unpack(ft).

  9. Assert: due to validation, defaultt is defined.

  10. Push the value defaultt to the stack n times.

  11. Execute the instruction (array.new_fixed x n).

F;(i32.const n) (array.new_default x)(defaultunpack(ft))n (array.new_fixed x n)(ifexpand(F.module.types[x])=array ft)

array.new_fixed x n

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is a array type.

  5. Let array ft be the expanded array type of deftype.

  6. Assert: due to validation, n values are on the top of the stack.

  7. Pop the n values val from the stack.

  8. For every value vali in val:

    1. Let fieldvali be the result of computing packft(vali)).

  9. Let fieldval be the concatenation of all field values fieldvali.

  10. Let ai be the array instance {type deftype,fields fieldval}.

  11. Let a be the length of S.arrays.

  12. Append ai to S.arrays.

  13. Push the array reference ref.array a to the stack.

S;F;valn (array.new_fixed x n)S;F;(ref.array |S.arrays|)(ifexpand(F.module.types[x])=array ftai={type F.module.types[x],fields (packft(val))n}S=Switharrays=S.arrays ai)

array.new_data x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type of deftype.

  6. Assert: due to validation, the data address F.module.dataaddrs[y] exists.

  7. Let da be the data address F.module.dataaddrs[y].

  8. Assert: due to validation, the data instance S.datas[da] exists.

  9. Let datainst be the data instance S.datas[da].

  10. Assert: due to validation, two values of type i32 are on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Pop the value i32.const s from the stack.

  13. Assert: due to validation, the field type ft has a defined bit width.

  14. Let z be the bit width of field type ft divided by eight.

  15. If the sum of s and n times z is larger than the length of datainst.data, then:

    1. Trap.

  16. Let b be the byte sequence datainst.data[s:nz].

  17. Let t be the value type unpack(ft).

  18. For each of the n consecutive subsequences bz of b:

    1. Assert: due to validation, bytesft is defined.

    2. Let ci be the constant for which bytesft(ci) is bz.

    3. Push the value t.const ci to the stack.

  19. Execute the instruction (array.new_fixed x n).

 S;F;(i32.const s) (i32.const n) (array.new_data x y)trap(ifexpand(F.module.types[x])=array fts+n|ft|/8>|S.datas[F.module.dataaddrs[y]].data|)S;F;(i32.const s) (i32.const n) (array.new_data x y)(t.const c)n (array.new_fixed x n)(ifexpand(F.module.types[x])=array ftt=unpack(ft)concat((bytesft(c))n)=S.datas[F.module.dataaddrs[y]].data[s:n|ft|/8]

array.new_elem x y

  1. Let F be the current frame.

  2. Assert: due to validation, the element address F.module.elemaddrs[y] exists.

  3. Let ea be the element address F.module.elemaddrs[y].

  4. Assert: due to validation, the element instance S.elems[ea] exists.

  5. Let eleminst be the element instance S.elems[ea].

  6. Assert: due to validation, two values of type i32 are on the top of the stack.

  7. Pop the value (i32.const n) from the stack.

  8. Pop the value (i32.const s) from the stack.

  9. If the sum of s and n is larger than the length of eleminst.elem, then:

    1. Trap.

  10. Let ref be the reference sequence eleminst.elem[s:n].

  11. Push the references ref to the stack.

  12. Execute the instruction (array.new_fixed x n).

 S;F;(i32.const s) (i32.const n) (array.new_elem x y)trap(ifs+n>|S.elems[F.module.elemaddrs[y]].elem|)S;F;(i32.const s) (i32.const n) (array.new_elem x y)refn (array.new_fixed x n)(ifrefn=S.elems[F.module.elemaddrs[y]].elem[s:n])

array.get_sx? x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type of deftype.

  6. Assert: due to validation, a value of type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  9. Pop the value ref from the stack.

  10. If ref is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref is an array reference.

  2. Let ref.array a be the reference value ref.

  3. Assert: due to validation, the array instance S.arrays[a] exists.

  4. If n is larger than or equal to the length of S.arrays[a].fields, then:

    1. Trap.

  5. Let fieldval be the field value S.arrays[a].fields[i].

  6. Let val be the result of computing unpackftsx?(fieldval)).

  7. Push the value val to the stack.

 S;F;(ref.array a) (i32.const i) (array.get_sx? x)trap(ifi|arrays[a].fields|)S;F;(ref.array a) (i32.const i) (array.get_sx? x)val(ifexpand(F.module.types[x])=array ftval=unpackftsx?(S.arrays[a].fields[i]))S;F;(ref.null t) (i32.const i) (array.get_sx? x)trap

array.set x

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type of deftype.

  6. Assert: due to validation, a value is on the top of the stack.

  7. Pop the value val from the stack.

  8. Assert: due to validation, a value of type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  11. Pop the value ref from the stack.

  12. If ref is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref is an array reference.

  2. Let ref.array a be the reference value ref.

  3. Assert: due to validation, the array instance S.arrays[a] exists.

  4. If n is larger than or equal to the length of S.arrays[a].fields, then:

    1. Trap.

  5. Let fieldval be the result of computing packft(val)).

  6. Replace the field value S.arrays[a].fields[i] with fieldval.

 S;F;(ref.array a) (i32.const i) val (array.set x)trap(ifi|arrays[a].fields|)S;F;(ref.array a) (i32.const i) val (array.set x)S;ϵ(ifexpand(F.module.types[x])=array ftS=Switharrays[a].fields[i]=packft(val))S;F;(ref.null t) (i32.const i) val (array.set x)trap

array.len

  1. Assert: due to validation, a value of type (ref null array) is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null t, then:

    1. Trap.

  4. Assert: due to validation, ref is an array reference.

  5. Let ref.array a be the reference value ref.

  6. Assert: due to validation, the array instance S.arrays[a] exists.

  7. Let n be the length of S.arrays[a].fields.

  8. Push the value (i32.const n) to the stack.

S;(ref.array a) array.len(i32.const |S.arrays[a].fields|)S;(ref.null t) array.lentrap

array.fill x

  1. Assert: due to validation, a value of type i32 is on the top of the stack.

  2. Pop the value n from the stack.

  3. Assert: due to validation, a value is on the top of the stack.

  4. Pop the value val from the stack.

  5. Assert: due to validation, a value of type i32 is on the top of the stack.

  6. Pop the value d from the stack.

  7. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  8. Pop the value ref from the stack.

  9. If ref is ref.null t, then:

    1. Trap.

  10. Assert: due to validation, ref is an array reference.

  11. Let ref.array a be the reference value ref.

  12. Assert: due to validation, the array instance S.arrays[a] exists.

  13. If d+n is larger than the length of S.arrays[a].fields, then:

    1. Trap.

  14. If n=0, then:

    1. Return.

  15. Push the value ref.array a to the stack.

  16. Push the value i32.const d to the stack.

  17. Push the value val to the stack.

  18. Execute the instruction array.set x.

  19. Push the value ref.array a to the stack.

  20. Assert: due to the earlier check against the array size, d+1<232.

  21. Push the value i32.const (d+1) to the stack.

  22. Push the value val to the stack.

  23. Push the value i32.const (n1) to the stack.

  24. Execute the instruction array.fill x.

 S;(ref.array a) (i32.const d) val (i32.const n) (array.fill x)trap(ifd+n>|S.arrays[a].fields|)S;(ref.array a) (i32.const d) val (i32.const 0) (array.fill x)ϵ(otherwise)S;(ref.array a) (i32.const d) val (i32.const n+1) (array.fill x)(ref.array a) (i32.const d) val (array.set x)(ref.array a) (i32.const d+1) val (i32.const n) (array.fill x)(otherwise)S;(ref.null t) (i32.const d) val (i32.const n) (array.fill x)trap

array.copy x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[y] exists.

  3. Let deftype be the defined type F.module.types[y].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array mut st be the expanded array type deftype.

  6. Assert: due to validation, a value of type i32 is on the top of the stack.

  7. Pop the value i32.const n from the stack.

  8. Assert: due to validation, a value of type i32 is on the top of the stack.

  9. Pop the value i32.const s from the stack.

  10. Assert: due to validation, a value of type (ref null y) is on the top of the stack.

  11. Pop the value ref2 from the stack.

  12. Assert: due to validation, a value of type i32 is on the top of the stack.

  13. Pop the value i32.const d from the stack.

  14. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  15. Pop the value ref1 from the stack.

  16. If ref1 is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref1 is an array reference.

  2. Let ref.array a1 be the reference value ref1.

  3. If ref2 is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref2 is an array reference.

  2. Let ref.array a2 be the reference value ref2.

  3. Assert: due to validation, the array instance S.arrays[a1] exists.

  4. Assert: due to validation, the array instance S.arrays[a2] exists.

  5. If d+n is larger than the length of S.arrays[a1].fields, then:

    1. Trap.

  6. If s+n is larger than the length of S.arrays[a2].fields, then:

    1. Trap.

  7. If n=0, then:

    1. Return.

  8. If ds, then:

    1. Push the value ref.array a1 to the stack.

    2. Push the value i32.const d to the stack.

    3. Push the value ref.array a2 to the stack.

    4. Push the value i32.const s to the stack.

    5. Execute getfield(st).

    6. Execute the instruction array.set x.

    7. Push the value ref.array a1 to the stack.

    8. Assert: due to the earlier check against the array size, d+1<232.

    9. Push the value i32.const (d+1) to the stack.

    10. Push the value ref.array a2 to the stack.

    11. Assert: due to the earlier check against the array size, s+1<232.

    12. Push the value i32.const (s+1) to the stack.

  9. Else:

    1. Push the value ref.array a1 to the stack.

    2. Assert: due to the earlier check against the array size, d+n1<232.

    3. Push the value i32.const (d+n1) to the stack.

    4. Push the value ref.array a2 to the stack.

    5. Assert: due to the earlier check against the array size, s+n1<232.

    6. Push the value i32.const (s+n1) to the stack.

    7. Execute getfield(st).

    8. Execute the instruction array.set x.

    9. Push the value ref.array a1 to the stack.

    10. Push the value i32.const d to the stack.

    11. Push the value ref.array a2 to the stack.

    12. Push the value i32.const s to the stack.

  10. Push the value i32.const (n1) to the stack.

  11. Execute the instruction array.copy x y.

 S;F;(ref.array a1) (i32.const d) (ref.array a2) (i32.const s) (i32.const n) (array.copy x y)trap(ifd+n>|S.arrays[a1].fields|s+n>|S.arrays[a2].fields|)S;F;(ref.array a1) (i32.const d) (ref.array a2) (i32.const s) (i32.const 0) (array.copy x y)ϵ(otherwise)S;F;(ref.array a1) (i32.const d) (ref.array a2) (i32.const s) (i32.const n+1) (array.copy x y)(ref.array a1) (i32.const d)(ref.array a2) (i32.const s) getfield(st)(array.set x)(ref.array a1) (i32.const d+1) (ref.array a2) (i32.const s+1) (i32.const n) (array.copy x y)(otherwise,ifdsF.module.types[y]=array mut st)S;F;(ref.array a1) (i32.const d) (ref.array a2) (i32.const s) (i32.const n+1) (array.copy x y)(ref.array a1) (i32.const d+n)(ref.array a2) (i32.const s+n) getfield(st)(array.set x)(ref.array a1) (i32.const d) (ref.array a2) (i32.const s) (i32.const n) (array.copy x y)(otherwise,ifd>sF.module.types[y]=array mut st)S;F;(ref.null t) (i32.const d) val (i32.const s) (i32.const n) (array.copy x y)trapS;F;val (i32.const d) (ref.null t) (i32.const s) (i32.const n) (array.copy x y)trap

Where:

getfield(valtype)=array.get ygetfield(packedtype)=array.get_u y

array.init_data x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type deftype.

  6. Assert: due to validation, the data address F.module.dataaddrs[y] exists.

  7. Let da be the data address F.module.dataaddrs[y].

  8. Assert: due to validation, the data instance S.datas[da] exists.

  9. Let datainst be the data instance S.datas[da].

  10. Assert: due to validation, three values of type i32 are on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Pop the value i32.const s from the stack.

  13. Pop the value i32.const d from the stack.

  14. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  15. Pop the value ref from the stack.

  16. If ref is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref is an array reference.

  2. Let ref.array a be the reference value ref.

  3. Assert: due to validation, the array instance S.arrays[a] exists.

  4. Assert: due to validation, the field type ft has a defined bit width.

  5. Let z be the bit width of field type ft divided by eight.

  6. If d+n is larger than the length of S.arrays[a].fields, or the sum of s and n times z is larger than the length of datainst.data, then:

    1. Trap.

  7. If n=0, then:

    1. Return.

  8. Let b be the byte sequence datainst.data[s:z].

  9. Let t be the value type unpack(ft).

  10. Assert: due to validation, bytesft is defined.

  11. Let c be the constant for which bytesft(c) is b.

  12. Push the value ref.array a to the stack.

  13. Push the value i32.const d to the stack.

  14. Push the value t.const c to the stack.

  15. Execute the instruction array.set x.

  16. Push the value ref.array a to the stack.

  17. Push the value i32.const (d+1) to the stack.

  18. Push the value i32.const (s+z) to the stack.

  19. Push the value i32.const (n1) to the stack.

  20. Execute the instruction array.init_data x y.

 S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const n) (array.init_data x y)trap(ifd+n>|S.arrays[a].fields|(F.module.types[x]=array fts+n|ft|/8>|S.datas[F.module.dataaddrs[y]].data|))S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const 0) (array.init_data x y)ϵ(otherwise)S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const n+1) (array.init_data x y)(ref.array a) (i32.const d) (t.const c) (array.set x)(ref.array a) (i32.const d+1) (i32.const s+|ft|/8) (i32.const n) (array.init_data x y)(otherwise,ifF.module.types[x]=array ftt=unpack(ft)bytesft(c)=S.datas[F.module.dataaddrs[y]].data[s:|ft|/8]S;F;(ref.null t) (i32.const d) (i32.const s) (i32.const n) (array.init_data x y)trap

array.init_elem x y

  1. Let F be the current frame.

  2. Assert: due to validation, the defined type F.module.types[x] exists.

  3. Let deftype be the defined type F.module.types[x].

  4. Assert: due to validation, the expansion of deftype is an array type.

  5. Let array ft be the expanded array type deftype.

  6. Assert: due to validation, the element address F.module.elemaddrs[y] exists.

  7. Let ea be the element address F.module.elemaddrs[y].

  8. Assert: due to validation, the element instance S.elems[ea] exists.

  9. Let eleminst be the element instance S.elems[ea].

  10. Assert: due to validation, three values of type i32 are on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Pop the value i32.const s from the stack.

  13. Pop the value i32.const d from the stack.

  14. Assert: due to validation, a value of type (ref null x) is on the top of the stack.

  15. Pop the value ref from the stack.

  16. If ref is ref.null t, then:

  1. Trap.

  1. Assert: due to validation, ref is an array reference.

  2. Let ref.array a be the reference value ref.

  3. Assert: due to validation, the array instance S.arrays[a] exists.

  4. If d+n is larger than the length of S.arrays[a].fields, or s+n is larger than the length of eleminst.elem, then:

    1. Trap.

  5. If n=0, then:

    1. Return.

  6. Let ref be the reference value eleminst.elem[s].

  7. Push the value ref.array a to the stack.

  8. Push the value i32.const d to the stack.

  9. Push the value ref to the stack.

  10. Execute the instruction array.set x.

  11. Push the value ref.array a to the stack.

  12. Push the value i32.const (d+1) to the stack.

  13. Push the value i32.const (s+1) to the stack.

  14. Push the value i32.const (n1) to the stack.

  15. Execute the instruction array.init_elem x y.

 S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const n) (array.init_elem x y)trap(ifd+n>|S.arrays[a].fields|s+n>|S.elems[F.module.elemaddrs[y]].elem|)S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const 0) (array.init_elem x y)ϵ(otherwise)S;F;(ref.array a) (i32.const d) (i32.const s) (i32.const n+1) (array.init_elem x y)(ref.array a) (i32.const d) ref (array.set x)(ref.array a) (i32.const d+1) (i32.const s+1) (i32.const n) (array.init_elem x y)(otherwise,ifref=S.elems[F.module.elemaddrs[y]].elem[s])S;F;(ref.null t) (i32.const d) (i32.const s) (i32.const n) (array.init_elem x y)trap

any.convert_extern

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Push the reference value (ref.null any) to the stack.

  4. Else:

    1. Assert: due to validation, a ref is an external reference.

    2. Let ref.extern ref be the reference value ref.

    3. Push the reference value ref to the stack.

(ref.null ht) any.convert_extern(ref.null any)(ref.extern ref) any.convert_externref

extern.convert_any

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Push the reference value (ref.null extern) to the stack.

  4. Else:

    1. Let ref be the reference value (ref.extern ref).

    2. Push the reference value ref to the stack.

(ref.null ht) extern.convert_any(ref.null extern)ref extern.convert_any(ref.extern ref)(ifref(ref.null ht))

Vector Instructions

Vector instructions that operate bitwise are handled as integer operations of respective width.

opvN(i1,,ik)=iopN(i1,,ik)

Most other vector instructions are defined in terms of numeric operators that are applied lane-wise according to the given shape.

optxN(n1,,nk)=lanestxN1(opt(i1,,ik))(ifi1=lanestxN(n1)ik=lanestxN(nk)

Note

For example, the result of instruction i32x4.add applied to operands v1,v2 invokes addi32x4(v1,v2), which maps to lanesi32x41(addi32(i1,i2)), where i1 and i2 are sequences resulting from invoking lanesi32x4(v1) and lanesi32x4(v2) respectively.

v128.const c

  1. Push the value v128.const c to the stack.

Note

No formal reduction rule is required for this instruction, since const instructions coincide with values.

v128.vvunop

  1. Assert: due to validation, a value of value type v128 is on the top of the stack.

  2. Pop the value v128.const c1 from the stack.

  3. Let c be the result of computing vvunopv128(c1).

  4. Push the value v128.const c to the stack.

(v128.const c1) v128.vvunop(v128.const c)(ifc=vvunopv128(c1))

v128.vvbinop

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c2 from the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let c be the result of computing vvbinopv128(c1,c2).

  5. Push the value v128.const c to the stack.

(v128.const c1) (v128.const c2) v128.vvbinop(v128.const c)(ifc=vvbinopv128(c1,c2))

v128.vvternop

  1. Assert: due to validation, three values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c3 from the stack.

  3. Pop the value v128.const c2 from the stack.

  4. Pop the value v128.const c1 from the stack.

  5. Let c be the result of computing vvternopv128(c1,c2,c3).

  6. Push the value v128.const c to the stack.

(v128.const c1) (v128.const c2) (v128.const c3) v128.vvternop(v128.const c)(ifc=vvternopv128(c1,c2,c3))

v128.any_true

  1. Assert: due to validation, a value of value type v128 is on the top of the stack.

  2. Pop the value v128.const c1 from the stack.

  3. Let i be the result of computing ine128(c1,0).

  4. Push the value i32.const i onto the stack.

(v128.const c1) v128.any_true(i32.const i)(ifi=ine128(c1,0))

i8x16.swizzle

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c2 from the stack.

  3. Let i be the result of computing lanesi8x16(c2).

  4. Pop the value v128.const c1 from the stack.

  5. Let j be the result of computing lanesi8x16(c1).

  6. Let c be the concatenation of the two sequences j and 0240.

  7. Let c be the result of computing lanesi8x161(c[i[0]]c[i[15]]).

  8. Push the value v128.const c onto the stack.

(v128.const c1) (v128.const c2) i8x16.swizzle(v128.const c)(ifi=lanesi8x16(c2)c=lanesi8x16(c1) 0240c=lanesi8x161(c[i[0]]c[i[15]]))

i8x16.shuffle x

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Assert: due to validation, for all xi in x it holds that xi<32.

  3. Pop the value v128.const c2 from the stack.

  4. Let i2 be the result of computing lanesi8x16(c2).

  5. Pop the value v128.const c1 from the stack.

  6. Let i1 be the result of computing lanesi8x16(c1).

  7. Let i be the concatenation of the two sequences i1 and i2.

  8. Let c be the result of computing lanesi8x161(i[x[0]]i[x[15]]).

  9. Push the value v128.const c onto the stack.

(v128.const c1) (v128.const c2) (i8x16.shuffle x)(v128.const c)(ifi=lanesi8x16(c1) lanesi8x16(c2)c=lanesi8x161(i[x[0]]i[x[15]]))

shape.splat

  1. Let t be the type unpack(shape).

  2. Assert: due to validation, a value of value type t is on the top of the stack.

  3. Pop the value t.const c1 from the stack.

  4. Let N be the integer dim(shape).

  5. Let c be the result of computing lanesshape1(c1N).

  6. Push the value v128.const c to the stack.

(t.const c1) shape.splat(v128.const c)(ift=unpack(shape)c=lanesshape1(c1dim(shape)))

t1xN.extract_lane_sx? x

  1. Assert: due to validation, x<N.

  2. Assert: due to validation, a value of value type v128 is on the top of the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i be the result of computing lanest1xN(c1).

  5. Let t2 be the type unpack(t1xN).

  6. Let c2 be the result of computing extendt1,t2sx?(i[x]).

  7. Push the value t2.const c2 to the stack.

(v128.const c1) (t1xN.extract_lane x)(t2.const c2)(ift2=unpack(t1xN)c2=extendt1,t2sx?(lanest1xN(c1)[x]))

shape.replace_lane x

  1. Assert: due to validation, x<dim(shape).

  2. Let t2 be the type unpack(shape).

  3. Assert: due to validation, a value of value type t1 is on the top of the stack.

  4. Pop the value t2.const c2 from the stack.

  5. Assert: due to validation, a value of value type v128 is on the top of the stack.

  6. Pop the value v128.const c1 from the stack.

  7. Let i be the result of computing lanesshape(c1).

  8. Let c be the result of computing lanesshape1(iwith[x]=c2).

  9. Push v128.const c on the stack.

(v128.const c1) (t2.const c2) (shape.replace_lane x)(v128.const c)(ifi=lanesshape(c1)c=lanesshape1(iwith[x]=c2))

shape.vunop

  1. Assert: due to validation, a value of value type v128 is on the top of the stack.

  2. Pop the value v128.const c1 from the stack.

  3. Let c be the result of computing vunopshape(c1).

  4. Push the value v128.const c to the stack.

(v128.const c1) shape.vunop(v128.const c)(ifc=vunopshape(c1))

shape.vbinop

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c2 from the stack.

  3. Pop the value v128.const c1 from the stack.

  4. If vbinopshape(c1,c2) is defined:

    1. Let c be a possible result of computing vbinopshape(c1,c2).

    2. Push the value v128.const c to the stack.

  5. Else:

    1. Trap.

(v128.const c1) (v128.const c2) shape.vbinop(v128.const c)(ifcvbinopshape(c1,c2))(v128.const c1) (v128.const c2) shape.vbinoptrap(ifvbinopshape(c1,c2)={})

txN.vrelop

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c2 from the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i1 be the result of computing lanestxN(c1).

  5. Let i2 be the result of computing lanestxN(c2).

  6. Let i be the result of computing vrelopt(i1,i2).

  7. Let j be the result of computing extend1,|t|s(i).

  8. Let c be the result of computing lanestxN1(j).

  9. Push the value v128.const c to the stack.

(v128.const c1) (v128.const c2) txN.vrelop(v128.const c)(ifc=lanestxN1(extend1,|t|s(vrelopt(lanestxN(c1),lanestxN(c2)))))

txN.vishiftop

  1. Assert: due to validation, a value of value type i32 is on the top of the stack.

  2. Pop the value i32.const s from the stack.

  3. Assert: due to validation, a value of value type v128 is on the top of the stack.

  4. Pop the value v128.const c1 from the stack.

  5. Let i be the result of computing lanestxN(c1).

  6. Let j be the result of computing vishiftopt(i,sN).

  7. Let c be the result of computing lanestxN1(j).

  8. Push the value v128.const c to the stack.

(v128.const c1) (i32.const s) txN.vishiftop(v128.const c)(ifi=lanestxN(c1)c=lanestxN1(vishiftopt(i,sN)))

shape.all_true

  1. Assert: due to validation, a value of value type v128 is on the top of the stack.

  2. Pop the value v128.const c from the stack.

  3. Let i1 be the result of computing lanesshape(c).

  4. Let i be the result of computing bool((i10)).

  5. Push the value i32.const i onto the stack.

(v128.const c) shape.all_true(i32.const i)(ifi1=lanesshape(c)i=bool((i10)))

txN.bitmask

  1. Assert: due to validation, a value of value type v128 is on the top of the stack.

  2. Pop the value v128.const c from the stack.

  3. Let i1N be the result of computing lanestxN(c).

  4. Let B be the bit width |t| of value type t.

  5. Let i2N be the result of computing ilt_sB(i1N,0N).

  6. Let j be the concatenation of the two sequences i2N and 032N.

  7. Let i be the result of computing ibits321(j).

  8. Push the value i32.const i onto the stack.

(v128.const c) txN.bitmask(i32.const i)(ifi=ibits321(ilt_s|t|(lanestxN(c),0N)))

t2xN.narrow_t1xM_sx

  1. Assert: due to syntax, N=2M.

  2. Assert: due to validation, two values of value type v128 are on the top of the stack.

  3. Pop the value v128.const c2 from the stack.

  4. Let i2M be the result of computing lanest1xM(c2).

  5. Let d2M be the result of computing narrow|t1|,|t2|sx(i2M).

  6. Pop the value v128.const c1 from the stack.

  7. Let i1M be the result of computing lanest1xM(c1).

  8. Let d1M be the result of computing narrow|t1|,|t2|sx(i1M).

  9. Let jN be the concatenation of the two sequences d1M and d2M.

  10. Let c be the result of computing lanest2xN1(jN).

  11. Push the value v128.const c onto the stack.

(v128.const c1) (v128.const c2) t2xN.narrow_t1xM_sx(v128.const c)(ifd1M=narrow|t1|,|t2|sx(lanest1xM(c1))d2M=narrow|t1|,|t2|sx(lanest1xM(c2))c=lanest2xN1(d1M d2M))

t2xN.vcvtop_t1xM_sx

  1. Assert: due to syntax, N=M.

  2. Assert: due to validation, a value of value type v128 is on the top of the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i be the result of computing lanest1xM(c1).

  5. Let j be the result of computing vcvtop|t1|,|t2|sx(i).

  6. Let c be the result of computing lanest2xN1(j).

  7. Push the value v128.const c onto the stack.

(v128.const c1) t2xN.vcvtop_t1xM_sx(v128.const c)(ifc=lanest2xN1(vcvtop|t1|,|t2|sx(lanest1xM(c1))))

t2xN.vcvtop_half_t1xM_sx?

  1. Assert: due to syntax, N=M/2.

  2. Assert: due to validation, a value of value type v128 is on the top of the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i be the result of computing lanest1xM(c1).

  5. If half is low, then:

    1. Let j be the sequence i[0:N].

  6. Else:

    1. Let j be the sequence i[N:N].

  7. Let k be the result of computing vcvtop|t1|,|t2|sx?(j).

  8. Let c be the result of computing lanest2xN1(k).

  9. Push the value v128.const c onto the stack.

(v128.const c1) t2xN.vcvtop_half_t1xM_sx?(v128.const c)(ifc=lanest2xN1(vcvtop|t1|,|t2|sx?(lanest1xM(c1)[half(0,N):N])))

where:

low(x,y)=xhigh(x,y)=y

t2xN.vcvtop_t1xM_sx?_zero

  1. Assert: due to syntax, N=2M.

  2. Assert: due to validation, a value of value type v128 is on the top of the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i be the result of computing lanest1xM(c1).

  5. Let j be the result of computing vcvtop|t1|,|t2|sx?(i).

  6. Let k be the concatenation of the two sequences j and 0M.

  7. Let c be the result of computing lanest2xN1(k).

  8. Push the value v128.const c onto the stack.

(v128.const c1) t2xN.vcvtop_t1xM_sx?_zero(v128.const c)(ifc=lanest2xN1(vcvtop|t1|,|t2|sx?(lanest1xM(c1)) 0M))

i32x4.dot_i16x8_s

  1. Assert: due to validation, two values of value type v128 are on the top of the stack.

  2. Pop the value v128.const c2 from the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i1 be the result of computing lanesi16x8(c1).

  5. Let j1 be the result of computing extend16,32s(i1).

  6. Let i2 be the result of computing lanesi16x8(c2).

  7. Let j2 be the result of computing extend16,32s(i2).

  8. Let (k1 k2) be the result of computing imul32(j1,j2).

  9. Let k be the result of computing iadd32(k1,k2).

  10. Let c be the result of computing lanesi32x41(k).

  11. Push the value v128.const c onto the stack.

(v128.const c1) (v128.const c2) i32x4.dot_i16x8_s(v128.const c)(if(i1 i2)=imul32(extend16,32s(lanesi16x8(c1)),extend16,32s(lanesi16x8(c2)))j=iadd32(i1,i2)c=lanesi32x41(j))

t2xN.extmul_half_t1xM_sx

  1. Assert: due to syntax, N=M/2.

  2. Assert: due to validation, two values of value type v128 are on the top of the stack.

  3. Pop the value v128.const c2 from the stack.

  4. Pop the value v128.const c1 from the stack.

  5. Let i1 be the result of computing lanest1xM(c1).

  6. Let i2 be the result of computing lanest1xM(c2).

  7. If half is low, then:

    1. Let j1 be the sequence i1[0:N].

    2. Let j2 be the sequence i2[0:N].

  8. Else:

    1. Let j1 be the sequence i1[N:N].

    2. Let j2 be the sequence i2[N:N].

  9. Let k1 be the result of computing extend|t1|,|t2|sx(j1).

  10. Let k2 be the result of computing extend|t1|,|t2|sx(j2).

  11. Let k be the result of computing imul|t2|(k1,k2).

  12. Let c be the result of computing lanest2xN1(k).

  13. Push the value v128.const c onto the stack.

(v128.const c1) (v128.const c2) t2xN.extmul_half_t1xM_sx(v128.const c)(ifi=lanest1xM(c1)[half(0,N):N]j=lanest1xM(c2)[half(0,N):N]c=lanest2xN1(imul|t2|(extend|t1|,|t2|sx(i),extend|t1|,|t2|sx(j))))

where:

low(x,y)=xhigh(x,y)=y

t2xN.extadd_pairwise_t1xM_sx

  1. Assert: due to syntax, N=M/2.

  2. Assert: due to validation, a value of value type v128 is on the top of the stack.

  3. Pop the value v128.const c1 from the stack.

  4. Let i be the result of computing lanest1xM(c1).

  5. Let (j1 j2) be the result of computing extend|t1|,|t2|sx(i).

  6. Let k be the result of computing iadd|t2|(j1,j2).

  7. Let c be the result of computing lanest2xN1(k).

  8. Push the value v128.const c to the stack.

(v128.const c1) t2xN.extadd_pairwise_t1xM_sx(v128.const c)(if(i1 i2)=extend|t1|,|t2|sx(lanest1xM(c1))j=iadd|t2|(i1,i2)c=lanest2xN1(j))

Parametric Instructions

drop

  1. Assert: due to validation, a value is on the top of the stack.

  2. Pop the value val from the stack.

val  dropϵ

select (t)?

  1. Assert: due to validation, a value of value type i32 is on the top of the stack.

  2. Pop the value i32.const c from the stack.

  3. Assert: due to validation, two more values (of the same value type) are on the top of the stack.

  4. Pop the value val2 from the stack.

  5. Pop the value val1 from the stack.

  6. If c is not 0, then:

    1. Push the value val1 back to the stack.

  7. Else:

    1. Push the value val2 back to the stack.

val1 val2 (i32.const c) (select t?)val1(ifc0)val1 val2 (i32.const c) (select t?)val2(ifc=0)

Note

In future versions of WebAssembly, select may allow more than one value per choice.

Variable Instructions

local.get x

  1. Let F be the current frame.

  2. Assert: due to validation, F.locals[x] exists and is non-empty.

  3. Let val be the value F.locals[x].

  4. Push the value val to the stack.

F;(local.get x)F;val(ifF.locals[x]=val)

local.set x

  1. Let F be the current frame.

  2. Assert: due to validation, F.locals[x] exists.

  3. Assert: due to validation, a value is on the top of the stack.

  4. Pop the value val from the stack.

  5. Replace F.locals[x] with the value val.

F;val (local.set x)F;ϵ(ifF=Fwithlocals[x]=val)

local.tee x

  1. Assert: due to validation, a value is on the top of the stack.

  2. Pop the value val from the stack.

  3. Push the value val to the stack.

  4. Push the value val to the stack.

  5. Execute the instruction local.set x.

val (local.tee x)val val (local.set x)

global.get x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.globaladdrs[x] exists.

  3. Let a be the global address F.module.globaladdrs[x].

  4. Assert: due to validation, S.globals[a] exists.

  5. Let glob be the global instance S.globals[a].

  6. Let val be the value glob.value.

  7. Push the value val to the stack.

S;F;(global.get x)S;F;val(ifS.globals[F.module.globaladdrs[x]].value=val)

global.set x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.globaladdrs[x] exists.

  3. Let a be the global address F.module.globaladdrs[x].

  4. Assert: due to validation, S.globals[a] exists.

  5. Let glob be the global instance S.globals[a].

  6. Assert: due to validation, a value is on the top of the stack.

  7. Pop the value val from the stack.

  8. Replace glob.value with the value val.

S;F;val (global.set x)S;F;ϵ(ifS=Swithglobals[F.module.globaladdrs[x]].value=val)

Note

Validation ensures that the global is, in fact, marked as mutable.

Table Instructions

table.get x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let a be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[a] exists.

  5. Let tab be the table instance S.tables[a].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. If i is not smaller than the length of tab.elem, then:

    1. Trap.

  9. Let val be the value tab.elem[i].

  10. Push the value val to the stack.

 S;F;(i32.const i) (table.get x)S;F;val(ifS.tables[F.module.tableaddrs[x]].elem[i]=val)S;F;(i32.const i) (table.get x)S;F;trap(otherwise)

table.set x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let a be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[a] exists.

  5. Let tab be the table instance S.tables[a].

  6. Assert: due to validation, a reference value is on the top of the stack.

  7. Pop the value val from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. If i is not smaller than the length of tab.elem, then:

    1. Trap.

  11. Replace the element tab.elem[i] with val.

 S;F;(i32.const i) val (table.set x)S;F;ϵ(ifS=Swithtables[F.module.tableaddrs[x]].elem[i]=val)S;F;(i32.const i) val (table.set x)S;F;trap(otherwise)

table.size x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let a be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[a] exists.

  5. Let tab be the table instance S.tables[a].

  6. Let sz be the length of tab.elem.

  7. Push the value i32.const sz to the stack.

S;F;(table.size x)S;F;(i32.const sz)(if|S.tables[F.module.tableaddrs[x]].elem|=sz)

table.grow x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let a be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[a] exists.

  5. Let tab be the table instance S.tables[a].

  6. Let sz be the length of S.tables[a].

  7. Assert: due to validation, a value of value type i32 is on the top of the stack.

  8. Pop the value i32.const n from the stack.

  9. Assert: due to validation, a reference value is on the top of the stack.

  10. Pop the value val from the stack.

  11. Let err be the i32 value 2321, for which signed32(err) is 1.

  12. Either:

  1. If growing tab by n entries with initialization value val succeeds, then:

    1. Push the value i32.const sz to the stack.

  2. Else:

    1. Push the value i32.const err to the stack.

  1. Or:

  1. push the value i32.const err to the stack.

 S;F;val (i32.const n) (table.grow x)S;F;(i32.const sz)(ifF.module.tableaddrs[x]=asz=|S.tables[a].elem|S=Swithtables[a]=growtable(S.tables[a],n,val))S;F;val (i32.const n) (table.grow x)S;F;(i32.const signed321(1))

Note

The table.grow instruction is non-deterministic. It may either succeed, returning the old table size sz, or fail, returning 1. Failure must occur if the referenced table instance has a maximum size defined that would be exceeded. However, failure can occur in other cases as well. In practice, the choice depends on the resources available to the embedder.

table.fill x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let ta be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[ta] exists.

  5. Let tab be the table instance S.tables[ta].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const n from the stack.

  8. Assert: due to validation, a reference value is on the top of the stack.

  9. Pop the value val from the stack.

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const i from the stack.

  12. If i+n is larger than the length of tab.elem, then:

    1. Trap.

  1. If n is 0, then:

    1. Return.

  2. Push the value i32.const i to the stack.

  3. Push the value val to the stack.

  4. Execute the instruction table.set x.

  5. Push the value i32.const (i+1) to the stack.

  6. Push the value val to the stack.

  7. Push the value i32.const (n1) to the stack.

  8. Execute the instruction table.fill x.

S;F;(i32.const i) val (i32.const n) (table.fill x)S;F;trap(ifi+n>|S.tables[F.module.tableaddrs[x]].elem|)S;F;(i32.const i) val (i32.const 0) (table.fill x)S;F;ϵ(otherwise)S;F;(i32.const i) val (i32.const n+1) (table.fill x)S;F;(i32.const i) val (table.set x)(i32.const i+1) val (i32.const n) (table.fill x)(otherwise)

table.copy x y

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let tax be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[tax] exists.

  5. Let tabx be the table instance S.tables[tax].

  6. Assert: due to validation, F.module.tableaddrs[y] exists.

  7. Let tay be the table address F.module.tableaddrs[y].

  8. Assert: due to validation, S.tables[tay] exists.

  9. Let taby be the table instance S.tables[tay].

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Assert: due to validation, a value of value type i32 is on the top of the stack.

  13. Pop the value i32.const s from the stack.

  14. Assert: due to validation, a value of value type i32 is on the top of the stack.

  15. Pop the value i32.const d from the stack.

  16. If s+n is larger than the length of taby.elem or d+n is larger than the length of tabx.elem, then:

    1. Trap.

  17. If n=0, then:

  1. Return.

  1. If ds, then:

  1. Push the value i32.const d to the stack.

  2. Push the value i32.const s to the stack.

  3. Execute the instruction table.get y.

  4. Execute the instruction table.set x.

  5. Assert: due to the earlier check against the table size, d+1<232.

  6. Push the value i32.const (d+1) to the stack.

  7. Assert: due to the earlier check against the table size, s+1<232.

  8. Push the value i32.const (s+1) to the stack.

  1. Else:

  1. Assert: due to the earlier check against the table size, d+n1<232.

  2. Push the value i32.const (d+n1) to the stack.

  3. Assert: due to the earlier check against the table size, s+n1<232.

  4. Push the value i32.const (s+n1) to the stack.

  1. Execute the instruction table.get y.

  1. Execute the instruction table.set x.

  2. Push the value i32.const d to the stack.

  3. Push the value i32.const s to the stack.

  1. Push the value i32.const (n1) to the stack.

  2. Execute the instruction table.copy x y.

 S;F;(i32.const d) (i32.const s) (i32.const n) (table.copy x y)S;F;trap(ifs+n>|S.tables[F.module.tableaddrs[y]].elem|d+n>|S.tables[F.module.tableaddrs[x]].elem|)S;F;(i32.const d) (i32.const s) (i32.const 0) (table.copy x y)S;F;ϵ(otherwise)S;F;(i32.const d) (i32.const s) (i32.const n+1) (table.copy x y)S;F;(i32.const d) (i32.const s) (table.get y) (table.set x)(i32.const d+1) (i32.const s+1) (i32.const n) (table.copy x y)(otherwise,ifds)S;F;(i32.const d) (i32.const s) (i32.const n+1) (table.copy x y)S;F;(i32.const d+n) (i32.const s+n) (table.get y) (table.set x)(i32.const d) (i32.const s) (i32.const n) (table.copy x y)(otherwise,ifd>s)

table.init x y

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let ta be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[ta] exists.

  5. Let tab be the table instance S.tables[ta].

  6. Assert: due to validation, F.module.elemaddrs[y] exists.

  7. Let ea be the element address F.module.elemaddrs[y].

  8. Assert: due to validation, S.elems[ea] exists.

  9. Let elem be the element instance S.elems[ea].

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Assert: due to validation, a value of value type i32 is on the top of the stack.

  13. Pop the value i32.const s from the stack.

  14. Assert: due to validation, a value of value type i32 is on the top of the stack.

  15. Pop the value i32.const d from the stack.

  16. If s+n is larger than the length of elem.elem or d+n is larger than the length of tab.elem, then:

    1. Trap.

  17. If n=0, then:

    1. Return.

  18. Let val be the reference value elem.elem[s].

  19. Push the value i32.const d to the stack.

  20. Push the value val to the stack.

  21. Execute the instruction table.set x.

  22. Assert: due to the earlier check against the table size, d+1<232.

  23. Push the value i32.const (d+1) to the stack.

  24. Assert: due to the earlier check against the segment size, s+1<232.

  25. Push the value i32.const (s+1) to the stack.

  26. Push the value i32.const (n1) to the stack.

  27. Execute the instruction table.init x y.

 S;F;(i32.const d) (i32.const s) (i32.const n) (table.init x y)S;F;trap(ifs+n>|S.elems[F.module.elemaddrs[y]].elem|d+n>|S.tables[F.module.tableaddrs[x]].elem|)S;F;(i32.const d) (i32.const s) (i32.const 0) (table.init x y)S;F;ϵ(otherwise)S;F;(i32.const d) (i32.const s) (i32.const n+1) (table.init x y)S;F;(i32.const d) val (table.set x)(i32.const d+1) (i32.const s+1) (i32.const n) (table.init x y)(otherwise,ifval=S.elems[F.module.elemaddrs[y]].elem[s])

elem.drop x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.elemaddrs[x] exists.

  3. Let a be the element address F.module.elemaddrs[x].

  4. Assert: due to validation, S.elems[a] exists.

  5. Replace S.elems[a].elem with ϵ.

 S;F;(elem.drop x)S;F;ϵ(ifS=Swithelems[F.module.elemaddrs[x]].elem=ϵ)

Memory Instructions

Note

The alignment memarg.align in load and store instructions does not affect the semantics. It is an indication that the offset ea at which the memory is accessed is intended to satisfy the property eamod2memarg.align=0. A WebAssembly implementation can use this hint to optimize for the intended use. Unaligned access violating that property is still allowed and must succeed regardless of the annotation. However, it may be substantially slower on some hardware.

t.load memarg and t.loadN_sx memarg

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. Let ea be the integer i+memarg.offset.

  9. If N is not part of the instruction, then:

    1. Let N be the bit width |t| of number type t.

  10. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  11. Let b be the byte sequence mem.data[ea:N/8].

  12. If N and sx are part of the instruction, then:

    1. Let n be the integer for which bytesiN(n)=b.

    2. Let c be the result of computing extendN,|t|sx(n).

  13. Else:

    1. Let c be the constant for which bytest(c)=b.

  14. Push the value t.const c to the stack.

 S;F;(i32.const i) (t.load memarg)S;F;(t.const c)(ifea=i+memarg.offsetea+|t|/8|S.mems[F.module.memaddrs[0]].data|bytest(c)=S.mems[F.module.memaddrs[0]].data[ea:|t|/8])S;F;(i32.const i) (t.loadN_sx memarg)S;F;(t.const extendN,|t|sx(n))(ifea=i+memarg.offsetea+N/8|S.mems[F.module.memaddrs[0]].data|bytesiN(n)=S.mems[F.module.memaddrs[0]].data[ea:N/8])S;F;(i32.const i) (t.load(N_sx)? memarg)S;F;trap(otherwise)

v128.loadMxN_sx memarg

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. Let ea be the integer i+memarg.offset.

  9. If ea+MN/8 is larger than the length of mem.data, then:

    1. Trap.

  10. Let b be the byte sequence mem.data[ea:MN/8].

  11. Let mk be the integer for which bytesiM(mk)=b[kM/8:M/8].

  12. Let W be the integer M2.

  13. Let nk be the result of computing extendM,Wsx(mk).

  14. Let c be the result of computing lanesiWxN1(n0nN1).

  15. Push the value v128.const c to the stack.

 S;F;(i32.const i) (v128.loadMxN_sx memarg)S;F;(v128.const c)(ifea=i+memarg.offsetea+MN/8|S.mems[F.module.memaddrs[0]].data|bytesiM(mk)=S.mems[F.module.memaddrs[0]].data[ea+kM/8:M/8]W=M2c=lanesiWxN1(extendM,Wsx(m0)extendM,Wsx(mN1)))S;F;(i32.const i) (v128.loadMxN_sx memarg)S;F;trap(otherwise)

v128.loadN_splat memarg

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. Let ea be the integer i+memarg.offset.

  9. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  10. Let b be the byte sequence mem.data[ea:N/8].

  11. Let n be the integer for which bytesiN(n)=b.

  12. Let L be the integer 128/N.

  13. Let c be the result of computing lanesiNxL1(nL).

  14. Push the value v128.const c to the stack.

 S;F;(i32.const i) (v128.loadN_splat memarg)S;F;(v128.const c)(ifea=i+memarg.offsetea+N/8|S.mems[F.module.memaddrs[0]].data|bytesiN(n)=S.mems[F.module.memaddrs[0]].data[ea:N/8]c=lanesiNxL1(nL))S;F;(i32.const i) (v128.loadN_splat memarg)S;F;trap(otherwise)

v128.loadN_zero memarg

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const i from the stack.

  8. Let ea be the integer i+memarg.offset.

  9. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  10. Let b be the byte sequence mem.data[ea:N/8].

  11. Let n be the integer for which bytesiN(n)=b.

  12. Let c be the result of computing extendN,128u(n).

  13. Push the value v128.const c to the stack.

 S;F;(i32.const i) (v128.loadN_zero memarg)S;F;(v128.const c)(ifea=i+memarg.offsetea+N/8|S.mems[F.module.memaddrs[0]].data|bytesiN(n)=S.mems[F.module.memaddrs[0]].data[ea:N/8]c=extendN,128u(n))S;F;(i32.const i) (v128.loadN_zero memarg)S;F;trap(otherwise)

v128.loadN_lane memarg x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type v128 is on the top of the stack.

  7. Pop the value v128.const v from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. Let ea be the integer i+memarg.offset.

  11. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  12. Let b be the byte sequence mem.data[ea:N/8].

  13. Let r be the constant for which bytesiN(r)=b.

  14. Let L be 128/N.

  15. Let j be the result of computing lanesiNxL(v).

  16. Let c be the result of computing lanesiNxL1(jwith[x]=r).

  17. Push the value v128.const c to the stack.

 S;F;(i32.const i) (v128.const v) (v128.loadN_lane memarg x)S;F;(v128.const c)(ifea=i+memarg.offsetea+N/8|S.mems[F.module.memaddrs[0]].data|bytesiN(r)=S.mems[F.module.memaddrs[0]].data[ea:N/8]L=128/Nc=lanesiNxL1(lanesiNxL(v)with[x]=r))S;F;(i32.const i) (v128.const v) (v128.loadN_lane memarg x)S;F;trap(otherwise)

t.store memarg and t.storeN memarg

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type t is on the top of the stack.

  7. Pop the value t.const c from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. Let ea be the integer i+memarg.offset.

  11. If N is not part of the instruction, then:

    1. Let N be the bit width |t| of number type t.

  12. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  13. If N is part of the instruction, then:

    1. Let n be the result of computing wrap|t|,N(c).

    2. Let b be the byte sequence bytesiN(n).

  14. Else:

    1. Let b be the byte sequence bytest(c).

  15. Replace the bytes mem.data[ea:N/8] with b.

 S;F;(i32.const i) (t.const c) (t.store memarg)S;F;ϵ(ifea=i+memarg.offsetea+|t|/8|S.mems[F.module.memaddrs[0]].data|S=Swithmems[F.module.memaddrs[0]].data[ea:|t|/8]=bytest(c))S;F;(i32.const i) (t.const c) (t.storeN memarg)S;F;ϵ(ifea=i+memarg.offsetea+N/8|S.mems[F.module.memaddrs[0]].data|S=Swithmems[F.module.memaddrs[0]].data[ea:N/8]=bytesiN(wrap|t|,N(c)))S;F;(i32.const i) (t.const c) (t.storeN? memarg)S;F;trap(otherwise)

v128.storeN_lane memarg x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Assert: due to validation, a value of value type v128 is on the top of the stack.

  7. Pop the value v128.const c from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. Let ea be the integer i+memarg.offset.

  11. If ea+N/8 is larger than the length of mem.data, then:

    1. Trap.

  12. Let L be 128/N.

  13. Let j be the result of computing lanesiNxL(c).

  14. Let b be the result of computing bytesiN(j[x]).

  15. Replace the bytes mem.data[ea:N/8] with b.

 S;F;(i32.const i) (v128.const c) (v128.storeN_lane memarg x)S;F;ϵ(ifea=i+memarg.offsetea+N|S.mems[F.module.memaddrs[0]].data|L=128/NS=Swithmems[F.module.memaddrs[0]].data[ea:N/8]=bytesiN(lanesiNxL(c)[x]))S;F;(i32.const i) (v128.const c) (v128.storeN_lane memarg x)S;F;trap(otherwise)

memory.size

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Let sz be the length of mem.data divided by the page size.

  7. Push the value i32.const sz to the stack.

S;F;memory.sizeS;F;(i32.const sz)(if|S.mems[F.module.memaddrs[0]].data|=sz64Ki)

memory.grow

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let a be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[a] exists.

  5. Let mem be the memory instance S.mems[a].

  6. Let sz be the length of S.mems[a] divided by the page size.

  7. Assert: due to validation, a value of value type i32 is on the top of the stack.

  8. Pop the value i32.const n from the stack.

  9. Let err be the i32 value 2321, for which signed32(err) is 1.

  10. Either:

  1. If growing mem by n pages succeeds, then:

    1. Push the value i32.const sz to the stack.

  2. Else:

    1. Push the value i32.const err to the stack.

  1. Or:

  1. Push the value i32.const err to the stack.

 S;F;(i32.const n) memory.growS;F;(i32.const sz)(ifF.module.memaddrs[0]=asz=|S.mems[a].data|/64KiS=Swithmems[a]=growmem(S.mems[a],n))S;F;(i32.const n) memory.growS;F;(i32.const signed321(1))

Note

The memory.grow instruction is non-deterministic. It may either succeed, returning the old memory size sz, or fail, returning 1. Failure must occur if the referenced memory instance has a maximum size defined that would be exceeded. However, failure can occur in other cases as well. In practice, the choice depends on the resources available to the embedder.

memory.fill

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let ma be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[ma] exists.

  5. Let mem be the memory instance S.mems[ma].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const n from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value val from the stack.

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const d from the stack.

  12. If d+n is larger than the length of mem.data, then:

    1. Trap.

  13. If n=0, then:

    1. Return.

  14. Push the value i32.const d to the stack.

  15. Push the value val to the stack.

  16. Execute the instruction i32.store8 {offset 0,align 0}.

  17. Assert: due to the earlier check against the memory size, d+1<232.

  18. Push the value i32.const (d+1) to the stack.

  19. Push the value val to the stack.

  20. Push the value i32.const (n1) to the stack.

  21. Execute the instruction memory.fill.

 S;F;(i32.const d) val (i32.const n) memory.fillS;F;trap(ifd+n>|S.mems[F.module.memaddrs[0]].data|)S;F;(i32.const d) val (i32.const 0) memory.fillS;F;ϵ(otherwise)S;F;(i32.const d) val (i32.const n+1) memory.fillS;F;(i32.const d) val (i32.store8 {offset 0,align 0})(i32.const d+1) val (i32.const n) memory.fill(otherwise)

memory.copy

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let ma be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[ma] exists.

  5. Let mem be the memory instance S.mems[ma].

  6. Assert: due to validation, a value of value type i32 is on the top of the stack.

  7. Pop the value i32.const n from the stack.

  8. Assert: due to validation, a value of value type i32 is on the top of the stack.

  9. Pop the value i32.const s from the stack.

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const d from the stack.

  12. If s+n is larger than the length of mem.data or d+n is larger than the length of mem.data, then:

    1. Trap.

  13. If n=0, then:

  1. Return.

  1. If ds, then:

  1. Push the value i32.const d to the stack.

  2. Push the value i32.const s to the stack.

  3. Execute the instruction i32.load8_u {offset 0,align 0}.

  4. Execute the instruction i32.store8 {offset 0,align 0}.

  5. Assert: due to the earlier check against the memory size, d+1<232.

  6. Push the value i32.const (d+1) to the stack.

  7. Assert: due to the earlier check against the memory size, s+1<232.

  8. Push the value i32.const (s+1) to the stack.

  1. Else:

  1. Assert: due to the earlier check against the memory size, d+n1<232.

  2. Push the value i32.const (d+n1) to the stack.

  3. Assert: due to the earlier check against the memory size, s+n1<232.

  4. Push the value i32.const (s+n1) to the stack.

  5. Execute the instruction i32.load8_u {offset 0,align 0}.

  6. Execute the instruction i32.store8 {offset 0,align 0}.

  7. Push the value i32.const d to the stack.

  8. Push the value i32.const s to the stack.

  1. Push the value i32.const (n1) to the stack.

  2. Execute the instruction memory.copy.

 S;F;(i32.const d) (i32.const s) (i32.const n) memory.copyS;F;trap(ifs+n>|S.mems[F.module.memaddrs[0]].data|d+n>|S.mems[F.module.memaddrs[0]].data|)S;F;(i32.const d) (i32.const s) (i32.const 0) memory.copyS;F;ϵ(otherwise)S;F;(i32.const d) (i32.const s) (i32.const n+1) memory.copyS;F;(i32.const d)(i32.const s) (i32.load8_u {offset 0,align 0})(i32.store8 {offset 0,align 0})(i32.const d+1) (i32.const s+1) (i32.const n) memory.copy(otherwise,ifds)S;F;(i32.const d) (i32.const s) (i32.const n+1) memory.copyS;F;(i32.const d+n)(i32.const s+n) (i32.load8_u {offset 0,align 0})(i32.store8 {offset 0,align 0})(i32.const d) (i32.const s) (i32.const n) memory.copy(otherwise,ifd>s)

memory.init x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.memaddrs[0] exists.

  3. Let ma be the memory address F.module.memaddrs[0].

  4. Assert: due to validation, S.mems[ma] exists.

  5. Let mem be the memory instance S.mems[ma].

  6. Assert: due to validation, F.module.dataaddrs[x] exists.

  7. Let da be the data address F.module.dataaddrs[x].

  8. Assert: due to validation, S.datas[da] exists.

  9. Let data be the data instance S.datas[da].

  10. Assert: due to validation, a value of value type i32 is on the top of the stack.

  11. Pop the value i32.const n from the stack.

  12. Assert: due to validation, a value of value type i32 is on the top of the stack.

  13. Pop the value i32.const s from the stack.

  14. Assert: due to validation, a value of value type i32 is on the top of the stack.

  15. Pop the value i32.const d from the stack.

  16. If s+n is larger than the length of data.data or d+n is larger than the length of mem.data, then:

    1. Trap.

  17. If n=0, then:

    1. Return.

  18. Let b be the byte data.data[s].

  19. Push the value i32.const d to the stack.

  20. Push the value i32.const b to the stack.

  21. Execute the instruction i32.store8 {offset 0,align 0}.

  22. Assert: due to the earlier check against the memory size, d+1<232.

  23. Push the value i32.const (d+1) to the stack.

  24. Assert: due to the earlier check against the memory size, s+1<232.

  25. Push the value i32.const (s+1) to the stack.

  26. Push the value i32.const (n1) to the stack.

  27. Execute the instruction memory.init x.

 S;F;(i32.const d) (i32.const s) (i32.const n) (memory.init x)S;F;trap(ifs+n>|S.datas[F.module.dataaddrs[x]].data|d+n>|S.mems[F.module.memaddrs[0]].data|)S;F;(i32.const d) (i32.const s) (i32.const 0) (memory.init x)S;F;ϵ(otherwise)S;F;(i32.const d) (i32.const s) (i32.const n+1) (memory.init x)S;F;(i32.const d) (i32.const b) (i32.store8 {offset 0,align 0})(i32.const d+1) (i32.const s+1) (i32.const n) (memory.init x)(otherwise,ifb=S.datas[F.module.dataaddrs[x]].data[s])

data.drop x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.dataaddrs[x] exists.

  3. Let a be the data address F.module.dataaddrs[x].

  4. Assert: due to validation, S.datas[a] exists.

  5. Replace S.datas[a] with the data instance {data ϵ}.

 S;F;(data.drop x)S;F;ϵ(ifS=Swithdatas[F.module.dataaddrs[x]]={data ϵ})

Control Instructions

nop

  1. Do nothing.

nopϵ

unreachable

  1. Trap.

unreachabletrap

block blocktype instr end

  1. Let F be the current frame.

  2. Assert: due to validation, instrtypeS;F(blocktype) is defined.

  3. Let [t1m][t2n] be the instruction type instrtypeS;F(blocktype).

  4. Let L be the label whose arity is n and whose continuation is the end of the block.

  5. Assert: due to validation, there are at least m values on the top of the stack.

  6. Pop the values valm from the stack.

  7. Enter the block valm instr with label L.

 S;F;valm block bt instr endS;F;labeln{ϵ} valm instr end(ifinstrtypeS;F(bt)=[t1m][t2n])

loop blocktype instr end

  1. Let F be the current frame.

  2. Assert: due to validation, instrtypeS;F(blocktype) is defined.

  3. Let [t1m][t2n] be the instruction type instrtypeS;F(blocktype).

  4. Let L be the label whose arity is m and whose continuation is the start of the loop.

  5. Assert: due to validation, there are at least m values on the top of the stack.

  6. Pop the values valm from the stack.

  7. Enter the block valm instr with label L.

 S;F;valm loop bt instr endS;F;labelm{loop bt instr end} valm instr end(ifinstrtypeS;F(bt)=[t1m][t2n])

if blocktype instr1 else instr2 end

  1. Assert: due to validation, a value of value type i32 is on the top of the stack.

  2. Pop the value i32.const c from the stack.

  3. If c is non-zero, then:

    1. Execute the block instruction block blocktype instr1 end.

  4. Else:

    1. Execute the block instruction block blocktype instr2 end.

 (i32.const c) if bt instr1 else instr2 endblock bt instr1 end(ifc0)(i32.const c) if bt instr1 else instr2 endblock bt instr2 end(ifc=0)

br l

  1. Assert: due to validation, the stack contains at least l+1 labels.

  2. Let L be the l-th label appearing on the stack, starting from the top and counting from zero.

  3. Let n be the arity of L.

  4. Assert: due to validation, there are at least n values on the top of the stack.

  5. Pop the values valn from the stack.

  6. Repeat l+1 times:

    1. While the top of the stack is a value, do:

      1. Pop the value from the stack.

    2. Assert: due to validation, the top of the stack now is a label.

    3. Pop the label from the stack.

  7. Push the values valn to the stack.

  8. Jump to the continuation of L.

 labeln{instr} Bl[valn (br l)] endvaln instr

br_if l

  1. Assert: due to validation, a value of value type i32 is on the top of the stack.

  2. Pop the value i32.const c from the stack.

  3. If c is non-zero, then:

    1. Execute the instruction br l.

  4. Else:

    1. Do nothing.

 (i32.const c) (br_if l)(br l)(ifc0)(i32.const c) (br_if l)ϵ(ifc=0)

br_table l lN

  1. Assert: due to validation, a value of value type i32 is on the top of the stack.

  2. Pop the value i32.const i from the stack.

  3. If i is smaller than the length of l, then:

    1. Let li be the label l[i].

    2. Execute the instruction br li.

  4. Else:

    1. Execute the instruction br lN.

 (i32.const i) (br_table l lN)(br li)(ifl[i]=li)(i32.const i) (br_table l lN)(br lN)(if|l|i)

br_on_null l

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Execute the instruction (br l).

  4. Else:

    1. Push the value ref back to the stack.

ref (br_on_null l)(br l)(ifref=ref.null ht)ref (br_on_null l)ref(otherwise)

br_on_non_null l

  1. Assert: due to validation, a reference value is on the top of the stack.

  2. Pop the value ref from the stack.

  3. If ref is ref.null ht, then:

    1. Do nothing.

  4. Else:

    1. Push the value ref back to the stack.

    2. Execute the instruction (br l).

ref (br_on_non_null l)ϵ(ifref=ref.null ht)ref (br_on_non_null l)ref (br l)(otherwise)

br_on_cast l rt1 rt2

  1. Let F be the current frame.

  2. Let rt2 be the reference type closF.module(rt2).

  3. Assert: due to validation, rt2 is closed.

  4. Assert: due to validation, a reference value is on the top of the stack.

  5. Pop the value ref from the stack.

  6. Assert: due to validation, the reference value is valid with some reference type.

  7. Let rt be the reference type of ref.

  8. Push the value ref back to the stack.

  9. If the reference type rt matches rt2, then:

    1. Execute the instruction (br l).

S;F;ref (br_on_cast l rt1 rt2)ref (br l)(ifSref:rtrtclosF.module(rt2))S;F;ref (br_on_cast l rt1 rt2)ref(otherwise)

br_on_cast_fail l rt1 rt2

  1. Let F be the current frame.

  2. Let rt2 be the reference type closF.module(rt2).

  3. Assert: due to validation, rt2 is closed.

  4. Assert: due to validation, a reference value is on the top of the stack.

  5. Pop the value ref from the stack.

  6. Assert: due to validation, the reference value is valid with some reference type.

  7. Let rt be the reference type of ref.

  8. Push the value ref back to the stack.

  9. If the reference type rt does not match rt2, then:

    1. Execute the instruction (br l).

S;F;ref (br_on_cast_fail l rt1 rt2)ref(ifSref:rtrtclosF.module(rt2))S;F;ref (br_on_cast_fail l rt1 rt2)ref (br l)(otherwise)

return

  1. Let F be the current frame.

  2. Let n be the arity of F.

  3. Assert: due to validation, there are at least n values on the top of the stack.

  4. Pop the results valn from the stack.

  5. Assert: due to validation, the stack contains at least one frame.

  6. While the top of the stack is not a frame, do:

    1. Pop the top element from the stack.

  7. Assert: the top of the stack is the frame F.

  8. Pop the frame from the stack.

  9. Push valn to the stack.

  10. Jump to the instruction after the original call that pushed the frame.

 framen{F} B[valn return] endvaln

call x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.funcaddrs[x] exists.

  3. Let a be the function address F.module.funcaddrs[x].

  4. Invoke the function instance at address a.

F;(call x)F;(invoke a)(ifF.module.funcaddrs[x]=a)

call_ref x

  1. Assert: due to validation, a null or function reference is on the top of the stack.

  2. Pop the reference value r from the stack.

  3. If r is ref.null ht, then:

    1. Trap.

  4. Assert: due to validation, r is a function reference.

  5. Let ref.func a be the reference r.

  6. Invoke the function instance at address a.

F;(ref.func a) (call_ref x)F;(invoke a)F;(ref.null ht) (call_ref x)F;trap

call_indirect x y

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let ta be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[ta] exists.

  5. Let tab be the table instance S.tables[ta].

  6. Assert: due to validation, F.module.types[y] is defined.

  7. Let dtexpect be the defined type F.module.types[y].

  8. Assert: due to validation, a value with value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. If i is not smaller than the length of tab.elem, then:

    1. Trap.

  11. Let r be the reference tab.elem[i].

  12. If r is ref.null ht, then:

    1. Trap.

  13. Assert: due to validation of table mutation, r is a function reference.

  14. Let ref.func a be the function reference r.

  15. Assert: due to validation of table mutation, S.funcs[a] exists.

  16. Let f be the function instance S.funcs[a].

  17. Let dtactual be the defined type f.type.

  18. If dtactual does not match dtexpect, then:

    1. Trap.

  19. Invoke the function instance at address a.

 S;F;(i32.const i) (call_indirect x y)S;F;(invoke a)(ifS.tables[F.module.tableaddrs[x]].elem[i]=ref.func aS.funcs[a]=fSf.typeF.module.types[y])S;F;(i32.const i) (call_indirect x y)S;F;trap(otherwise)

return_call x

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.funcaddrs[x] exists.

  3. Let a be the function address F.module.funcaddrs[x].

  4. Tail-invoke the function instance at address a.

(return_call x)(return_invoke a)(if(call x)(invoke a))

return_call_ref x

  1. Assert: due to validation, a function reference is on the top of the stack.

  2. Pop the reference value r from the stack.

  3. If r is ref.null ht, then:

    1. Trap.

  4. Assert: due to validation, r is a function reference.

  5. Let ref.func a be the reference r.

  6. Tail-invoke the function instance at address a.

val (return_call_ref x)(return_invoke a)(ifval (call_ref x)(invoke a))val (return_call_ref x)trap(ifval (call_ref x)trap)

return_call_indirect x y

  1. Let F be the current frame.

  2. Assert: due to validation, F.module.tableaddrs[x] exists.

  3. Let ta be the table address F.module.tableaddrs[x].

  4. Assert: due to validation, S.tables[ta] exists.

  5. Let tab be the table instance S.tables[ta].

  6. Assert: due to validation, F.module.types[y] is defined.

  7. Let dtexpect be the defined type F.module.types[y].

  8. Assert: due to validation, a value with value type i32 is on the top of the stack.

  9. Pop the value i32.const i from the stack.

  10. If i is not smaller than the length of tab.elem, then:

    1. Trap.

  11. If tab.elem[i] is uninitialized, then:

    1. Trap.

  12. Let a be the function address tab.elem[i].

  13. Assert: due to validation, S.funcs[a] exists.

  14. Let f be the function instance S.funcs[a].

  15. Let dtactual be the defined type f.type.

  16. If dtactual does not match dtexpect, then:

    1. Trap.

  17. Tail-invoke the function instance at address a.

val (return_call_indirect x y)(return_invoke a)(ifval (call_indirect x y)(invoke a))val (return_call_indirect x y)trap(ifval (call_indirect x y)trap)

Blocks

The following auxiliary rules define the semantics of executing an instruction sequence that forms a block.

Entering instr with label L

  1. Push L to the stack.

  2. Jump to the start of the instruction sequence instr.

Note

No formal reduction rule is needed for entering an instruction sequence, because the label L is embedded in the administrative instruction that structured control instructions reduce to directly.

Exiting instr with label L

When the end of a block is reached without a jump or trap aborting it, then the following steps are performed.

  1. Pop all values val from the top of the stack.

  2. Assert: due to validation, the label L is now on the top of the stack.

  3. Pop the label from the stack.

  4. Push val back to the stack.

  5. Jump to the position after the end of the structured control instruction associated with the label L.

 labeln{instr} val endval

Note

This semantics also applies to the instruction sequence contained in a loop instruction. Therefore, execution of a loop falls off the end, unless a backwards branch is performed explicitly.

Function Calls

The following auxiliary rules define the semantics of invoking a function instance through one of the call instructions and returning from it.

Invocation of function address a

  1. Assert: due to validation, S.funcs[a] exists.

  2. Let f be the function instance, S.funcs[a].

  3. Let func [t1n][t2m] be the composite type expand(f.type).

  4. Let local be the list of locals f.code.locals.

  5. Let instr end be the expression f.code.body.

  6. Assert: due to validation, n values are on the top of the stack.

  7. Pop the values valn from the stack.

  8. Let F be the frame {module f.module,locals valn (defaultt)}.

  9. Push the activation of F with arity m to the stack.

  10. Let L be the label whose arity is m and whose continuation is the end of the function.

  11. Enter the instruction sequence instr with label L.

 S;valn (invoke a)S;framem{F} labelm{} instr end end(ifS.funcs[a]=fexpand(f.type)=func [t1n][t2m]f.code={type x,locals {type t}k,body instr end}F={module f.module, locals valn (defaultt)k})

Note

For non-defaultable types, the respective local is left uninitialized by these rules.

Tail-invocation of function address a

  1. Assert: due to validation, S.funcs[a] exists.

  2. Let func [t1n][t2m] be the composite type expand(S.funcs[a].type).

  3. Assert: due to validation, there are at least n values on the top of the stack.

  4. Pop the results valn from the stack.

  5. Assert: due to validation, the stack contains at least one frame.

  6. While the top of the stack is not a frame, do:

    1. Pop the top element from the stack.

  7. Assert: the top of the stack is a frame.

  8. Pop the frame from the stack.

  9. Push valn to the stack.

  10. Invoke the function instance at address a.

 S;framem{F} B[valn (return_invoke a)] endvaln (invoke a)(ifexpand(S.funcs[a].type)=func [t1n][t2m])

Returning from a function

When the end of a function is reached without a jump (i.e., return) or trap aborting it, then the following steps are performed.

  1. Let F be the current frame.

  2. Let n be the arity of the activation of F.

  3. Assert: due to validation, there are n values on the top of the stack.

  4. Pop the results valn from the stack.

  5. Assert: due to validation, the frame F is now on the top of the stack.

  6. Pop the frame from the stack.

  7. Push valn back to the stack.

  8. Jump to the instruction after the original call.

 framen{F} valn endvaln

Host Functions

Invoking a host function has non-deterministic behavior. It may either terminate with a trap or return regularly. However, in the latter case, it must consume and produce the right number and types of WebAssembly values on the stack, according to its function type.

A host function may also modify the store. However, all store modifications must result in an extension of the original store, i.e., they must only modify mutable contents and must not have instances removed. Furthermore, the resulting store must be valid, i.e., all data and code in it is well-typed.

 S;valn (invoke a)S;result(ifS.funcs[a]={type deftype,hostcode hf}expand(deftype)=func [t1n][t2m](S;result)hf(S;valn))S;valn (invoke a)S;valn (invoke a)(ifS.funcs[a]={type deftype,hostcode hf}expand(deftype)=func [t1n][t2m]hf(S;valn))

Here, hf(S;valn) denotes the implementation-defined execution of host function hf in current store S with arguments valn. It yields a set of possible outcomes, where each element is either a pair of a modified store S and a result or the special value indicating divergence. A host function is non-deterministic if there is at least one argument for which the set of outcomes is not singular.

For a WebAssembly implementation to be sound in the presence of host functions, every host function instance must be valid, which means that it adheres to suitable pre- and post-conditions: under a valid store S, and given arguments valn matching the ascribed parameter types t1n, executing the host function must yield a non-empty set of possible outcomes each of which is either divergence or consists of a valid store S that is an extension of S and a result matching the ascribed return types t2m. All these notions are made precise in the Appendix.

Note

A host function can call back into WebAssembly by invoking a function exported from a module. However, the effects of any such call are subsumed by the non-deterministic behavior allowed for the host function.

Expressions

An expression is evaluated relative to a current frame pointing to its containing module instance.

  1. Jump to the start of the instruction sequence instr of the expression.

  2. Execute the instruction sequence.

  3. Assert: due to validation, the top of the stack contains a value.

  4. Pop the value val from the stack.

The value val is the result of the evaluation.

S;F;instrS;F;instr(ifS;F;instr endS;F;instr end)

Note

Evaluation iterates this reduction rule until reaching a value. Expressions constituting function bodies are executed during function invocation.