Skip to content
This repository was archived by the owner on Nov 3, 2021. It is now read-only.

Commit f574364

Browse files
authored
[Interpreter] Implement rest of the instructions (#64)
`memory.init`, `data.drop`, `table.init`, `elem.drop`, `table.copy` Also fix writing passive segments in the text format.
1 parent f817560 commit f574364

File tree

8 files changed

+312
-16
lines changed

8 files changed

+312
-16
lines changed

interpreter/exec/eval.ml

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ exception Trap = Trap.Error
1717
exception Crash = Crash.Error (* failure that cannot happen in valid code *)
1818
exception Exhaustion = Exhaustion.Error
1919

20+
let table_error at = function
21+
| Table.Bounds -> "out of bounds table access"
22+
| exn -> raise exn
23+
2024
let memory_error at = function
2125
| Memory.Bounds -> "out of bounds memory access"
2226
| Memory.SizeOverflow -> "memory size overflow"
@@ -78,6 +82,8 @@ let func (inst : module_inst) x = lookup "function" inst.funcs x
7882
let table (inst : module_inst) x = lookup "table" inst.tables x
7983
let memory (inst : module_inst) x = lookup "memory" inst.memories x
8084
let global (inst : module_inst) x = lookup "global" inst.globals x
85+
let elems (inst : module_inst) x = lookup "elems" inst.elems x
86+
let data (inst : module_inst) x = lookup "data" inst.data x
8187
let local (frame : frame) x = lookup "local" frame.locals x
8288

8389
let elem inst x i at =
@@ -249,6 +255,22 @@ let rec step (c : config) : config =
249255
(try Eval_numeric.eval_cvtop cvtop v :: vs', []
250256
with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at])
251257

