blob: 7914ebeccd639dd5d3a8042f7b6dcf119e8234d3 [file] [log] [blame] [edit]
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