From 1a0384476e36251fde96c7375b23d8b6f1315079 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 14 Feb 2018 20:34:17 +0100 Subject: [PATCH] [spec/interpreter] Correct and test segment offset syntax (#663) --- document/core/text/modules.rst | 22 ++- test/core/data.wast | 335 +++++++++++++++++++++++++++++++++ test/core/elem.wast | 280 +++++++++++++++++++++------ test/core/memory.wast | 84 +-------- 4 files changed, 579 insertions(+), 142 deletions(-) create mode 100644 test/core/data.wast diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index d951fc92d3..24e66ff81b 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -489,7 +489,16 @@ When omitted, :math:`\T{0}` is assumed. Abbreviations ............. -As an abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. +As an abbreviation, a single instruction may occur in place of the offset: + +.. math: + \begin{array}{llcll} + \production{element offset} & + \Tinstr &\equiv& + \text{(}~\text{offset}~~\Tinstr~\text{)} + \end{array} + +As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. .. index:: data, memory, memory index, expression, byte @@ -524,7 +533,16 @@ The data is written as a :ref:`string `, which may be split up into Abbreviations ............. -As an abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. +As an abbreviation, a single instruction may occur in place of the offset: + +.. math: + \begin{array}{llcll} + \production{data offset} & + \Tinstr &\equiv& + \text{(}~\text{offset}~~\Tinstr~\text{)} + \end{array} + +As another abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. .. index:: module, type definition, function type, function, table, memory, global, element, data, start function, import, export, identifier context, identifier, name section diff --git a/test/core/data.wast b/test/core/data.wast new file mode 100644 index 0000000000..46b95436fd --- /dev/null +++ b/test/core/data.wast @@ -0,0 +1,335 @@ +;; Test the data section + +;; Syntax + +(module + (memory $m 1) + (data (i32.const 0)) + (data (i32.const 1) "a" "" "bcd") + (data (offset (i32.const 0))) + (data (offset (i32.const 0)) "" "a" "bc" "") + (data 0 (i32.const 0)) + (data 0x0 (i32.const 1) "a" "" "bcd") + (data 0x000 (offset (i32.const 0))) + (data 0 (offset (i32.const 0)) "" "a" "bc" "") + (data $m (i32.const 0)) + (data $m (i32.const 1) "a" "" "bcd") + (data $m (offset (i32.const 0))) + (data $m (offset (i32.const 0)) "" "a" "bc" "") +) + +;; Basic use + +(module + (memory 1) + (data (i32.const 0) "a") +) +(module + (import "spectest" "memory" (memory 1)) + (data (i32.const 0) "a") +) + +(module + (memory 1) + (data (i32.const 0) "a") + (data (i32.const 3) "b") + (data (i32.const 100) "cde") + (data (i32.const 5) "x") + (data (i32.const 3) "c") +) +(module + (import "spectest" "memory" (memory 1)) + (data (i32.const 0) "a") + (data (i32.const 1) "b") + (data (i32.const 2) "cde") + (data (i32.const 3) "f") + (data (i32.const 2) "g") + (data (i32.const 1) "h") +) + +(module + (global (import "spectest" "global_i32") i32) + (memory 1) + (data (get_global 0) "a") +) +(module + (global (import "spectest" "global_i32") i32) + (import "spectest" "memory" (memory 1)) + (data (get_global 0) "a") +) + +(module + (global $g (import "spectest" "global_i32") i32) + (memory 1) + (data (get_global $g) "a") +) +(module + (global $g (import "spectest" "global_i32") i32) + (import "spectest" "memory" (memory 1)) + (data (get_global $g) "a") +) + +;; Use of internal globals in constant expressions is not allowed in MVP. +;; (module (memory 1) (data (get_global 0) "a") (global i32 (i32.const 0))) +;; (module (memory 1) (data (get_global $g) "a") (global $g i32 (i32.const 0))) + +;; Corner cases + +(module + (memory 1) + (data (i32.const 0) "a") + (data (i32.const 0xffff) "b") +) +(module + (import "spectest" "memory" (memory 1)) + (data (i32.const 0) "a") + (data (i32.const 0xffff) "b") +) + +(module + (memory 2) + (data (i32.const 0x1_ffff) "a") +) + +(module + (memory 0) + (data (i32.const 0)) +) +(module + (import "spectest" "memory" (memory 0)) + (data (i32.const 0)) +) + +(module + (memory 0 0) + (data (i32.const 0)) +) + +(module + (memory 1) + (data (i32.const 0x1_0000) "") +) + +(module + (memory 0) + (data (i32.const 0) "" "") +) +(module + (import "spectest" "memory" (memory 0)) + (data (i32.const 0) "" "") +) + +(module + (memory 0 0) + (data (i32.const 0) "" "") +) + +(module + (import "spectest" "memory" (memory 0)) + (data (i32.const 0) "a") +) + +(module + (import "spectest" "memory" (memory 0 3)) + (data (i32.const 0) "a") +) + +(module + (global (import "spectest" "global_i32") i32) + (import "spectest" "memory" (memory 0)) + (data (get_global 0) "a") +) + +(module + (global (import "spectest" "global_i32") i32) + (import "spectest" "memory" (memory 0 3)) + (data (get_global 0) "a") +) + +(module + (import "spectest" "memory" (memory 0)) + (data (i32.const 1) "a") +) + +(module + (import "spectest" "memory" (memory 0 3)) + (data (i32.const 1) "a") +) + +;; Invalid bounds for data + +(assert_unlinkable + (module + (memory 0) + (data (i32.const 0) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 0 0) + (data (i32.const 0) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 0 1) + (data (i32.const 0) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 0) + (data (i32.const 1)) + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 0 1) + (data (i32.const 1)) + ) + "data segment does not fit" +) + +;; This seems to cause a time-out on Travis. +(;assert_unlinkable + (module + (memory 0x10000) + (data (i32.const 0xffffffff) "ab") + ) + "" ;; either out of memory or segment does not fit +;) + +(assert_unlinkable + (module + (global (import "spectest" "global_i32") i32) + (memory 0) + (data (get_global 0) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 1 2) + (data (i32.const 0x1_0000) "a") + ) + "data segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "memory" (memory 1)) + (data (i32.const 0x1_0000) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 2) + (data (i32.const 0x2_0000) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 2 3) + (data (i32.const 0x2_0000) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 1) + (data (i32.const -1) "a") + ) + "data segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "memory" (memory 1)) + (data (i32.const -1) "a") + ) + "data segment does not fit" +) + +(assert_unlinkable + (module + (memory 2) + (data (i32.const -100) "a") + ) + "data segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "memory" (memory 1)) + (data (i32.const -100) "a") + ) + "data segment does not fit" +) + +;; Data without memory + +(assert_invalid + (module + (data (i32.const 0) "") + ) + "unknown memory 0" +) + +;; Invalid offsets + +(assert_invalid + (module + (memory 1) + (data (i64.const 0)) + ) + "type mismatch" +) + +(assert_invalid + (module + (memory 1) + (data (i32.ctz (i32.const 0))) + ) + "constant expression required" +) + +(assert_invalid + (module + (memory 1) + (data (nop)) + ) + "constant expression required" +) + +(assert_invalid + (module + (memory 1) + (data (offset (nop) (i32.const 0))) + ) + "constant expression required" +) + +(assert_invalid + (module + (memory 1) + (data (offset (i32.const 0) (nop))) + ) + "constant expression required" +) + +;; Use of internal globals in constant expressions is not allowed in MVP. +;; (assert_invalid +;; (module (memory 1) (data (get_global $g)) (global $g (mut i32) (i32.const 0))) +;; "constant expression required" +;; ) diff --git a/test/core/elem.wast b/test/core/elem.wast index da28f3f95c..3c204c0734 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -1,15 +1,67 @@ ;; Test the element section +;; Syntax +(module + (table $t 10 anyfunc) + (func $f) + (elem (i32.const 0)) + (elem (i32.const 0) $f $f) + (elem (offset (i32.const 0))) + (elem (offset (i32.const 0)) $f $f) + (elem 0 (i32.const 0)) + (elem 0x0 (i32.const 0) $f $f) + (elem 0x000 (offset (i32.const 0))) + (elem 0 (offset (i32.const 0)) $f $f) + (elem $t (i32.const 0)) + (elem $t (i32.const 0) $f $f) + (elem $t (offset (i32.const 0))) + (elem $t (offset (i32.const 0)) $f $f) +) + +;; Basic use + (module (table 10 anyfunc) + (func $f) (elem (i32.const 0) $f) +) +(module + (import "spectest" "table" (table 10 anyfunc)) (func $f) + (elem (i32.const 0) $f) ) (module (table 10 anyfunc) + (func $f) + (elem (i32.const 0) $f) + (elem (i32.const 3) $f) + (elem (i32.const 7) $f) + (elem (i32.const 5) $f) + (elem (i32.const 3) $f) +) +(module + (import "spectest" "table" (table 10 anyfunc)) + (func $f) (elem (i32.const 9) $f) + (elem (i32.const 3) $f) + (elem (i32.const 7) $f) + (elem (i32.const 3) $f) + (elem (i32.const 5) $f) +) + +(module + (global (import "spectest" "global_i32") i32) + (table 1000 anyfunc) (func $f) + (elem (get_global 0) $f) +) + +(module + (global $g (import "spectest" "global_i32") i32) + (table 1000 anyfunc) + (func $f) + (elem (get_global $g) $f) ) (module @@ -26,128 +78,166 @@ (call_indirect (type $out-i32) (i32.const 9)) ) ) - (assert_return (invoke "call-7") (i32.const 65)) (assert_return (invoke "call-9") (i32.const 66)) -;; Two elements target the same slot +;; Corner cases (module - (type $out-i32 (func (result i32))) (table 10 anyfunc) - (elem (i32.const 9) $const-i32-a) - (elem (i32.const 9) $const-i32-b) - (func $const-i32-a (type $out-i32) (i32.const 65)) - (func $const-i32-b (type $out-i32) (i32.const 66)) - (func (export "call-overwritten-element") (type $out-i32) - (call_indirect (type $out-i32) (i32.const 9)) - ) + (func $f) + (elem (i32.const 9) $f) +) +(module + (import "spectest" "table" (table 10 anyfunc)) + (func $f) + (elem (i32.const 9) $f) ) -(assert_return (invoke "call-overwritten-element") (i32.const 66)) +(module + (table 0 anyfunc) + (elem (i32.const 0)) +) +(module + (import "spectest" "table" (table 0 anyfunc)) + (elem (i32.const 0)) +) + +(module + (table 0 0 anyfunc) + (elem (i32.const 0)) +) + +(module + (table 20 anyfunc) + (elem (i32.const 20)) +) + +(module + (import "spectest" "table" (table 0 anyfunc)) + (func $f) + (elem (i32.const 0) $f) +) + +(module + (import "spectest" "table" (table 0 100 anyfunc)) + (func $f) + (elem (i32.const 0) $f) +) + +(module + (import "spectest" "table" (table 0 anyfunc)) + (func $f) + (elem (i32.const 1) $f) +) + +(module + (import "spectest" "table" (table 0 30 anyfunc)) + (func $f) + (elem (i32.const 1) $f) +) ;; Invalid bounds for elements (assert_unlinkable (module - (table 10 anyfunc) - (elem (i32.const 10) $f) + (table 0 anyfunc) (func $f) + (elem (i32.const 0) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (table 10 20 anyfunc) - (elem (i32.const 10) $f) + (table 0 0 anyfunc) (func $f) + (elem (i32.const 0) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (table 10 anyfunc) - (elem (i32.const -1) $f) + (table 0 1 anyfunc) (func $f) + (elem (i32.const 0) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (table 10 anyfunc) - (elem (i32.const -10) $f) - (func $f) + (table 0 anyfunc) + (elem (i32.const 1)) ) "elements segment does not fit" ) -;; Tests with an imported table - -(module - (import "spectest" "table" (table 10 anyfunc)) - (elem (i32.const 0) $f) - (func $f) -) - -(module - (import "spectest" "table" (table 10 anyfunc)) - (elem (i32.const 9) $f) - (func $f) -) - -;; Two elements target the same slot - -(module - (type $out-i32 (func (result i32))) - (import "spectest" "table" (table 10 anyfunc)) - (elem (i32.const 9) $const-i32-a) - (elem (i32.const 9) $const-i32-b) - (func $const-i32-a (type $out-i32) (i32.const 65)) - (func $const-i32-b (type $out-i32) (i32.const 66)) - (func (export "call-overwritten-element") (type $out-i32) - (call_indirect (type $out-i32) (i32.const 9)) +(assert_unlinkable + (module + (table 10 anyfunc) + (func $f) + (elem (i32.const 10) $f) ) + "elements segment does not fit" ) - -(assert_return (invoke "call-overwritten-element") (i32.const 66)) - -;; Invalid bounds for elements - (assert_unlinkable (module - (import "spectest" "table" (table 10 anyfunc)) - (elem (i32.const 10) $f) + (import "spectest" "table" (table 10 anyfunc)) (func $f) + (elem (i32.const 10) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (import "spectest" "table" (table 10 20 anyfunc)) + (table 10 20 anyfunc) + (func $f) (elem (i32.const 10) $f) + ) + "elements segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) (func $f) + (elem (i32.const 10) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (import "spectest" "table" (table 10 anyfunc)) + (table 10 anyfunc) + (func $f) (elem (i32.const -1) $f) + ) + "elements segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) (func $f) + (elem (i32.const -1) $f) ) "elements segment does not fit" ) (assert_unlinkable (module - (import "spectest" "table" (table 10 anyfunc)) + (table 10 anyfunc) + (func $f) (elem (i32.const -10) $f) + ) + "elements segment does not fit" +) +(assert_unlinkable + (module + (import "spectest" "table" (table 10 anyfunc)) (func $f) + (elem (i32.const -10) $f) ) "elements segment does not fit" ) @@ -156,13 +246,89 @@ (assert_invalid (module - (elem (i32.const 0) $f) (func $f) + (elem (i32.const 0) $f) ) "unknown table 0" ) -;; Test element sections across multiple modules change the same table +;; Invalid offsets + +(assert_invalid + (module + (table 1 anyfunc) + (elem (i64.const 0)) + ) + "type mismatch" +) + +(assert_invalid + (module + (table 1 anyfunc) + (elem (i32.ctz (i32.const 0))) + ) + "constant expression required" +) + +(assert_invalid + (module + (table 1 anyfunc) + (elem (nop)) + ) + "constant expression required" +) + +(assert_invalid + (module + (table 1 anyfunc) + (elem (offset (nop) (i32.const 0))) + ) + "constant expression required" +) + +(assert_invalid + (module + (table 1 anyfunc) + (elem (offset (i32.const 0) (nop))) + ) + "constant expression required" +) + +;; Use of internal globals in constant expressions is not allowed in MVP. +;; (assert_invalid +;; (module (memory 1) (data (get_global $g)) (global $g (mut i32) (i32.const 0))) +;; "constant expression required" +;; ) + +;; Two elements target the same slot + +(module + (type $out-i32 (func (result i32))) + (table 10 anyfunc) + (elem (i32.const 9) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-overwritten") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 9)) + ) +) +(assert_return (invoke "call-overwritten") (i32.const 66)) + +(module + (type $out-i32 (func (result i32))) + (import "spectest" "table" (table 10 anyfunc)) + (elem (i32.const 9) $const-i32-a) + (elem (i32.const 9) $const-i32-b) + (func $const-i32-a (type $out-i32) (i32.const 65)) + (func $const-i32-b (type $out-i32) (i32.const 66)) + (func (export "call-overwritten-element") (type $out-i32) + (call_indirect (type $out-i32) (i32.const 9)) + ) +) +(assert_return (invoke "call-overwritten-element") (i32.const 66)) + +;; Element sections across multiple modules change the same table (module $module1 (type $out-i32 (func (result i32))) diff --git a/test/core/memory.wast b/test/core/memory.wast index ee39b3a043..c6f8cd5d4f 100644 --- a/test/core/memory.wast +++ b/test/core/memory.wast @@ -1,20 +1,9 @@ ;; Test memory section structure + (module (memory 0 0)) (module (memory 0 1)) (module (memory 1 256)) (module (memory 0 65536)) -(module (memory 0 0) (data (i32.const 0))) -(module (memory 0 0) (data (i32.const 0) "")) -(module (memory 1 1) (data (i32.const 0) "a")) -(module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 65535) "b")) -(module (memory 1 2) - (data (i32.const 0) "a") (data (i32.const 1) "b") (data (i32.const 2) "c") -) -(module (global (import "spectest" "global_i32") i32) (memory 1) (data (get_global 0) "a")) -(module (global $g (import "spectest" "global_i32") i32) (memory 1) (data (get_global $g) "a")) -;; Use of internal globals in constant expressions is not allowed in MVP. -;; (module (memory 1) (data (get_global 0) "a") (global i32 (i32.const 0))) -;; (module (memory 1) (data (get_global $g) "a") (global $g i32 (i32.const 0))) (assert_invalid (module (memory 0) (memory 0)) "multiple memories") (assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories") @@ -55,77 +44,6 @@ "unknown memory" ) -(assert_invalid - (module (memory 1) (data (i64.const 0))) - "type mismatch" -) -(assert_invalid - (module (memory 1) (data (i32.ctz (i32.const 0)))) - "constant expression required" -) -(assert_invalid - (module (memory 1) (data (nop))) - "constant expression required" -) -;; Use of internal globals in constant expressions is not allowed in MVP. -;; (assert_invalid -;; (module (memory 1) (data (get_global $g)) (global $g (mut i32) (i32.const 0))) -;; "constant expression required" -;; ) - -(assert_unlinkable - (module (memory 0 0) (data (i32.const 0) "a")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 0 1) (data (i32.const 0) "a")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 1 2) (data (i32.const -1) "a")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 1 2) (data (i32.const -1000) "a")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 0 0) (data (i32.const 1) "")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 1) (data (i32.const 0x12000) "")) - "data segment does not fit" -) -(assert_unlinkable - (module (memory 1 2) (data (i32.const -1) "")) - "data segment does not fit" -) -;; This seems to cause a time-out on Travis. -(;assert_unlinkable - (module (memory 0x10000) (data (i32.const 0xffffffff) "ab")) - "" ;; either out of memory or segment does not fit -;) -(assert_unlinkable - (module - (global (import "spectest" "global_i32") i32) - (memory 0) (data (get_global 0) "a") - ) - "data segment does not fit" -) - -(module (memory 0 0) (data (i32.const 0) "")) -(module (memory 1 1) (data (i32.const 0x10000) "")) -(module (memory 1 2) (data (i32.const 0) "abc") (data (i32.const 0) "def")) -(module (memory 1 2) (data (i32.const 3) "ab") (data (i32.const 0) "de")) -(module - (memory 1 2) - (data (i32.const 0) "a") (data (i32.const 2) "b") (data (i32.const 1) "c") -) (assert_invalid (module (memory 1 0))