Skip to content

Commit

Permalink
Use mmap for implicit memory bounds checks (#68)
Browse files Browse the repository at this point in the history
Implements #38 for memory (but not tables).

Also cleans up a lot of spaghetti code for division, which I rewrote when debugging.

This PR enables implicit memory bounds checks by using mmap instead of malloc for linear memory. The key idea is to rely on hardware protection, as described in the original WASM paper, instead of explicit checks (although these can be re-enabled via the --explicit-bounds-checks flag.

Doing so yields significant speedups -- we are on par with (and sometimes beat!) V8 in the benchmarks I've tried.
  • Loading branch information
SimonJF authored Jul 27, 2018
1 parent 6359e6c commit 40e608f
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 140 deletions.
2 changes: 1 addition & 1 deletion includes/spec-wasm2c-prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ uint32_t* Z_spectestZ_global_i32Z_i = &spectest_global_i32;
*/

static void init_spectest_module(void) {
wasm_rt_allocate_memory(&spectest_memory_memory, 1, 2);
wasm_rt_allocate_memory(&spectest_memory_memory, 1, 2, true);
wasm_rt_allocate_table(&spectest_table_table, 10, 20);
}

Expand Down
56 changes: 32 additions & 24 deletions src/lib/cmmcompile/cmm_rts.ml
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,22 @@ module Memory = struct
[root; eo], nodbg)
else base_expr in

if is_value eo then
with_mem_check
~root
~effective_offset:eo
~chunk ~expr:(expr eo)
else
Clet (eo_ident, eo,
with_mem_check
~root
~effective_offset:eo_var
~chunk
~expr:(expr eo_var))
if Util.Command_line.explicit_bounds_checks () then
begin
if is_value eo then
with_mem_check
~root
~effective_offset:eo
~chunk ~expr:(expr eo)
else
Clet (eo_ident, eo,
with_mem_check
~root
~effective_offset:eo_var
~chunk
~expr:(expr eo_var))
end
else expr eo

let store ~root ~dynamic_pointer ~(op:Libwasm.Ast.storeop) ~to_store =
let open Libwasm.Types in
Expand All @@ -176,18 +180,22 @@ module Memory = struct
Cop (Cstore (chunk, Assignment),
[effective_address root eo; to_store], nodbg) in

if is_value eo then
with_mem_check
~root
~effective_offset:eo
~chunk ~expr:(expr eo)
else
Clet (eo_ident, eo,
with_mem_check
~root
~effective_offset:eo_var
~chunk
~expr:(expr eo_var))
if Util.Command_line.explicit_bounds_checks () then
begin
if is_value eo then
with_mem_check
~root
~effective_offset:eo
~chunk ~expr:(expr eo)
else
Clet (eo_ident, eo,
with_mem_check
~root
~effective_offset:eo_var
~chunk
~expr:(expr eo_var))
end
else expr eo

let grow root pages =
(* I *think* it's safe to put false as allocation flag here, since
Expand Down
11 changes: 2 additions & 9 deletions src/lib/cmmcompile/dce.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ let empty_dce_info usages pure expr = {
expr
}

(* An identifier used where we need to perform an action, but don't need
* the result. This means we have fewer variables for reg allocation, but
* still perform the necessary side-effects *)
let impure_ident = Ident.create "impure"

let increment_usages ht ident =
(* Function parameters aren't in the hashtable. *)
let ident_name = Ident.name ident in
Expand Down Expand Up @@ -92,6 +87,8 @@ let populate_info ht expr =
| Cexit (_, es) -> all_pure es
| Ctrywith (e1, _, e2) -> all_pure [e1; e2]
| Cop (Capply _, es, _)
| Cop (Cdivi, es, _)
| Cop (Cdiviu, es, _)
| Cop (Cextcall _, es, _)
| Cop (Cextcall_indirect _, es, _)
| Cop (Cload _, es, _)
Expand Down Expand Up @@ -134,10 +131,6 @@ let dce ht expr =
(* Only used once, so reasonable to inline. We can kill
* the binding. *)
go e2
else if dce_info.usages = 0 && (dce_info.pure = Impure) then
(* Redundant load / store, but we still need to perform it.
* Bind it to the "impure" identifier. *)
Clet (impure_ident, go e1, go e2)
else
(* Otherwise, we need the binding. *)
Clet (ident, go e1, go e2)
Expand Down
Loading

0 comments on commit 40e608f

Please sign in to comment.