Skip to content

Commit b0de0e9

Browse files
authored
Implement parser support for pagetype (#51 from WebAssembly/parser_impl)
2 parents 16296b7 + 402d938 commit b0de0e9

9 files changed

Lines changed: 76 additions & 30 deletions

File tree

interpreter/runtime/memory.ml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,30 @@ let valid_limits {min; max} =
2222
| None -> true
2323
| Some m -> I64.le_u min m
2424

25-
let valid_size at i =
26-
match at with
27-
| I32AT -> I64.le_u i 0xffffL
28-
| I64AT -> true
25+
let valid_size at pt i =
26+
match at, pt with
27+
| I32AT, PageT ps -> I64.le_u i (Int64.shift_right 0xffff_ffffL ps)
28+
| _, _ -> true
2929

3030
let create n (PageT ps) =
3131
try
32-
let size = Int64.(shift_left n ps) in
32+
let size = Int64.shift_left n ps in
3333
let mem = Array1_64.create Int8_unsigned C_layout size in
3434
Array1.fill mem 0;
3535
mem
3636
with Out_of_memory -> raise OutOfMemory
3737

3838
let alloc (MemoryT (at, lim, pt) as ty) =
3939
assert Free.((memorytype ty).types = Set.empty);
40-
if not (valid_size at lim.min) then raise SizeOverflow;
40+
if not (valid_size at pt lim.min) then raise SizeOverflow;
4141
if not (valid_limits lim) then raise Type;
4242
{ty; content = create lim.min pt}
4343

4444
let bound mem =
4545
Array1_64.dim mem.content
4646

4747
let pagesize mem =
48-
let MemoryT (_, _, PageT x) = mem.ty in (Int64.shift_left 1L x)
48+
let MemoryT (_, _, PageT x) = mem.ty in Int64.shift_left 1L x
4949

5050
let size mem =
5151
Int64.(div (bound mem) (pagesize mem))
@@ -63,7 +63,7 @@ let grow mem delta =
6363
let new_size = Int64.add old_size delta in
6464
if I64.gt_u old_size new_size then raise SizeOverflow else
6565
let lim' = {lim with min = new_size} in
66-
if not (valid_size at new_size) then raise SizeOverflow else
66+
if not (valid_size at pt new_size) then raise SizeOverflow else
6767
if not (valid_limits lim') then raise SizeLimit else
6868
let after = create new_size pt in
6969
let dim = Array1_64.dim mem.content in

interpreter/text/lexer.mll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@ rule token = parse
780780
| "start" -> START
781781
| "import" -> IMPORT
782782
| "export" -> EXPORT
783+
| "pagesize" -> PAGESIZE
783784

784785
| "module" -> MODULE
785786
| "binary" -> BIN

interpreter/text/parser.mly

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ let parse_annots (m : module_) : Custom.section list =
321321
%token VEC_SHUFFLE
322322
%token<Ast.laneidx -> Ast.instr'> VEC_EXTRACT VEC_REPLACE
323323
%token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
324+
%token PAGESIZE
324325
%token TABLE ELEM MEMORY TAG DATA DECLARE OFFSET ITEM IMPORT EXPORT
325326
%token MODULE BIN QUOTE DEFINITION INSTANCE
326327
%token SCRIPT REGISTER INVOKE GET
@@ -465,8 +466,16 @@ subtype :
465466
tabletype :
466467
| addrtype limits reftype { fun c -> TableT ($1, $2, $3 c) }
467468

469+
%inline pagetype :
470+
| LPAR PAGESIZE NAT RPAR
471+
{ let n = (nat32 $3 $loc($3)) in
472+
if not (Lib.Int32.is_power_of_two_unsigned n) then
473+
error (at $sloc) "invalid custom page size: must be power of two";
474+
PageT (Int32.to_int (Lib.Int32.log2_unsigned n)) }
475+
| /* empty */ { PageT 16 } /* Sugar */
476+
468477
memorytype :
469-
| addrtype limits { fun c -> MemoryT ($1, $2, PageT 16) }
478+
| addrtype limits pagetype { fun c -> MemoryT ($1, $2, $3) }
470479

471480
limits :
472481
| NAT { {min = nat64 $1 $loc($1); max = None} }
@@ -1126,12 +1135,14 @@ memory_fields :
11261135
| inline_export memory_fields /* Sugar */
11271136
{ fun c x loc -> let mems, data, ims, exs = $2 c x loc in
11281137
mems, data, ims, $1 (MemoryX x) c :: exs }
1129-
| addrtype LPAR DATA string_list RPAR /* Sugar */
1138+
| addrtype pagetype LPAR DATA string_list RPAR /* Sugar */
11301139
{ fun c x loc ->
1131-
let size = Int64.(div (add (of_int (String.length $4)) 65535L) 65536L) in
1140+
let PageT ps = $2 in
1141+
let page_size = Int64.shift_left 1L ps in
1142+
let size = Int64.(div (add (of_int (String.length $5)) (sub page_size 1L)) page_size) in
11321143
let offset = [at_const $1 (0L @@ loc) @@ loc] @@ loc in
1133-
[Memory (MemoryT ($1, {min = size; max = Some size}, PageT 16)) @@ loc],
1134-
[Data ($4, Active (x, offset) @@ loc) @@ loc],
1144+
[Memory (MemoryT ($1, {min = size; max = Some size}, $2)) @@ loc],
1145+
[Data ($5, Active (x, offset) @@ loc) @@ loc],
11351146
[], [] }
11361147
11371148

interpreter/util/lib.ml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,20 @@ end
307307

308308
module Int32 =
309309
struct
310-
let log2 n =
311-
if n <= 0l then failwith "log2";
310+
let log2_unsigned n =
312311
let rec loop acc n =
313312
if n = 1l then acc else loop (Int32.add acc 1l) (Int32.shift_right_logical n 1) in
314313
loop 0l n
314+
315+
let log2 n =
316+
if n <= 0l then failwith "log2" else log2_unsigned n
317+
318+
let is_power_of_two_unsigned n =
319+
n <> 0l && Int32.(logand n (sub n 1l)) = 0l
315320

316321
let is_power_of_two n =
317-
if n < 0l then failwith "is_power_of_two";
318-
n <> 0l && Int32.(logand n (sub n 1l)) = 0l
322+
if n < 0l then failwith "is_power_of_two" else
323+
is_power_of_two_unsigned n
319324
end
320325

321326
module Int64 =

interpreter/util/lib.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ end
9797
module Int32 :
9898
sig
9999
val log2 : int32 -> int32
100+
val log2_unsigned : int32 -> int32
100101
val is_power_of_two : int32 -> bool
102+
val is_power_of_two_unsigned : int32 -> bool
101103
end
102104

103105
module Int64 :

interpreter/valid/valid.ml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ let check_limits {min; max} range at msg =
105105
"size minimum must not be greater than maximum"
106106

107107
let check_pagetype (PageT ps) at =
108-
require (ps = 16 || ps = 0) at "page size must be 1 or 64KiB"
108+
require (ps = 16 || ps = 0) at "invalid custom page size"
109109

110110
let check_numtype (c : context) (t : numtype) at =
111111
()
@@ -200,13 +200,16 @@ let check_globaltype (c : context) (gt : globaltype) at =
200200

201201
let check_memorytype (c : context) (mt : memorytype) at =
202202
let MemoryT (at_, lim, pt) = mt in
203+
check_pagetype pt at;
203204
let sz, s =
204-
match at_ with
205-
| I32AT -> 0x1_0000L, "2^16 pages (4 GiB) for i32"
206-
| I64AT -> 0x1_0000_0000_0000L, "2^48 pages (256 TiB) for i64"
205+
match at_, pt with
206+
| I32AT, PageT 16 -> 0x1_0000L, "2^16 pages (4 GiB) for i32"
207+
| I64AT, PageT 16 -> 0x1_0000_0000_0000L, "2^48 pages (256 TiB) for i64"
208+
(* TODO: divide by page size, what about error msg? *)
209+
| I32AT, _ -> 0xFFFF_FFFFL, "2^32 - 1 bytes for i32"
210+
| I64AT, _ -> 0xFFFF_FFFF_FFFF_FFFFL, "2^64 - 1 bytes for i64"
207211
in
208-
check_limits lim sz at ("memory size must be at most " ^ s);
209-
check_pagetype pt at
212+
check_limits lim sz at ("memory size must be at most " ^ s)
210213

211214
let check_tabletype (c : context) (tt : tabletype) at =
212215
let TableT (at_, lim, t) = tt in

test/core/custom-page-sizes/custom-page-sizes.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
;; Inline data segments
111111

112112
;; pagesize 0
113-
(assert_malformed (module quote "(memory (pagesize 0) (data))") "invalid custom page size")
113+
(assert_malformed (module quote "(module (memory (pagesize 0) (data)))") "invalid custom page size")
114114

115115
;; pagesize 1
116116
(module

test/core/custom-page-sizes/memory_max.wast

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,26 @@
1919
(module
2020
(import "test" "unknown" (func))
2121
(memory 0xFFFF_FFFF (pagesize 1)))
22-
"unknown import")
22+
"incompatible import type")
23+
24+
;; i32 (pagesize 1)
25+
(assert_unlinkable
26+
(module
27+
(import "test" "unknown" (memory 0xFFFF_FFFF (pagesize 1))))
28+
"incompatible import type")
2329

2430
;; i32 (default pagesize)
2531
(assert_unlinkable
2632
(module
2733
(import "test" "unknown" (func))
2834
(memory 65536 (pagesize 65536)))
29-
"unknown import")
35+
"incompatible import type")
36+
37+
;; i32 (default pagesize)
38+
(assert_unlinkable
39+
(module
40+
(import "test" "unknown" (memory 65536 (pagesize 65536))))
41+
"incompatible import type")
3042

