diff options
author | Derek Schuff <dschuff@chromium.org> | 2016-06-02 14:30:30 -0700 |
---|---|---|
committer | Derek Schuff <dschuff@chromium.org> | 2016-06-02 14:30:30 -0700 |
commit | d4dc216888d5028f41e6189e65001694e49a66c2 (patch) | |
tree | 35ac5962bedb07fa732b34b62f7b7c3d68280ce4 /test | |
parent | d595e89003dc3636952de4c561679e3a077e6015 (diff) | |
download | binaryen-d4dc216888d5028f41e6189e65001694e49a66c2.tar.gz binaryen-d4dc216888d5028f41e6189e65001694e49a66c2.tar.bz2 binaryen-d4dc216888d5028f41e6189e65001694e49a66c2.zip |
Generate thunks for address-taken imports (#554)
Under emscripten, C code can take the address of a function implemented
in Javascript (which is exposed via an import in wasm). Because imports
do not have linear memory address in wasm, we need to generate a thunk
to be the target of the indirect call; it call the import directly.
This is facilited by a new .s directive (.functype) which declares the
types of functions which are declared but not defined.
Fixes https://github.com/WebAssembly/binaryen/issues/392
Diffstat (limited to 'test')
-rw-r--r-- | test/dot_s/indirect-import.c | 27 | ||||
-rw-r--r-- | test/dot_s/indirect-import.s | 55 | ||||
-rw-r--r-- | test/dot_s/indirect-import.wast | 147 |
3 files changed, 229 insertions, 0 deletions
diff --git a/test/dot_s/indirect-import.c b/test/dot_s/indirect-import.c new file mode 100644 index 000000000..006424d84 --- /dev/null +++ b/test/dot_s/indirect-import.c @@ -0,0 +1,27 @@ +#include <stdint.h> + +struct big { + float a; + double b; + int32_t c; +}; + +float extern_fd(double); +void extern_vj(uint64_t); +void extern_v(void); +int32_t extern_ijidf(int64_t, int32_t, double, float); +void extern_struct(struct big); +struct big extern_sret(void); + +intptr_t bar() { + float (*fd)(double) = &extern_fd; + void (*vj)(uint64_t) = &extern_vj; + vj(1ULL); + void (*v)(void) = &extern_v; + v(); + int32_t (*ijidf)(int64_t, int32_t, double, float) = &extern_ijidf; + ijidf(1LL, 2, 3.0, 4.0f); + void (*vs)(struct big) = &extern_struct; + struct big (*s)(void) = &extern_sret; + return (intptr_t)fd; +} diff --git a/test/dot_s/indirect-import.s b/test/dot_s/indirect-import.s new file mode 100644 index 000000000..5131d86f3 --- /dev/null +++ b/test/dot_s/indirect-import.s @@ -0,0 +1,55 @@ + .text + .file "indirect-import.ll" + .hidden bar + .globl bar + .type bar,@function +bar: # @bar + .result i32 + .local i32, i32 +# BB#0: # %entry + i32.const $push13=, 0 + i32.const $push10=, 0 + i32.load $push11=, __stack_pointer($pop10) + i32.const $push12=, 32 + i32.sub $push17=, $pop11, $pop12 + i32.store $push20=, __stack_pointer($pop13), $pop17 + tee_local $push19=, $0=, $pop20 + i32.const $push0=, extern_fd@FUNCTION + i32.store $drop=, 28($pop19), $pop0 + i32.const $push1=, extern_vj@FUNCTION + i32.store $drop=, 24($0), $pop1 + i64.const $push2=, 1 + call extern_vj@FUNCTION, $pop2 + i32.const $push3=, extern_v@FUNCTION + i32.store $drop=, 20($0), $pop3 + call extern_v@FUNCTION + i32.const $push4=, extern_ijidf@FUNCTION + i32.store $drop=, 16($0), $pop4 + i64.const $push18=, 1 + i32.const $push7=, 2 + f64.const $push6=, 0x1.8p1 + f32.const $push5=, 0x1p2 + i32.call $drop=, extern_ijidf@FUNCTION, $pop18, $pop7, $pop6, $pop5 + i32.const $push8=, extern_struct@FUNCTION + i32.store $drop=, 12($0), $pop8 + i32.const $push9=, extern_sret@FUNCTION + i32.store $drop=, 8($0), $pop9 + i32.load $1=, 28($0) + i32.const $push16=, 0 + i32.const $push14=, 32 + i32.add $push15=, $0, $pop14 + i32.store $drop=, __stack_pointer($pop16), $pop15 + copy_local $push21=, $1 + # fallthrough-return: $pop21 + .endfunc +.Lfunc_end0: + .size bar, .Lfunc_end0-bar + + + .ident "clang version 3.9.0 (trunk 271427) (llvm/trunk 271429)" + .functype extern_fd, f32, f64 + .functype extern_vj, void, i64 + .functype extern_v, void + .functype extern_ijidf, i32, i64, i32, f64, f32 + .functype extern_struct, void, i32 + .functype extern_sret, void, i32 diff --git a/test/dot_s/indirect-import.wast b/test/dot_s/indirect-import.wast new file mode 100644 index 000000000..8ffeea168 --- /dev/null +++ b/test/dot_s/indirect-import.wast @@ -0,0 +1,147 @@ +(module + (memory 1) + (export "memory" memory) + (type $FUNCSIG$ijidf (func (param i64 i32 f64 f32) (result i32))) + (type $FUNCSIG$v (func)) + (type $FUNCSIG$vj (func (param i64))) + (type $FUNCSIG$fd (func (param f64) (result f32))) + (type $FUNCSIG$vi (func (param i32))) + (import $extern_ijidf "env" "extern_ijidf" (param i64 i32 f64 f32) (result i32)) + (import $extern_v "env" "extern_v") + (import $extern_vj "env" "extern_vj" (param i64)) + (import $extern_fd "env" "extern_fd" (param f64) (result f32)) + (import $extern_struct "env" "extern_struct" (param i32)) + (import $extern_sret "env" "extern_sret" (param i32)) + (export "bar" $bar) + (export "dynCall_fd" $dynCall_fd) + (export "dynCall_vj" $dynCall_vj) + (export "dynCall_v" $dynCall_v) + (export "dynCall_ijidf" $dynCall_ijidf) + (export "dynCall_vi" $dynCall_vi) + (table $__importThunk_extern_fd $__importThunk_extern_vj $__importThunk_extern_v $__importThunk_extern_ijidf $__importThunk_extern_struct $__importThunk_extern_sret) + (func $bar (result i32) + (local $0 i32) + (local $1 i32) + (i32.store offset=28 + (set_local $0 + (i32.store offset=4 + (i32.const 0) + (i32.sub + (i32.load offset=4 + (i32.const 0) + ) + (i32.const 32) + ) + ) + ) + (i32.const 0) + ) + (i32.store offset=24 + (get_local $0) + (i32.const 1) + ) + (call_import $extern_vj + (i64.const 1) + ) + (i32.store offset=20 + (get_local $0) + (i32.const 2) + ) + (call_import $extern_v) + (i32.store offset=16 + (get_local $0) + (i32.const 3) + ) + (call_import $extern_ijidf + (i64.const 1) + (i32.const 2) + (f64.const 3) + (f32.const 4) + ) + (i32.store offset=12 + (get_local $0) + (i32.const 4) + ) + (i32.store offset=8 + (get_local $0) + (i32.const 5) + ) + (set_local $1 + (i32.load offset=28 + (get_local $0) + ) + ) + (i32.store offset=4 + (i32.const 0) + (i32.add + (get_local $0) + (i32.const 32) + ) + ) + (get_local $1) + ) + (func $__importThunk_extern_fd (type $FUNCSIG$fd) (param $0 f64) (result f32) + (call_import $extern_fd + (get_local $0) + ) + ) + (func $__importThunk_extern_vj (type $FUNCSIG$vj) (param $0 i64) + (call_import $extern_vj + (get_local $0) + ) + ) + (func $__importThunk_extern_v (type $FUNCSIG$v) + (call_import $extern_v) + ) + (func $__importThunk_extern_ijidf (type $FUNCSIG$ijidf) (param $0 i64) (param $1 i32) (param $2 f64) (param $3 f32) (result i32) + (call_import $extern_ijidf + (get_local $0) + (get_local $1) + (get_local $2) + (get_local $3) + ) + ) + (func $__importThunk_extern_struct (type $FUNCSIG$vi) (param $0 i32) + (call_import $extern_struct + (get_local $0) + ) + ) + (func $__importThunk_extern_sret (type $FUNCSIG$vi) (param $0 i32) + (call_import $extern_sret + (get_local $0) + ) + ) + (func $dynCall_fd (param $fptr i32) (param $0 f64) (result f32) + (call_indirect $FUNCSIG$fd + (get_local $fptr) + (get_local $0) + ) + ) + (func $dynCall_vj (param $fptr i32) (param $0 i64) + (call_indirect $FUNCSIG$vj + (get_local $fptr) + (get_local $0) + ) + ) + (func $dynCall_v (param $fptr i32) + (call_indirect $FUNCSIG$v + (get_local $fptr) + ) + ) + (func $dynCall_ijidf (param $fptr i32) (param $0 i64) (param $1 i32) (param $2 f64) (param $3 f32) (result i32) + (call_indirect $FUNCSIG$ijidf + (get_local $fptr) + (get_local $0) + (get_local $1) + (get_local $2) + (get_local $3) + ) + ) + (func $dynCall_vi (param $fptr i32) (param $0 i32) + (call_indirect $FUNCSIG$vi + (get_local $fptr) + (get_local $0) + ) + ) +) +;; METADATA: { "asmConsts": {},"staticBump": 12, "initializers": [] } |