Skip to content

Commit

Permalink
Implement atomic instructions in the interpreter (WebAssembly#67)
Browse files Browse the repository at this point in the history
Added support for all atomic loads, stores, rmw, and cmpxchg instructions. They currently operate on non-shared memory, since I haven't implemented the `shared` flag yet.
  • Loading branch information
binji committed Oct 24, 2017
1 parent ca698f9 commit 4034e63
Show file tree
Hide file tree
Showing 14 changed files with 943 additions and 0 deletions.
80 changes: 80 additions & 0 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(* Decoding stream *)

open Values

type stream =
{
name : string;
Expand Down Expand Up @@ -200,6 +202,82 @@ let memop s =
let offset = vu32 s in
Int32.to_int align, offset

let atomic_instr s =
let pos = pos s in
match op s with
| 0x10 -> let a, o = memop s in i32_atomic_load a o
| 0x11 -> let a, o = memop s in i64_atomic_load a o
| 0x12 -> let a, o = memop s in i32_atomic_load8_u a o
| 0x13 -> let a, o = memop s in i32_atomic_load16_u a o
| 0x14 -> let a, o = memop s in i64_atomic_load8_u a o
| 0x15 -> let a, o = memop s in i64_atomic_load16_u a o
| 0x16 -> let a, o = memop s in i64_atomic_load32_u a o
| 0x17 -> let a, o = memop s in i32_atomic_store a o
| 0x18 -> let a, o = memop s in i64_atomic_store a o
| 0x19 -> let a, o = memop s in i32_atomic_store8 a o
| 0x1a -> let a, o = memop s in i32_atomic_store16 a o
| 0x1b -> let a, o = memop s in i64_atomic_store8 a o
| 0x1c -> let a, o = memop s in i64_atomic_store16 a o
| 0x1d -> let a, o = memop s in i64_atomic_store32 a o

| 0x1e -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwAdd) a o
| 0x1f -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwAdd) a o
| 0x20 -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwAdd) a o
| 0x21 -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwAdd) a o
| 0x22 -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwAdd) a o
| 0x23 -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwAdd) a o
| 0x24 -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwAdd) a o

| 0x25 -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwSub) a o
| 0x26 -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwSub) a o
| 0x27 -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwSub) a o
| 0x28 -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwSub) a o
| 0x29 -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwSub) a o
| 0x2a -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwSub) a o
| 0x2b -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwSub) a o

| 0x2c -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwAnd) a o
| 0x2d -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwAnd) a o
| 0x2e -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwAnd) a o
| 0x2f -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwAnd) a o
| 0x30 -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwAnd) a o
| 0x31 -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwAnd) a o
| 0x32 -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwAnd) a o

| 0x33 -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwOr) a o
| 0x34 -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwOr) a o
| 0x35 -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwOr) a o
| 0x36 -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwOr) a o
| 0x37 -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwOr) a o
| 0x38 -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwOr) a o
| 0x39 -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwOr) a o

| 0x3a -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwXor) a o
| 0x3b -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwXor) a o
| 0x3c -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwXor) a o
| 0x3d -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwXor) a o
| 0x3e -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwXor) a o
| 0x3f -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwXor) a o
| 0x40 -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwXor) a o

| 0x41 -> let a, o = memop s in i32_atomic_rmw (I32 I32Op.RmwXchg) a o
| 0x42 -> let a, o = memop s in i64_atomic_rmw (I64 I64Op.RmwXchg) a o
| 0x43 -> let a, o = memop s in i32_atomic_rmw8_u (I32 I32Op.RmwXchg) a o
| 0x44 -> let a, o = memop s in i32_atomic_rmw16_u (I32 I32Op.RmwXchg) a o
| 0x45 -> let a, o = memop s in i64_atomic_rmw8_u (I64 I64Op.RmwXchg) a o
| 0x46 -> let a, o = memop s in i64_atomic_rmw16_u (I64 I64Op.RmwXchg) a o
| 0x47 -> let a, o = memop s in i64_atomic_rmw32_u (I64 I64Op.RmwXchg) a o

| 0x48 -> let a, o = memop s in i32_atomic_rmw_cmpxchg a o
| 0x49 -> let a, o = memop s in i64_atomic_rmw_cmpxchg a o
| 0x4a -> let a, o = memop s in i32_atomic_rmw8_u_cmpxchg a o
| 0x4b -> let a, o = memop s in i32_atomic_rmw16_u_cmpxchg a o
| 0x4c -> let a, o = memop s in i64_atomic_rmw8_u_cmpxchg a o
| 0x4d -> let a, o = memop s in i64_atomic_rmw16_u_cmpxchg a o
| 0x4e -> let a, o = memop s in i64_atomic_rmw32_u_cmpxchg a o

