blob: d1f2bce982796ecdd822504e278a764cc18fd3b6 [file] [log] [blame]
open Bigarray
open Lib.Bigarray
open Types
open Values
type size = int32 (* number of pages *)
type address = int64
type offset = int32
type pack_size = Pack8 | Pack16 | Pack32
type extension = SX | ZX
type memory' = (int, int8_unsigned_elt, c_layout) Array1.t
type memory = {mutable content : memory'; max : size option}
type t = memory
exception Type
exception Bounds
exception SizeOverflow
exception SizeLimit
exception OutOfMemory
let page_size = 0x10000L (* 64 KiB *)
let packed_size = function
| Pack8 -> 1
| Pack16 -> 2
| Pack32 -> 4
let within_limits n = function
| None -> true
| Some max -> I32.le_u n max
let create n =
if I32.gt_u n 0x10000l then raise SizeOverflow else
try
let size = Int64.(mul (of_int32 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 (MemoryType {min; max}) =
assert (within_limits min max);
{content = create min; max}
let bound mem =
Array1_64.dim mem.content
let size mem =
Int64.(to_int32 (div (bound mem) page_size))
let type_of mem =
MemoryType {min = size mem; max = mem.max}
let grow mem delta =
let old_size = size mem in
let new_size = Int32.add old_size delta in
if I32.gt_u old_size new_size then raise SizeOverflow else
if not (within_limits new_size mem.max) 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.content <- after
let load_byte mem a =
try Array1_64.get mem.content a with Invalid_argument _ -> raise Bounds
let store_byte mem a b =
try Array1_64.set mem.content a b with Invalid_argument _ -> raise Bounds
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 =
for i = String.length bs - 1 downto 0 do
store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i])
done
let effective_address a o =
let ea = Int64.(add a (of_int32 o)) in
if I64.lt_u ea a then raise Bounds;
ea
let loadn mem a o n =
assert (n > 0 && n <= 8);
let rec loop a n =
if n = 0 then 0L else begin
let x = Int64.(shift_left (loop (add a 1L) (n - 1)) 8) in
Int64.logor (Int64.of_int (load_byte mem a)) x
end
in loop (effective_address a o) n
let storen mem a o n x =
assert (n > 0 && n <= 8);
let rec loop a n x =
if n > 0 then begin
Int64.(loop (add a 1L) (n - 1) (shift_right x 8));
store_byte mem a (Int64.to_int x land 0xff)
end
in loop (effective_address a o) n x
let load_value mem a o t =
let n = loadn mem a o (Types.size t) in
match t with
| I32Type -> I32 (Int64.to_int32 n)
| I64Type -> I64 n
| F32Type -> F32 (F32.of_bits (Int64.to_int32 n))
| F64Type -> F64 (F64.of_bits n)
let store_value mem a o v =
let x =
match v with
| I32 x -> Int64.of_int32 x
| I64 x -> x
| F32 x -> Int64.of_int32 (F32.to_bits x)
| F64 x -> F64.to_bits x
in storen mem a o (Types.size (Values.type_of v)) x
let extend x n = function
| ZX -> x
| SX -> let sh = 64 - 8 * n in Int64.(shift_right (shift_left x sh) sh)
let load_packed sz ext mem a o t =
assert (packed_size sz <= Types.size t);
let n = packed_size sz in
let x = extend (loadn mem a o n) n ext in
match t with
| I32Type -> I32 (Int64.to_int32 x)
| I64Type -> I64 x
| _ -> raise Type
let store_packed sz mem a o v =
assert (packed_size sz <= Types.size (Values.type_of v));
let n = packed_size sz in
let x =
match v with
| I32 x -> Int64.of_int32 x
| I64 x -> x
| _ -> raise Type
in storen mem a o n x