3143
;; Memory size just over the maximum.
3244

test/core/custom-page-sizes/memory_max_i64.wast

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,28 @@
1717
;; i64 (pagesize 1)
1818
(assert_unlinkable
1919
(module
20-
(import "test" "import" (func))
20+
(import "test" "unknown" (func))
2121
(memory i64 0xFFFF_FFFF_FFFF_FFFF (pagesize 1)))
22-
"unknown import")
22+
"incompatible import type")
23+
24+
;; i64 (pagesize 1)
25+
(assert_unlinkable
26+
(module
27+
(import "test" "unknown" (memory i64 0xFFFF_FFFF_FFFF_FFFF (pagesize 1))))
28+
"incompatible import type")
2329

2430
;; i64 (default pagesize)
2531
(assert_unlinkable
2632
(module
2733
(import "test" "unknown" (func))
2834
(memory i64 0x1_0000_0000_0000 (pagesize 65536)))
29-
"unknown import")
35+
"incompatible import type")
36+
37+
;; i64 (default pagesize)
38+
(assert_unlinkable
39+
(module
40+
(import "test" "unknown" (memory i64 0x1_0000_0000_0000 (pagesize 65536))))
41+
"incompatible import type")
3042

3143
;; Memory size just over the maximum.
3244
;;
@@ -36,7 +48,7 @@
3648
;; i64 (pagesize 1)
3749
(assert_malformed
3850
(module quote "(memory i64 0x1_0000_0000_0000_0000 (pagesize 1))")
39-
"constant out of range")
51+
"i64 constant out of range")
4052

4153
;; i64 (default pagesize)
4254
(assert_invalid

0 commit comments

Comments
 (0)