| open Types | |
| open Value | |
| open Bigarray | |
| open Lib.Bigarray | |
| type size = int64 (* number of pages *) | |
| type offset = address | |
| type count = int32 | |
| type memory' = (int, int8_unsigned_elt, c_layout) Array1.t | |
| type memory = {mutable ty : memorytype; mutable content : memory'} | |
| type t = memory | |
| exception Type = Value.Type | |
| exception Bounds | |
| exception SizeOverflow | |
| exception SizeLimit | |
| exception OutOfMemory | |
| let page_size = 0x10000L (* 64 KiB *) | |
| let valid_limits {min; max} = | |
| match max with | |
| | None -> true | |
| | Some m -> I64.le_u min m | |
| let valid_size at i = | |
| match at with | |
| | I32AT -> I64.le_u i 0xffffL | |
| | I64AT -> true | |
| let create n = | |
| try | |
| let size = Int64.(mul n page_size) in | |
| let mem = Array1_64.create Int8_unsigned C_layout size in | |
| Array1.fill mem 0; | |
| mem | |
| with Out_of_memory -> raise OutOfMemory | |
| let alloc (MemoryT (at, lim) as ty) = | |
| assert Free.((memorytype ty).types = Set.empty); | |
| if not (valid_size at lim.min) then raise SizeOverflow; | |
| if not (valid_limits lim) then raise Type; | |
| {ty; content = create lim.min} | |
| let bound mem = | |
| Array1_64.dim mem.content | |
| let size mem = | |
| Int64.(div (bound mem) page_size) | |
| let type_of mem = | |
| mem.ty | |
| let addrtype_of mem = | |
| let MemoryT (at, _) = type_of mem in at | |
| let grow mem delta = | |
| let MemoryT (at, lim) = mem.ty in | |
| assert (lim.min = size mem); | |
| let old_size = lim.min in | |
| let new_size = Int64.add old_size delta in | |
| if I64.gt_u old_size new_size then raise SizeOverflow else | |
| let lim' = {lim with min = new_size} in | |
| if not (valid_size at new_size) then raise SizeOverflow else | |
| if not (valid_limits lim') then raise SizeLimit else | |
| let after = create new_size in | |
| let dim = Array1_64.dim mem.content in | |
| Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim); | |
| mem.ty <- MemoryT (at, lim'); | |
| mem.content <- after | |
| let load_byte mem a = | |
| if a < 0L || a >= Array1_64.dim mem.content then raise Bounds; | |
| Array1_64.get mem.content a | |
| let store_byte mem a b = | |
| if a < 0L || a >= Array1_64.dim mem.content then raise Bounds; | |
| Array1_64.set mem.content a b | |
| let load_bytes mem a n = | |
| let buf = Buffer.create n in | |
| for i = 0 to n - 1 do | |
| Buffer.add_char buf (Char.chr (load_byte mem Int64.(add a (of_int i)))) | |
| done; | |
| Buffer.contents buf | |
| let store_bytes mem a bs = | |
| if a < 0L then raise Bounds; | |
| for i = String.length bs - 1 downto 0 do | |
| store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i]) | |
| done | |
| (* Typed accessors *) | |
| let effective_address a o = | |
| let ea = Int64.(add a o) in | |
| if I64.lt_u ea a then raise Bounds; | |
| ea | |
| let load_num mem a o nt = | |
| let bs = load_bytes mem (effective_address a o) (Types.num_size nt) in | |
| Value.num_of_bits nt bs | |
| let store_num mem a o n = | |
| let bs = Value.bits_of_num n in | |
| store_bytes mem (effective_address a o) bs | |
| let load_num_packed sz sx mem a o nt = | |
| let bs = load_bytes mem (effective_address a o) (Pack.packed_size sz) in | |
| Value.num_of_packed_bits nt sz sx bs | |
| let store_num_packed sz mem a o n = | |
| let bs = Value.packed_bits_of_num sz n in | |
| store_bytes mem (effective_address a o) bs | |
| let load_vec mem a o vt = | |
| let bs = load_bytes mem (effective_address a o) (Types.vec_size vt) in | |
| Value.vec_of_bits vt bs | |
| let store_vec mem a o v = | |
| let bs = Value.bits_of_vec v in | |
| store_bytes mem (effective_address a o) bs | |
| let load_vec_packed sz vext mem a o t = | |
| let bs = load_bytes mem (effective_address a o) (Pack.packed_size sz) in | |
| Value.vec_of_packed_bits t sz vext bs | |
| let load_val mem a o t = | |
| let bs = load_bytes mem (effective_address a o) (Types.val_size t) in | |
| Value.val_of_bits t bs | |
| let store_val mem a o v = | |
| let bs = Value.bits_of_val v in | |
| store_bytes mem (effective_address a o) bs | |
| let load_val_storage mem a o st = | |
| let bs = load_bytes mem (effective_address a o) (Types.storage_size st) in | |
| Value.val_of_storage_bits st bs | |
| let store_val_storage mem a o st v = | |
| let bs = Value.storage_bits_of_val st v in | |
| store_bytes mem (effective_address a o) bs |