summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-03-13 09:29:38 -0700
committerGitHub <noreply@github.com>2018-03-13 09:29:38 -0700
commitd52213c3f5e96bb3450721d96aa68d3c5e0865b6 (patch)
treec585377fb842da0c4b87657f5047272196af9e6c /test
parent0008b795d11d65d0759c3c0a71ee74b536f1ecf8 (diff)
downloadbinaryen-d52213c3f5e96bb3450721d96aa68d3c5e0865b6.tar.gz
binaryen-d52213c3f5e96bb3450721d96aa68d3c5e0865b6.tar.bz2
binaryen-d52213c3f5e96bb3450721d96aa68d3c5e0865b6.zip
Function pointer cast emulation (#1468)
This adds a pass that implements "function pointer cast emulation" - allows indirect calls to go through even if the number of arguments or their types is incorrect. That is undefined behavior in C/C++ but in practice somehow works in native archs. It is even relied upon in e.g. Python. Emscripten already has such emulation for asm.js, which also worked for asm2wasm. This implements something like it in binaryen which also allows the wasm backend to use it. As a result, Python should now be portable using the wasm backend. The mechanism used for the emulation is to make all indirect calls use a fixed number of arguments, all of type i64, and a return type of also i64. Thunks are then placed in the table which translate the arguments properly for the target, basically by reinterpreting to i64 and back. As a result, receiving an i64 when an i32 is sent will have the upper bits all zero, and the reverse would truncate the upper bits, etc. (Note that this is different than emscripten's existing emulation, which converts (as signed) to a double. That makes sense for JS where double's can contain all numeric values, but in wasm we have i64s. Also, bitwise conversion may be more like what native archs do anyhow. It is enough for Python.) Also adds validation for a function's type matching the function's actual params and result (surprised we didn't have that before, but we didn't, and there was even a place in the test suite where that was wrong). Also simplifies the build script by moving two cpp files into the wasm/ subdir, so they can be built once and shared between the various tools.
Diffstat (limited to 'test')
-rw-r--r--test/passes/dce.txt6
-rw-r--r--test/passes/dce.wast6
-rw-r--r--test/passes/fpcast-emu.txt294
-rw-r--r--test/passes/fpcast-emu.wast48
4 files changed, 348 insertions, 6 deletions
diff --git a/test/passes/dce.txt b/test/passes/dce.txt
index 6f2422b2a..b2976432b 100644
--- a/test/passes/dce.txt
+++ b/test/passes/dce.txt
@@ -322,7 +322,7 @@
(unreachable)
)
)
- (func $unreachable-block-ends-br_if (; 11 ;) (type $1) (result i32)
+ (func $unreachable-block-ends-br_if (; 11 ;) (type $2) (result i32)
(block $label$2
(nop)
(unreachable)
@@ -377,13 +377,13 @@
)
)
)
- (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (; 15 ;) (type $1) (param $var$0 i32) (result i32)
+ (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (; 15 ;) (type $3) (param $var$0 i32) (result i32)
(block $block
(nop)
(unreachable)
)
)
- (func $br-with-unreachable-value-should-not-give-a-block-a-value (; 16 ;) (type $1) (param $var$0 i32) (result i32)
+ (func $br-with-unreachable-value-should-not-give-a-block-a-value (; 16 ;) (type $3) (param $var$0 i32) (result i32)
(block $label$0 (result i32)
(block $block
(drop
diff --git a/test/passes/dce.wast b/test/passes/dce.wast
index 93c98ce4d..18f7db012 100644
--- a/test/passes/dce.wast
+++ b/test/passes/dce.wast
@@ -466,7 +466,7 @@
(i32.const 19)
)
)
- (func $unreachable-block-ends-br_if (type $1) (result i32)
+ (func $unreachable-block-ends-br_if (result i32)
(block $label$0 (result i32)
(block $label$2
(nop)
@@ -538,7 +538,7 @@
)
)
)
- (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (type $1) (param $var$0 i32) (result i32)
+ (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (param $var$0 i32) (result i32)
(block $label$0 (result i32)
(br $label$0
(block (result i32)
@@ -554,7 +554,7 @@
)
)
)
- (func $br-with-unreachable-value-should-not-give-a-block-a-value (type $1) (param $var$0 i32) (result i32)
+ (func $br-with-unreachable-value-should-not-give-a-block-a-value (param $var$0 i32) (result i32)
(block $label$0 (result i32)
(br $label$0
(block (result i32) ;; turns into unreachable when refinalized
diff --git a/test/passes/fpcast-emu.txt b/test/passes/fpcast-emu.txt
new file mode 100644
index 000000000..94b92ad17
--- /dev/null
+++ b/test/passes/fpcast-emu.txt
@@ -0,0 +1,294 @@
+(module
+ (type $vijfd (func (param i32 i64 f32 f64)))
+ (type $jii (func (param i32 i32) (result i64)))
+ (type $fjj (func (param i64 i64) (result f32)))
+ (type $dff (func (param f32 f32) (result f64)))
+ (type $idd (func (param f64 f64) (result i32)))
+ (type $FUNCSIG$fijfd (func (param i32 i64 f32 f64) (result f32)))
+ (type $FUNCSIG$jjjjjjjjjjjjjjjj (func (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) (result i64)))
+ (type $FUNCSIG$vijfd (func (param i32 i64 f32 f64)))
+ (type $FUNCSIG$jii (func (param i32 i32) (result i64)))
+ (type $FUNCSIG$fjj (func (param i64 i64) (result f32)))
+ (type $FUNCSIG$dff (func (param f32 f32) (result f64)))
+ (type $FUNCSIG$idd (func (param f64 f64) (result i32)))
+ (import "env" "imported_func" (func $imported-func (param i32 i64 f32 f64) (result f32)))
+ (table 10 10 anyfunc)
+ (elem (i32.const 0) $byn$fpcast-emu$a $byn$fpcast-emu$b $byn$fpcast-emu$c $byn$fpcast-emu$d $byn$fpcast-emu$e $byn$fpcast-emu$e $byn$fpcast-emu$imported-func)
+ (export "dynCall_dff" (func $dynCall_dff))
+ (export "dynCall_idd" (func $dynCall_idd))
+ (func $a (; 1 ;) (type $vijfd) (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+ (drop
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.extend_u/i32
+ (i32.const 1)
+ )
+ (i64.const 2)
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (f32.const 3)
+ )
+ )
+ (i64.reinterpret/f64
+ (f64.const 4)
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i32.const 1337)
+ )
+ )
+ )
+ (func $b (; 2 ;) (type $jii) (param $x i32) (param $y i32) (result i64)
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.extend_u/i32
+ (i32.const 1)
+ )
+ (i64.extend_u/i32
+ (i32.const 2)
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i32.const 1337)
+ )
+ )
+ (func $c (; 3 ;) (type $fjj) (param $x i64) (param $y i64) (result f32)
+ (f32.reinterpret/i32
+ (i32.wrap/i64
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.const 1)
+ (i64.const 2)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i32.const 1337)
+ )
+ )
+ )
+ )
+ (func $d (; 4 ;) (type $dff) (param $x f32) (param $y f32) (result f64)
+ (f64.reinterpret/i64
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (f32.const 1)
+ )
+ )
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (f32.const 2)
+ )
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i32.const 1337)
+ )
+ )
+ )
+ (func $e (; 5 ;) (type $idd) (param $x f64) (param $y f64) (result i32)
+ (i32.wrap/i64
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.reinterpret/f64
+ (f64.const 1)
+ )
+ (i64.reinterpret/f64
+ (f64.const 2)
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i32.const 1337)
+ )
+ )
+ )
+ (func $dynCall_dff (; 6 ;) (param $fptr i32) (param $0 f32) (param $1 f32) (result f64)
+ (f64.reinterpret/i64
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (get_local $0)
+ )
+ )
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (get_local $1)
+ )
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (get_local $fptr)
+ )
+ )
+ )
+ (func $dynCall_idd (; 7 ;) (param $fptr i32) (param $0 f64) (param $1 f64) (result i32)
+ (i32.wrap/i64
+ (call_indirect (type $FUNCSIG$jjjjjjjjjjjjjjjj)
+ (i64.reinterpret/f64
+ (get_local $0)
+ )
+ (i64.reinterpret/f64
+ (get_local $1)
+ )
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (i64.const 0)
+ (get_local $fptr)
+ )
+ )
+ )
+ (func $byn$fpcast-emu$a (; 8 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (call $a
+ (i32.wrap/i64
+ (get_local $0)
+ )
+ (get_local $1)
+ (f32.reinterpret/i32
+ (i32.wrap/i64
+ (get_local $2)
+ )
+ )
+ (f64.reinterpret/i64
+ (get_local $3)
+ )
+ )
+ (i64.const 0)
+ )
+ (func $byn$fpcast-emu$b (; 9 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (call $b
+ (i32.wrap/i64
+ (get_local $0)
+ )
+ (i32.wrap/i64
+ (get_local $1)
+ )
+ )
+ )
+ (func $byn$fpcast-emu$c (; 10 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (call $c
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+ )
+ )
+ (func $byn$fpcast-emu$d (; 11 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (i64.reinterpret/f64
+ (call $d
+ (f32.reinterpret/i32
+ (i32.wrap/i64
+ (get_local $0)
+ )
+ )
+ (f32.reinterpret/i32
+ (i32.wrap/i64
+ (get_local $1)
+ )
+ )
+ )
+ )
+ )
+ (func $byn$fpcast-emu$e (; 12 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (i64.extend_u/i32
+ (call $e
+ (f64.reinterpret/i64
+ (get_local $0)
+ )
+ (f64.reinterpret/i64
+ (get_local $1)
+ )
+ )
+ )
+ )
+ (func $byn$fpcast-emu$imported-func (; 13 ;) (type $FUNCSIG$jjjjjjjjjjjjjjjj) (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i64) (param $6 i64) (param $7 i64) (param $8 i64) (param $9 i64) (param $10 i64) (param $11 i64) (param $12 i64) (param $13 i64) (param $14 i64) (result i64)
+ (i64.extend_u/i32
+ (i32.reinterpret/f32
+ (call $imported-func
+ (i32.wrap/i64
+ (get_local $0)
+ )
+ (get_local $1)
+ (f32.reinterpret/i32
+ (i32.wrap/i64
+ (get_local $2)
+ )
+ )
+ (f64.reinterpret/i64
+ (get_local $3)
+ )
+ )
+ )
+ )
+ )
+)
diff --git a/test/passes/fpcast-emu.wast b/test/passes/fpcast-emu.wast
new file mode 100644
index 000000000..cef0d0deb
--- /dev/null
+++ b/test/passes/fpcast-emu.wast
@@ -0,0 +1,48 @@
+(module
+ (type $vijfd (func (param i32) (param i64) (param f32) (param f64)))
+ (type $jii (func (param i32) (param i32) (result i64)))
+ (type $fjj (func (param i64) (param i64) (result f32)))
+ (type $dff (func (param f32) (param f32) (result f64)))
+ (type $idd (func (param f64) (param f64) (result i32)))
+ (import "env" "imported_func" (func $imported-func (param i32 i64 f32 f64) (result f32)))
+ (table 10 10 anyfunc)
+ (elem (i32.const 0) $a $b $c $d $e $e $imported-func)
+ (func $a (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+ (call_indirect (type $vijfd)
+ (i32.const 1)
+ (i64.const 2)
+ (f32.const 3)
+ (f64.const 4)
+ (i32.const 1337)
+ )
+ )
+ (func $b (param $x i32) (param $y i32) (result i64)
+ (call_indirect (type $jii)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 1337)
+ )
+ )
+ (func $c (param $x i64) (param $y i64) (result f32)
+ (call_indirect (type $fjj)
+ (i64.const 1)
+ (i64.const 2)
+ (i32.const 1337)
+ )
+ )
+ (func $d (param $x f32) (param $y f32) (result f64)
+ (call_indirect (type $dff)
+ (f32.const 1)
+ (f32.const 2)
+ (i32.const 1337)
+ )
+ )
+ (func $e (param $x f64) (param $y f64) (result i32)
+ (call_indirect (type $idd)
+ (f64.const 1)
+ (f64.const 2)
+ (i32.const 1337)
+ )
+ )
+)
+