| b -> illegal s pos b

let rec instr s =
let pos = pos s in
match op s with
Expand Down Expand Up @@ -438,6 +516,8 @@ let rec instr s =
| 0xc3 -> i64_extend16_s
| 0xc4 -> i64_extend32_s

| 0xfe -> atomic_instr s

| b -> illegal s pos b

and instr_block s = List.rev (instr_block' s [])
Expand Down
148 changes: 148 additions & 0 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,154 @@ let encode m =
| Store ({ty = I64Type; sz = Some Mem32; _} as mo) -> op 0x3e; memop mo
| Store {ty = F32Type | F64Type; sz = Some _; _} -> assert false

| AtomicLoad ({ty = I32Type; sz = None; _} as mo) ->
op 0xfe; op 0x10; memop mo
| AtomicLoad ({ty = I64Type; sz = None; _} as mo) ->
op 0xfe; op 0x11; memop mo
| AtomicLoad ({ty = I32Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x12; memop mo
| AtomicLoad ({ty = I32Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x13; memop mo
| AtomicLoad {ty = I32Type; sz = Some Mem32; _} -> assert false
| AtomicLoad ({ty = I64Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x14; memop mo
| AtomicLoad ({ty = I64Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x15; memop mo
| AtomicLoad ({ty = I64Type; sz = Some Mem32; _} as mo) ->
op 0xfe; op 0x16; memop mo
| AtomicLoad {ty = F32Type | F64Type; _} -> assert false

| AtomicStore ({ty = I32Type; sz = None; _} as mo) ->
op 0xfe; op 0x17; memop mo
| AtomicStore ({ty = I64Type; sz = None; _} as mo) ->
op 0xfe; op 0x18; memop mo
| AtomicStore ({ty = I32Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x19; memop mo
| AtomicStore ({ty = I32Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x1a; memop mo
| AtomicStore {ty = I32Type; sz = Some Mem32; _} -> assert false
| AtomicStore ({ty = I64Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x1b; memop mo
| AtomicStore ({ty = I64Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x1c; memop mo
| AtomicStore ({ty = I64Type; sz = Some Mem32; _} as mo) ->
op 0xfe; op 0x1d; memop mo
| AtomicStore {ty = F32Type | F64Type; _} -> assert false

| AtomicRmw (I32 I32Op.RmwAdd, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x1e; memop mo
| AtomicRmw (I64 I64Op.RmwAdd, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x1f; memop mo
| AtomicRmw (I32 I32Op.RmwAdd, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x20; memop mo
| AtomicRmw (I32 I32Op.RmwAdd, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x21; memop mo
| AtomicRmw (I64 I64Op.RmwAdd, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x22; memop mo
| AtomicRmw (I64 I64Op.RmwAdd, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x23; memop mo
| AtomicRmw (I64 I64Op.RmwAdd, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x24; memop mo

| AtomicRmw (I32 I32Op.RmwSub, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x25; memop mo
| AtomicRmw (I64 I64Op.RmwSub, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x26; memop mo
| AtomicRmw (I32 I32Op.RmwSub, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x27; memop mo
| AtomicRmw (I32 I32Op.RmwSub, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x28; memop mo
| AtomicRmw (I64 I64Op.RmwSub, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x29; memop mo
| AtomicRmw (I64 I64Op.RmwSub, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x2a; memop mo
| AtomicRmw (I64 I64Op.RmwSub, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x2b; memop mo

| AtomicRmw (I32 I32Op.RmwAnd, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x2c; memop mo
| AtomicRmw (I64 I64Op.RmwAnd, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x2d; memop mo
| AtomicRmw (I32 I32Op.RmwAnd, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x2e; memop mo
| AtomicRmw (I32 I32Op.RmwAnd, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x2f; memop mo
| AtomicRmw (I64 I64Op.RmwAnd, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x30; memop mo
| AtomicRmw (I64 I64Op.RmwAnd, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x31; memop mo
| AtomicRmw (I64 I64Op.RmwAnd, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x32; memop mo

| AtomicRmw (I32 I32Op.RmwOr, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x33; memop mo
| AtomicRmw (I64 I64Op.RmwOr, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x34; memop mo
| AtomicRmw (I32 I32Op.RmwOr, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x35; memop mo
| AtomicRmw (I32 I32Op.RmwOr, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x36; memop mo
| AtomicRmw (I64 I64Op.RmwOr, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x37; memop mo
| AtomicRmw (I64 I64Op.RmwOr, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x38; memop mo
| AtomicRmw (I64 I64Op.RmwOr, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x39; memop mo

| AtomicRmw (I32 I32Op.RmwXor, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x3a; memop mo
| AtomicRmw (I64 I64Op.RmwXor, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x3b; memop mo
| AtomicRmw (I32 I32Op.RmwXor, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x3c; memop mo
| AtomicRmw (I32 I32Op.RmwXor, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x3d; memop mo
| AtomicRmw (I64 I64Op.RmwXor, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x3e; memop mo
| AtomicRmw (I64 I64Op.RmwXor, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x3f; memop mo
| AtomicRmw (I64 I64Op.RmwXor, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x40; memop mo

| AtomicRmw (I32 I32Op.RmwXchg, ({ty = I32Type; sz = None; _} as mo)) ->
op 0xfe; op 0x41; memop mo
| AtomicRmw (I64 I64Op.RmwXchg, ({ty = I64Type; sz = None; _} as mo)) ->
op 0xfe; op 0x42; memop mo
| AtomicRmw (I32 I32Op.RmwXchg, ({ty = I32Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x43; memop mo
| AtomicRmw (I32 I32Op.RmwXchg, ({ty = I32Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x44; memop mo
| AtomicRmw (I64 I64Op.RmwXchg, ({ty = I64Type; sz = Some Mem8; _} as mo)) ->
op 0xfe; op 0x45; memop mo
| AtomicRmw (I64 I64Op.RmwXchg, ({ty = I64Type; sz = Some Mem16; _} as mo)) ->
op 0xfe; op 0x46; memop mo
| AtomicRmw (I64 I64Op.RmwXchg, ({ty = I64Type; sz = Some Mem32; _} as mo)) ->
op 0xfe; op 0x47; memop mo

| AtomicRmw (I32 _, {ty = I64Type; _}) -> assert false
| AtomicRmw (I64 _, {ty = I32Type; _}) -> assert false
| AtomicRmw ((F32 _ | F64 _), _) -> assert false
| AtomicRmw (_, {ty = I32Type; sz = Some Mem32; _}) -> assert false
| AtomicRmw (_, {ty = F32Type | F64Type; _}) -> assert false

| AtomicRmwCmpXchg ({ty = I32Type; sz = None; _} as mo) ->
op 0xfe; op 0x48; memop mo
| AtomicRmwCmpXchg ({ty = I64Type; sz = None; _} as mo) ->
op 0xfe; op 0x49; memop mo
| AtomicRmwCmpXchg ({ty = I32Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x4a; memop mo
| AtomicRmwCmpXchg ({ty = I32Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x4b; memop mo
| AtomicRmwCmpXchg {ty = I32Type; sz = Some Mem32; _} -> assert false
| AtomicRmwCmpXchg ({ty = I64Type; sz = Some Mem8; _} as mo) ->
op 0xfe; op 0x4c; memop mo
| AtomicRmwCmpXchg ({ty = I64Type; sz = Some Mem16; _} as mo) ->
op 0xfe; op 0x4d; memop mo
| AtomicRmwCmpXchg ({ty = I64Type; sz = Some Mem32; _} as mo) ->
op 0xfe; op 0x4e; memop mo
| AtomicRmwCmpXchg {ty = F32Type | F64Type; _} -> assert false


| CurrentMemory -> op 0x3f; u8 0x00
| GrowMemory -> op 0x40; u8 0x00

Expand Down
62 changes: 62 additions & 0 deletions interpreter/exec/eval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ let take n (vs : 'a stack) at =
let drop n (vs : 'a stack) at =
try Lib.List.drop n vs with Failure _ -> Crash.error at "stack underflow"

let check_align addr ty sz at =
if not (Memory.is_aligned addr ty sz) then
Trap.error at "unaligned atomic memory access"


(* Evaluation *)

Expand Down Expand Up @@ -214,6 +218,64 @@ let rec step (c : config) : config =
vs', []
with exn -> vs', [Trapped (memory_error e.at exn) @@ e.at]);

| AtomicLoad {offset; ty; sz; _}, I32 i :: vs' ->
let mem = memory frame.inst (0l @@ e.at) in
let addr = I64_convert.extend_u_i32 i in
(try
check_align addr ty sz e.at;
let v =
match sz with
| None -> Memory.load_value mem addr offset ty
| Some sz -> Memory.load_packed sz Memory.ZX mem addr offset ty
in v :: vs', []
with exn -> vs', [Trapped (memory_error e.at exn) @@ e.at])

| AtomicStore {offset; ty; sz; _}, v :: I32 i :: vs' ->
let mem = memory frame.inst (0l @@ e.at) in
let addr = I64_convert.extend_u_i32 i in
(try
check_align addr ty sz e.at;
(match sz with
| None -> Memory.store_value mem addr offset v
| Some sz -> Memory.store_packed sz mem addr offset v
);
vs', []
with exn -> vs', [Trapped (memory_error e.at exn) @@ e.at]);

| AtomicRmw (rmwop, {offset; ty; sz; _}), v :: I32 i :: vs' ->
let mem = memory frame.inst (0l @@ e.at) in
let addr = I64_convert.extend_u_i32 i in
(try
check_align addr ty sz e.at;
let v1 =
match sz with
| None -> Memory.load_value mem addr offset ty
| Some sz -> Memory.load_packed sz Memory.ZX mem addr offset ty
in let v2 = Eval_numeric.eval_rmwop rmwop v1 v
in (match sz with
| None -> Memory.store_value mem addr offset v2
| Some sz -> Memory.store_packed sz mem addr offset v2
);
v1 :: vs', []
with exn -> vs', [Trapped (memory_error e.at exn) @@ e.at])

| AtomicRmwCmpXchg {offset; ty; sz; _}, vn :: ve :: I32 i :: vs' ->
let mem = memory frame.inst (0l @@ e.at) in
let addr = I64_convert.extend_u_i32 i in
(try
check_align addr ty sz e.at;
let v1 =
match sz with
| None -> Memory.load_value mem addr offset ty
| Some sz -> Memory.load_packed sz Memory.ZX mem addr offset ty
in (if v1 = ve then
match sz with
| None -> Memory.store_value mem addr offset vn
| Some sz -> Memory.store_packed sz mem addr offset vn
);
v1 :: vs', []
with exn -> vs', [Trapped (memory_error e.at exn) @@ e.at]);

| CurrentMemory, vs ->
let mem = memory frame.inst (0l @@ e.at) in
I32 (Memory.size mem) :: vs, []
Expand Down
13 changes: 13 additions & 0 deletions interpreter/exec/eval_numeric.ml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ struct
| GeS -> IXX.ge_s
| GeU -> IXX.ge_u
in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2)

let rmwop op =
let f = match op with
| RmwAdd -> IXX.add
| RmwSub -> IXX.sub
| RmwAnd -> IXX.and_
| RmwOr -> IXX.or_
| RmwXor -> IXX.xor
| RmwXchg -> fun x y -> y (* Return the "new" value, y *)
in fun v1 v2 -> to_value (f (of_value 1 v1) (of_value 2 v2))
end

module I32Op = IntOp (I32) (Values.I32Value)
Expand Down Expand Up @@ -114,6 +124,8 @@ struct
| Gt -> FXX.gt
| Ge -> FXX.ge
in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2)

let rmwop op = assert false
end

module F32Op = FloatOp (F32) (Values.F32Value)
Expand Down Expand Up @@ -198,3 +210,4 @@ let eval_binop = op I32Op.binop I64Op.binop F32Op.binop F64Op.binop
let eval_testop = op I32Op.testop I64Op.testop F32Op.testop F64Op.testop
let eval_relop = op I32Op.relop I64Op.relop F32Op.relop F64Op.relop
let eval_cvtop = op I32CvtOp.cvtop I64CvtOp.cvtop F32CvtOp.cvtop F64CvtOp.cvtop
let eval_rmwop = op I32Op.rmwop I64Op.rmwop F32Op.rmwop F64Op.rmwop
1 change: 1 addition & 0 deletions interpreter/exec/eval_numeric.mli
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ val eval_binop : Ast.binop -> value -> value -> value
val eval_testop : Ast.testop -> value -> bool
val eval_relop : Ast.relop -> value -> value -> bool
val eval_cvtop : Ast.cvtop -> value -> value
val eval_rmwop : Ast.rmwop -> value -> value -> value
10 changes: 10 additions & 0 deletions interpreter/runtime/memory.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ let mem_size = function
| Mem16 -> 2
| Mem32 -> 4

let mem_size_opt t sz =
match sz with
| None -> Types.size t
| Some s -> mem_size s

let is_aligned a t sz =
let align = mem_size_opt t sz in
let mask = align - 1 in
Int64.(logand a (of_int mask)) = 0L

let within_limits n = function
| None -> true
| Some max -> I32.le_u n max
Expand Down
1 change: 1 addition & 0 deletions interpreter/runtime/memory.mli
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ exception OutOfMemory

val page_size : int64
val mem_size : mem_size -> int
val is_aligned : address -> value_type -> mem_size option -> bool

val alloc : memory_type -> memory (* raises SizeOverflow, OutOfMemory *)
val type_of : memory -> memory_type
Expand Down
Loading

0 comments on commit 4034e63

Please sign in to comment.