258+
| MemoryInit x, I32 n :: I32 s :: I32 d :: vs' ->
259+
let mem = memory frame.inst (0l @@ e.at) in
260+
(match !(data frame.inst x) with
261+
| Some bs ->
262+
let dst = I64_convert.extend_i32_u d in
263+
let src = I64_convert.extend_i32_u s in
264+
(try Memory.init mem bs dst src n; vs', []
265+
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
266+
| None -> vs', [Trapping "data segment dropped" @@ e.at])
267+
268+
| DataDrop x, vs ->
269+
let seg = data frame.inst x in
270+
(match !seg with
271+
| Some _ -> seg := None; vs, []
272+
| None -> vs, [Trapping "data segment dropped" @@ e.at])
273+
252274
| MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
253275
let mem = memory frame.inst (0l @@ e.at) in
254276
let dst = I64_convert.extend_i32_u d in
@@ -262,6 +284,25 @@ let rec step (c : config) : config =
262284
(try Memory.fill mem addr (Int32.to_int b) n; vs', []
263285
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
264286

287+
| TableInit x, I32 n :: I32 s :: I32 d :: vs' ->
288+
let tab = table frame.inst (0l @@ e.at) in
289+
(match !(elems frame.inst x) with
290+
| Some es ->
291+
(try Table.init tab es d s n; vs', []
292+
with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
293+
| None -> vs', [Trapping "elements segment dropped" @@ e.at])
294+
295+
| ElemDrop x, vs ->
296+
let seg = elems frame.inst x in
297+
(match !seg with
298+
| Some _ -> seg := None; vs, []
299+
| None -> vs, [Trapping "elements segment dropped" @@ e.at])
300+
301+
| TableCopy, I32 n :: I32 s :: I32 d :: vs' ->
302+
let tab = table frame.inst (0l @@ e.at) in
303+
(try Table.copy tab d s n; vs', []
304+
with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
305+
265306
| _ ->
266307
let s1 = string_of_values (List.rev vs) in
267308
let s2 = string_of_value_types (List.map type_of (List.rev vs)) in
@@ -394,6 +435,19 @@ let create_export (inst : module_inst) (ex : export) : export_inst =
394435
| GlobalExport x -> ExternGlobal (global inst x)
395436
in name, ext
396437

438+
let elems_list inst init =
439+
List.map (fun x -> (FuncElem (func inst x))) init
440+
441+
let create_elems (inst : module_inst) (seg : table_segment) : elems_inst =
442+
match seg.it with
443+
| Active _ -> ref None
444+
| Passive init -> ref (Some (elems_list inst init))
445+
446+
let create_data (inst : module_inst) (seg : memory_segment) : data_inst =
447+
match seg.it with
448+
| Active _ -> ref None
449+
| Passive init -> ref (Some init)
450+
397451

398452
let init_func (inst : module_inst) (func : func_inst) =
399453
match func with
@@ -405,7 +459,9 @@ let init_table (inst : module_inst) (seg : table_segment) =
405459
| Active {index; offset = const; init} ->
406460
let tab = table inst index in
407461
let offset = i32 (eval_const inst const) const.at in
408-
(try Table.init tab offset (List.map (fun x -> FuncElem (func inst x)) init)
462+
let elems = elems_list inst init in
463+
let len = Int32.of_int (List.length elems) in
464+
(try Table.init tab elems offset 0l len
409465
with Table.Bounds -> Link.error seg.at "elements segment does not fit table")
410466
| Passive init -> ()
411467

@@ -415,7 +471,8 @@ let init_memory (inst : module_inst) (seg : memory_segment) =
415471
let mem = memory inst index in
416472
let offset' = i32 (eval_const inst const) const.at in
417473
let offset = I64_convert.extend_i32_u offset' in
418-
(try Memory.init mem offset init
474+
let len = Int32.of_int (String.length init) in
475+
(try Memory.init mem init offset 0L len
419476
with Memory.Bounds -> Link.error seg.at "data segment does not fit memory")
420477
| Passive init -> ()
421478

@@ -448,10 +505,16 @@ let init (m : module_) (exts : extern list) : module_inst =
448505
funcs = inst0.funcs @ fs;
449506
tables = inst0.tables @ List.map (create_table inst0) tables;
450507
memories = inst0.memories @ List.map (create_memory inst0) memories;
451-
globals = inst0.globals @ List.map (create_global inst0) globals;
508+
globals = inst0.globals @ List.map (create_global inst0) globals
509+
}
510+
in
511+
let inst =
512+
{ inst1 with
513+
exports = List.map (create_export inst1) exports;
514+
elems = List.map (create_elems inst1) elems;
515+
data = List.map (create_data inst1) data
452516
}
453517
in
454-
let inst = {inst1 with exports = List.map (create_export inst1) exports} in
455518
List.iter (init_func inst) fs;
456519
List.iter (init_table inst) elems;
457520
List.iter (init_memory inst) data;

interpreter/runtime/instance.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ type module_inst =
88
memories : memory_inst list;
99
globals : global_inst list;
1010
exports : export_inst list;
11+
elems : elems_inst list;
12+
data : data_inst list;
1113
}
1214

1315
and func_inst = module_inst ref Func.t
1416
and table_inst = Table.t
1517
and memory_inst = Memory.t
1618
and global_inst = Global.t
1719
and export_inst = Ast.name * extern
20+
and elems_inst = Table.elem list option ref
21+
and data_inst = string option ref
1822

1923
and extern =
2024
| ExternFunc of func_inst
@@ -29,7 +33,7 @@ type Table.elem += FuncElem of func_inst
2933

3034
let empty_module_inst =
3135
{ types = []; funcs = []; tables = []; memories = []; globals = [];
32-
exports = [] }
36+
exports = []; elems = []; data = [] }
3337

3438
let extern_type_of = function
3539
| ExternFunc func -> ExternFuncType (Func.type_of func)

interpreter/runtime/memory.ml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,23 @@ let store_packed sz mem a o v =
145145
| _ -> raise Type
146146
in storen mem a o n x
147147

148+
let check_str_bounds bs a =
149+
if I64.gt_u a (Int64.of_int (String.length bs)) then raise Bounds
150+
148151
let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
149152

150-
let init mem a bs =
151-
for i = 0 to String.length bs - 1 do
152-
store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i])
153-
done;
154-
check_bounds mem Int64.(add a (of_int (String.length bs)))
153+
let init mem bs d s n =
154+
let n' = Int64.of_int32 n in
155+
let rec loop d s n =
156+
if n > 0l then begin
157+
check_str_bounds bs s;
158+
let b = (Char.code bs.[Int64.to_int s]) in
159+
store_byte mem d b;
160+
loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l)
161+
end
162+
in loop d s n;
163+
check_bounds mem (Int64.add d n');
164+
check_str_bounds bs (Int64.add s n')
155165

156166
let copy mem d s n =
157167
let n' = Int64.of_int32 n in

interpreter/runtime/memory.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ val store_packed :
4444
pack_size -> memory -> address -> offset -> value -> unit
4545
(* raises Type, Bounds *)
4646

47-
val init : memory -> address -> string -> unit (* raises Bounds *)
47+
val init :
48+
memory -> string -> address -> address -> count -> unit (* raises Bounds *)
4849
val copy : memory -> address -> address -> count -> unit (* raises Bounds *)
4950
val fill : memory -> address -> int -> count -> unit (* raises Bounds *)

interpreter/runtime/table.ml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ open Types
22

33
type size = int32
44
type index = int32
5+
type count = int32
56

67
type elem = ..
78
type elem += Uninitialized
@@ -50,6 +51,28 @@ let store tab i v =
5051

5152
let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds
5253

53-
let init tab offset elems =
54-
List.iteri (fun i -> store tab (Int32.(add offset (of_int i)))) elems;
55-
check_bounds tab Int32.(add offset (of_int (List.length elems)))
54+
let init tab es d s n =
55+
let rec loop es d s n =
56+
match s, n, es with
57+
| 0l, 0l, _ -> ()
58+
| 0l, n, e::es' ->
59+
store tab d e;
60+
loop es' (Int32.add d 1l) 0l (Int32.sub n 1l)
61+
| s, n, _::es' -> loop es' d (Int32.sub s 1l) n
62+
| _ -> raise Bounds
63+
in loop es d s n;
64+
check_bounds tab (Int32.add d n)
65+
66+
let copy tab d s n =
67+
let overlap = I32.lt_s Int32.(abs (sub d s)) n in
68+
let rec loop d s n dx =
69+
if n > 0l then begin
70+
store tab d (load tab s);
71+
loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx
72+
end
73+
in (if overlap && s < d then
74+
loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l)
75+
else
76+
loop d s n 1l);
77+
check_bounds tab (Int32.add d n);
78+
check_bounds tab (Int32.add s n)

interpreter/runtime/table.mli

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type t = table
55

66
type size = int32
77
type index = int32
8+
type count = int32
89

910
type elem = ..
1011
type elem += Uninitialized
@@ -21,4 +22,6 @@ val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *)
2122
val load : table -> index -> elem (* raises Bounds *)
2223
val store : table -> index -> elem -> unit (* raises Bounds *)
2324

24-
val init : table -> index -> elem list -> unit (* raises Bounds *)
25+
val init :
26+
table -> elem list -> index -> index -> count -> unit (* raises Bounds *)
27+
val copy : table -> index -> index -> count -> unit (* raises Bounds *)

interpreter/text/arrange.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ let segment head dat seg =
300300
match seg.it with
301301
| Active {index; offset; init} ->
302302
Node (head, atom var index :: Node ("offset", const offset) :: dat init)
303-
| Passive init -> Node (head, dat init)
303+
| Passive init -> Node (head ^ " passive", dat init)
304304

305305
let elems seg =
306306
segment "elem" (list (atom var)) seg

0 commit comments

Comments
 (0)