mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 16:20:49 +00:00
Merge #334
334: Added longjmp implementation r=syrusakbary a=syrusakbary Added longjmp implementation Co-authored-by: Syrus <me@syrusakbary.com> Co-authored-by: Mark McCaskey <mark@wasmer.io> Co-authored-by: Lachlan Sneff <lachlan.sneff@gmail.com>
This commit is contained in:
commit
72b9939331
.circleci
Makefileexamples
lib
@ -274,7 +274,7 @@ jobs:
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
make test
|
||||
make test-nightly
|
||||
make test-emscripten
|
||||
make test-emscripten-clif
|
||||
# make test-emscripten-nightly
|
||||
- save_cache:
|
||||
paths:
|
||||
|
3
Makefile
3
Makefile
@ -48,6 +48,9 @@ test-emscripten:
|
||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
||||
|
||||
test-emscripten-clif:
|
||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
||||
|
||||
test-emscripten-nightly:
|
||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features dynasm -- --test-threads=1 $(runargs)
|
||||
|
||||
|
Binary file not shown.
@ -30,4 +30,5 @@ glob = "0.2.11"
|
||||
[features]
|
||||
clif = []
|
||||
llvm = ["wasmer-llvm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
|
9
lib/emscripten/emtests/ignores.txt
vendored
9
lib/emscripten/emtests/ignores.txt
vendored
@ -30,16 +30,7 @@ test_i64
|
||||
test_i64_7z
|
||||
test_i64_varargs
|
||||
test_llvm_intrinsics
|
||||
test_longjmp2
|
||||
test_longjmp3
|
||||
test_longjmp4
|
||||
test_longjmp
|
||||
test_longjmp_exc
|
||||
test_longjmp_funcptr
|
||||
test_longjmp_repeat
|
||||
test_longjmp_stacked
|
||||
test_longjmp_throw
|
||||
test_longjmp_unwind
|
||||
test_lower_intrinsics
|
||||
test_main_thread_async_em_asm
|
||||
test_mainenv
|
||||
|
@ -15,78 +15,6 @@ pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
|
||||
get_emscripten_data(ctx).temp_ret_0
|
||||
}
|
||||
|
||||
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
|
||||
debug!("emscripten::invoke_i");
|
||||
if let Some(dyn_call_i) = &get_emscripten_data(ctx).dyn_call_i {
|
||||
dyn_call_i.call(index).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_i is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
|
||||
debug!("emscripten::invoke_ii");
|
||||
if let Some(dyn_call_ii) = &get_emscripten_data(ctx).dyn_call_ii {
|
||||
dyn_call_ii.call(index, a1).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_ii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iii");
|
||||
if let Some(dyn_call_iii) = &get_emscripten_data(ctx).dyn_call_iii {
|
||||
dyn_call_iii.call(index, a1, a2).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iiii");
|
||||
if let Some(dyn_call_iiii) = &get_emscripten_data(ctx).dyn_call_iiii {
|
||||
dyn_call_iiii.call(index, a1, a2, a3).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_v(ctx: &mut Ctx, index: i32) {
|
||||
debug!("emscripten::invoke_v");
|
||||
if let Some(dyn_call_v) = &get_emscripten_data(ctx).dyn_call_v {
|
||||
dyn_call_v.call(index).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_v is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
|
||||
debug!("emscripten::invoke_vi");
|
||||
if let Some(dyn_call_vi) = &get_emscripten_data(ctx).dyn_call_vi {
|
||||
dyn_call_vi.call(index, a1).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_vi is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
|
||||
debug!("emscripten::invoke_vii");
|
||||
if let Some(dyn_call_vii) = &get_emscripten_data(ctx).dyn_call_vii {
|
||||
dyn_call_vii.call(index, a1, a2).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_vii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
|
||||
debug!("emscripten::invoke_viii");
|
||||
if let Some(dyn_call_viii) = &get_emscripten_data(ctx).dyn_call_viii {
|
||||
dyn_call_viii.call(index, a1, a2, a3).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
|
||||
debug!("emscripten::invoke_viiii");
|
||||
if let Some(dyn_call_viiii) = &get_emscripten_data(ctx).dyn_call_viiii {
|
||||
dyn_call_viiii.call(index, a1, a2, a3, a4).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiii is set to None");
|
||||
}
|
||||
}
|
||||
pub fn __Unwind_Backtrace(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
||||
debug!("emscripten::__Unwind_Backtrace");
|
||||
0
|
||||
@ -244,29 +172,92 @@ pub fn _getloadavg(_ctx: &mut Ctx, _loadavg: i32, _nelem: i32) -> i32 {
|
||||
debug!("emscripten::getloadavg");
|
||||
0
|
||||
}
|
||||
|
||||
// Invoke functions
|
||||
// They save the stack to allow unwinding
|
||||
|
||||
// Macro definitions
|
||||
macro_rules! invoke {
|
||||
($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
|
||||
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
|
||||
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
|
||||
match result {
|
||||
Ok(v) => v,
|
||||
Err(_e) => {
|
||||
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
|
||||
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
|
||||
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
|
||||
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
|
||||
0 as _
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
macro_rules! invoke_no_return {
|
||||
($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
|
||||
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
|
||||
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
|
||||
match result {
|
||||
Ok(v) => v,
|
||||
Err(_e) => {
|
||||
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
|
||||
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
|
||||
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
|
||||
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// Invoke functions
|
||||
pub fn invoke_i(ctx: &mut Ctx, index: i32) -> i32 {
|
||||
debug!("emscripten::invoke_i");
|
||||
invoke!(ctx, dyn_call_i, index)
|
||||
}
|
||||
pub fn invoke_ii(ctx: &mut Ctx, index: i32, a1: i32) -> i32 {
|
||||
debug!("emscripten::invoke_ii");
|
||||
invoke!(ctx, dyn_call_ii, index, a1)
|
||||
}
|
||||
pub fn invoke_iii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iii");
|
||||
invoke!(ctx, dyn_call_iii, index, a1, a2)
|
||||
}
|
||||
pub fn invoke_iiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iiii");
|
||||
invoke!(ctx, dyn_call_iiii, index, a1, a2, a3)
|
||||
}
|
||||
pub fn invoke_v(ctx: &mut Ctx, index: i32) {
|
||||
debug!("emscripten::invoke_v");
|
||||
invoke_no_return!(ctx, dyn_call_v, index);
|
||||
}
|
||||
pub fn invoke_vi(ctx: &mut Ctx, index: i32, a1: i32) {
|
||||
debug!("emscripten::invoke_vi");
|
||||
invoke_no_return!(ctx, dyn_call_vi, index, a1);
|
||||
}
|
||||
pub fn invoke_vii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
|
||||
debug!("emscripten::invoke_vii");
|
||||
invoke_no_return!(ctx, dyn_call_vii, index, a1, a2);
|
||||
}
|
||||
|
||||
pub fn invoke_viii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
|
||||
debug!("emscripten::invoke_viii");
|
||||
invoke_no_return!(ctx, dyn_call_viii, index, a1, a2, a3);
|
||||
}
|
||||
pub fn invoke_viiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
|
||||
debug!("emscripten::invoke_viiii");
|
||||
invoke_no_return!(ctx, dyn_call_viiii, index, a1, a2, a3, a4);
|
||||
}
|
||||
pub fn invoke_dii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) -> f64 {
|
||||
debug!("emscripten::invoke_dii");
|
||||
if let Some(dyn_call_dii) = &get_emscripten_data(ctx).dyn_call_dii {
|
||||
dyn_call_dii.call(index, a1, a2).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_dii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_dii, index, a1, a2)
|
||||
}
|
||||
pub fn invoke_diiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 {
|
||||
debug!("emscripten::invoke_diiii");
|
||||
if let Some(dyn_call_diiii) = &get_emscripten_data(ctx).dyn_call_diiii {
|
||||
dyn_call_diiii.call(index, a1, a2, a3, a4).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_diiii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_diiii, index, a1, a2, a3, a4)
|
||||
}
|
||||
pub fn invoke_iiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
|
||||
debug!("emscripten::invoke_iiiii");
|
||||
if let Some(dyn_call_iiiii) = &get_emscripten_data(ctx).dyn_call_iiiii {
|
||||
dyn_call_iiiii.call(index, a1, a2, a3, a4).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiiii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_iiiii, index, a1, a2, a3, a4)
|
||||
}
|
||||
pub fn invoke_iiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -278,11 +269,7 @@ pub fn invoke_iiiiii(
|
||||
a5: i32,
|
||||
) -> i32 {
|
||||
debug!("emscripten::invoke_iiiiii");
|
||||
if let Some(dyn_call_iiiiii) = &get_emscripten_data(ctx).dyn_call_iiiiii {
|
||||
dyn_call_iiiiii.call(index, a1, a2, a3, a4, a5).unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiiiii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_iiiiii, index, a1, a2, a3, a4, a5)
|
||||
}
|
||||
pub fn invoke_iiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -295,13 +282,7 @@ pub fn invoke_iiiiiii(
|
||||
a6: i32,
|
||||
) -> i32 {
|
||||
debug!("emscripten::invoke_iiiiiii");
|
||||
if let Some(dyn_call_iiiiiii) = &get_emscripten_data(ctx).dyn_call_iiiiiii {
|
||||
dyn_call_iiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6)
|
||||
.unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiiiiii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_iiiiiii, index, a1, a2, a3, a4, a5, a6)
|
||||
}
|
||||
pub fn invoke_iiiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -315,13 +296,7 @@ pub fn invoke_iiiiiiii(
|
||||
a7: i32,
|
||||
) -> i32 {
|
||||
debug!("emscripten::invoke_iiiiiiii");
|
||||
if let Some(dyn_call_iiiiiiii) = &get_emscripten_data(ctx).dyn_call_iiiiiiii {
|
||||
dyn_call_iiiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7)
|
||||
.unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiiiiiii is set to None");
|
||||
}
|
||||
invoke!(ctx, dyn_call_iiiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
|
||||
}
|
||||
pub fn invoke_iiiiiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -337,29 +312,28 @@ pub fn invoke_iiiiiiiiii(
|
||||
a9: i32,
|
||||
) -> i32 {
|
||||
debug!("emscripten::invoke_iiiiiiiiii");
|
||||
if let Some(dyn_call_iiiiiiiiii) = &get_emscripten_data(ctx).dyn_call_iiiiiiiiii {
|
||||
dyn_call_iiiiiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
.unwrap()
|
||||
} else {
|
||||
panic!("dyn_call_iiiiiiiiii is set to None");
|
||||
}
|
||||
invoke!(
|
||||
ctx,
|
||||
dyn_call_iiiiiiiiii,
|
||||
index,
|
||||
a1,
|
||||
a2,
|
||||
a3,
|
||||
a4,
|
||||
a5,
|
||||
a6,
|
||||
a7,
|
||||
a8,
|
||||
a9
|
||||
)
|
||||
}
|
||||
pub fn invoke_vd(ctx: &mut Ctx, index: i32, a1: f64) {
|
||||
debug!("emscripten::invoke_vd");
|
||||
if let Some(dyn_call_vd) = &get_emscripten_data(ctx).dyn_call_vd {
|
||||
dyn_call_vd.call(index, a1).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_vd is set to None");
|
||||
}
|
||||
invoke_no_return!(ctx, dyn_call_vd, index, a1)
|
||||
}
|
||||
pub fn invoke_viiiii(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
|
||||
debug!("emscripten::invoke_viiiii");
|
||||
if let Some(dyn_call_viiiii) = &get_emscripten_data(ctx).dyn_call_viiiii {
|
||||
dyn_call_viiiii.call(index, a1, a2, a3, a4, a5).unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(ctx, dyn_call_viiiii, index, a1, a2, a3, a4, a5)
|
||||
}
|
||||
pub fn invoke_viiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -372,13 +346,7 @@ pub fn invoke_viiiiii(
|
||||
a6: i32,
|
||||
) {
|
||||
debug!("emscripten::invoke_viiiiii");
|
||||
if let Some(dyn_call_viiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiii {
|
||||
dyn_call_viiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(ctx, dyn_call_viiiiii, index, a1, a2, a3, a4, a5, a6)
|
||||
}
|
||||
pub fn invoke_viiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -392,13 +360,7 @@ pub fn invoke_viiiiiii(
|
||||
a7: i32,
|
||||
) {
|
||||
debug!("emscripten::invoke_viiiiiii");
|
||||
if let Some(dyn_call_viiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiii {
|
||||
dyn_call_viiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(ctx, dyn_call_viiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
|
||||
}
|
||||
pub fn invoke_viiiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -413,13 +375,19 @@ pub fn invoke_viiiiiiii(
|
||||
a8: i32,
|
||||
) {
|
||||
debug!("emscripten::invoke_viiiiiiii");
|
||||
if let Some(dyn_call_viiiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiiii {
|
||||
dyn_call_viiiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7, a8)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiiiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(
|
||||
ctx,
|
||||
dyn_call_viiiiiiii,
|
||||
index,
|
||||
a1,
|
||||
a2,
|
||||
a3,
|
||||
a4,
|
||||
a5,
|
||||
a6,
|
||||
a7,
|
||||
a8
|
||||
)
|
||||
}
|
||||
pub fn invoke_viiiiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -435,13 +403,20 @@ pub fn invoke_viiiiiiiii(
|
||||
a9: i32,
|
||||
) {
|
||||
debug!("emscripten::invoke_viiiiiiiii");
|
||||
if let Some(dyn_call_viiiiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiiiii {
|
||||
dyn_call_viiiiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiiiiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(
|
||||
ctx,
|
||||
dyn_call_viiiiiiiii,
|
||||
index,
|
||||
a1,
|
||||
a2,
|
||||
a3,
|
||||
a4,
|
||||
a5,
|
||||
a6,
|
||||
a7,
|
||||
a8,
|
||||
a9
|
||||
)
|
||||
}
|
||||
pub fn invoke_viiiiiiiiii(
|
||||
ctx: &mut Ctx,
|
||||
@ -458,13 +433,21 @@ pub fn invoke_viiiiiiiiii(
|
||||
a10: i32,
|
||||
) {
|
||||
debug!("emscripten::invoke_viiiiiiiiii");
|
||||
if let Some(dyn_call_viiiiiiiiii) = &get_emscripten_data(ctx).dyn_call_viiiiiiiiii {
|
||||
dyn_call_viiiiiiiiii
|
||||
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("dyn_call_viiiiiiiiii is set to None");
|
||||
}
|
||||
invoke_no_return!(
|
||||
ctx,
|
||||
dyn_call_viiiiiiiiii,
|
||||
index,
|
||||
a1,
|
||||
a2,
|
||||
a3,
|
||||
a4,
|
||||
a5,
|
||||
a6,
|
||||
a7,
|
||||
a8,
|
||||
a9,
|
||||
a10
|
||||
)
|
||||
}
|
||||
|
||||
pub fn invoke_iiji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
|
||||
|
@ -1,43 +1,61 @@
|
||||
use super::env::get_emscripten_data;
|
||||
use libc::{c_int, c_void};
|
||||
use std::cell::UnsafeCell;
|
||||
use super::process::abort_with_message;
|
||||
use libc::c_int;
|
||||
// use std::cell::UnsafeCell;
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
|
||||
/// setjmp
|
||||
pub fn __setjmp(ctx: &mut Ctx, env_addr: u32) -> c_int {
|
||||
pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
|
||||
debug!("emscripten::__setjmp (setjmp)");
|
||||
unsafe {
|
||||
// Rather than using the env as the holder of the jump buffer pointer,
|
||||
// we use the environment address to store the index relative to jumps
|
||||
// so the address of the jump it's outside the wasm memory itself.
|
||||
let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
|
||||
// We create the jump buffer outside of the wasm memory
|
||||
let jump_buf: UnsafeCell<[u32; 27]> = UnsafeCell::new([0; 27]);
|
||||
let jumps = &mut get_emscripten_data(ctx).jumps;
|
||||
let result = setjmp(jump_buf.get() as _);
|
||||
// We set the jump index to be the last 3value of jumps
|
||||
*jump_index = jumps.len() as _;
|
||||
// We hold the reference of the jump buffer
|
||||
jumps.push(jump_buf);
|
||||
result
|
||||
}
|
||||
abort_with_message(ctx, "missing function: _longjmp");
|
||||
unreachable!()
|
||||
// unsafe {
|
||||
// // Rather than using the env as the holder of the jump buffer pointer,
|
||||
// // we use the environment address to store the index relative to jumps
|
||||
// // so the address of the jump it's outside the wasm memory itself.
|
||||
// let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
|
||||
// // We create the jump buffer outside of the wasm memory
|
||||
// let jump_buf: UnsafeCell<[u32; 27]> = UnsafeCell::new([0; 27]);
|
||||
// let jumps = &mut get_emscripten_data(ctx).jumps;
|
||||
// let result = setjmp(jump_buf.get() as _);
|
||||
// // We set the jump index to be the last 3value of jumps
|
||||
// *jump_index = jumps.len() as _;
|
||||
// // We hold the reference of the jump buffer
|
||||
// jumps.push(jump_buf);
|
||||
// result
|
||||
// }
|
||||
}
|
||||
|
||||
/// longjmp
|
||||
#[allow(unreachable_code)]
|
||||
pub fn __longjmp(ctx: &mut Ctx, env_addr: u32, val: c_int) {
|
||||
pub fn __longjmp(ctx: &mut Ctx, _env_addr: u32, _val: c_int) {
|
||||
debug!("emscripten::__longjmp (longmp)");
|
||||
unsafe {
|
||||
// We retrieve the jump index from the env address
|
||||
let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
|
||||
let jumps = &mut get_emscripten_data(ctx).jumps;
|
||||
// We get the real jump buffer from the jumps vector, using the retrieved index
|
||||
let jump_buf = &jumps[*jump_index as usize];
|
||||
longjmp(jump_buf.get() as _, val)
|
||||
};
|
||||
abort_with_message(ctx, "missing function: _longjmp");
|
||||
// unsafe {
|
||||
// // We retrieve the jump index from the env address
|
||||
// let jump_index = emscripten_memory_pointer!(ctx.memory(0), env_addr) as *mut i8;
|
||||
// let jumps = &mut get_emscripten_data(ctx).jumps;
|
||||
// // We get the real jump buffer from the jumps vector, using the retrieved index
|
||||
// let jump_buf = &jumps[*jump_index as usize];
|
||||
// longjmp(jump_buf.get() as _, val)
|
||||
// };
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn setjmp(env: *mut c_void) -> c_int;
|
||||
fn longjmp(env: *mut c_void, val: c_int) -> !;
|
||||
/// _longjmp
|
||||
// This function differs from the js implementation, it should return Result<(), &'static str>
|
||||
pub fn _longjmp(ctx: &mut Ctx, env_addr: i32, val: c_int) -> Result<(), ()> {
|
||||
let val = if val == 0 { 1 } else { val };
|
||||
get_emscripten_data(ctx)
|
||||
.set_threw
|
||||
.as_ref()
|
||||
.expect("set_threw is None")
|
||||
.call(env_addr, val)
|
||||
.expect("set_threw failed to call");
|
||||
// TODO: return Err("longjmp")
|
||||
Err(())
|
||||
}
|
||||
|
||||
// extern "C" {
|
||||
// fn setjmp(env: *mut c_void) -> c_int;
|
||||
// fn longjmp(env: *mut c_void, val: c_int) -> !;
|
||||
// }
|
||||
|
@ -127,6 +127,10 @@ pub struct EmscriptenData<'a> {
|
||||
pub dyn_call_vijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
|
||||
pub dyn_call_viidii: Option<Func<'a, (i32, i32, i32, f64, i32, i32)>>,
|
||||
pub temp_ret_0: i32,
|
||||
|
||||
pub stack_save: Option<Func<'a, (), i32>>,
|
||||
pub stack_restore: Option<Func<'a, (i32)>>,
|
||||
pub set_threw: Option<Func<'a, (i32, i32)>>,
|
||||
}
|
||||
|
||||
impl<'a> EmscriptenData<'a> {
|
||||
@ -186,6 +190,10 @@ impl<'a> EmscriptenData<'a> {
|
||||
let dyn_call_vijj = instance.func("dynCall_vijj").ok();
|
||||
let dyn_call_viidii = instance.func("dynCall_viidii").ok();
|
||||
|
||||
let stack_save = instance.func("stackSave").ok();
|
||||
let stack_restore = instance.func("stackRestore").ok();
|
||||
let set_threw = instance.func("_setThrew").ok();
|
||||
|
||||
EmscriptenData {
|
||||
malloc,
|
||||
free,
|
||||
@ -238,6 +246,10 @@ impl<'a> EmscriptenData<'a> {
|
||||
dyn_call_vijj,
|
||||
dyn_call_viidii,
|
||||
temp_ret_0: 0,
|
||||
|
||||
stack_save,
|
||||
stack_restore,
|
||||
set_threw,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -650,7 +662,8 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
||||
// Jump
|
||||
"__setjmp" => func!(crate::jmp::__setjmp),
|
||||
"__longjmp" => func!(crate::jmp::__longjmp),
|
||||
"_longjmp" => func!(crate::jmp::__longjmp),
|
||||
"_longjmp" => func!(crate::jmp::_longjmp),
|
||||
"_emscripten_longjmp" => func!(crate::jmp::_longjmp),
|
||||
|
||||
// Bitwise
|
||||
"_llvm_bswap_i64" => func!(crate::bitwise::_llvm_bswap_i64),
|
||||
|
@ -67,36 +67,36 @@ macro_rules! assert_emscripten_output {
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn assert_emscripten_output(wasm_bytes: &[u8], raw_expected_str: &str) {
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
use wasmer_emscripten::{generate_emscripten_env, stdio::StdioCapturer, EmscriptenGlobals};
|
||||
// pub fn assert_emscripten_output(wasm_bytes: &[u8], raw_expected_str: &str) {
|
||||
// use wasmer_clif_backend::CraneliftCompiler;
|
||||
// use wasmer_emscripten::{generate_emscripten_env, stdio::StdioCapturer, EmscriptenGlobals};
|
||||
|
||||
let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &CraneliftCompiler::new())
|
||||
.expect("WASM can't be compiled");
|
||||
// let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &CraneliftCompiler::new())
|
||||
// .expect("WASM can't be compiled");
|
||||
|
||||
let mut emscripten_globals = EmscriptenGlobals::new(&module);
|
||||
let import_object = generate_emscripten_env(&mut emscripten_globals);
|
||||
let mut instance = module
|
||||
.instantiate(&import_object)
|
||||
.map_err(|err| format!("Can't instantiate the WebAssembly module: {:?}", err))
|
||||
.unwrap();
|
||||
// let mut emscripten_globals = EmscriptenGlobals::new(&module);
|
||||
// let import_object = generate_emscripten_env(&mut emscripten_globals);
|
||||
// let mut instance = module
|
||||
// .instantiate(&import_object)
|
||||
// .map_err(|err| format!("Can't instantiate the WebAssembly module: {:?}", err))
|
||||
// .unwrap();
|
||||
|
||||
let capturer = StdioCapturer::new();
|
||||
// let capturer = StdioCapturer::new();
|
||||
|
||||
wasmer_emscripten::run_emscripten_instance(&module, &mut instance, "test", vec![])
|
||||
.expect("run_emscripten_instance finishes");
|
||||
// wasmer_emscripten::run_emscripten_instance(&module, &mut instance, "test", vec![])
|
||||
// .expect("run_emscripten_instance finishes");
|
||||
|
||||
let raw_output_string = capturer.end().unwrap().0;
|
||||
// let raw_output_string = capturer.end().unwrap().0;
|
||||
|
||||
// trim the strings to avoid cross-platform line ending and white space issues
|
||||
let output = raw_output_string.trim();
|
||||
let expected_output = raw_expected_str.trim();
|
||||
// // trim the strings to avoid cross-platform line ending and white space issues
|
||||
// let output = raw_output_string.trim();
|
||||
// let expected_output = raw_expected_str.trim();
|
||||
|
||||
let contains_output = output.contains(expected_output);
|
||||
// let contains_output = output.contains(expected_output);
|
||||
|
||||
assert!(
|
||||
contains_output,
|
||||
"Output: `{}` does not contain expected output: `{}`",
|
||||
output, expected_output
|
||||
);
|
||||
}
|
||||
// assert!(
|
||||
// contains_output,
|
||||
// "Output: `{}` does not contain expected output: `{}`",
|
||||
// output, expected_output
|
||||
// );
|
||||
// }
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp2() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp2.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp3() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp3.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp4() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp4.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp_funcptr() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp_funcptr.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp_repeat() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp_repeat.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp_stacked() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp_stacked.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp_throw() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp_throw.wasm",
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_test_longjmp_unwind() {
|
||||
assert_emscripten_output!(
|
||||
"../../emtests/test_longjmp_unwind.wasm",
|
||||
|
@ -61,15 +61,15 @@ struct UncatchableException : WasmException
|
||||
struct UserException : UncatchableException
|
||||
{
|
||||
public:
|
||||
UserException(std::string msg) : msg(msg) {}
|
||||
UserException(size_t data, size_t vtable) : data(data), vtable(vtable) {}
|
||||
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
return std::string("user exception: ") + msg;
|
||||
return "user exception";
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
// The parts of a `Box<dyn Any>`.
|
||||
size_t data, vtable;
|
||||
};
|
||||
|
||||
struct WasmTrap : UncatchableException
|
||||
@ -176,6 +176,12 @@ extern "C"
|
||||
delete module;
|
||||
}
|
||||
|
||||
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
|
||||
// side.
|
||||
[[noreturn]] void throw_any(size_t data, size_t vtable) {
|
||||
throw UserException(data, vtable);
|
||||
}
|
||||
|
||||
bool invoke_trampoline(
|
||||
trampoline_t trampoline,
|
||||
void *ctx,
|
||||
|
@ -75,7 +75,11 @@ extern "C" {
|
||||
fn module_delete(module: *mut LLVMModule);
|
||||
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
||||
|
||||
fn throw_trap(ty: i32);
|
||||
fn throw_trap(ty: i32) -> !;
|
||||
|
||||
/// This should be the same as spliting up the fat pointer into two arguments,
|
||||
/// but this is cleaner, I think?
|
||||
fn throw_any(data: *mut dyn Any) -> !;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
fn invoke_trampoline(
|
||||
@ -433,8 +437,8 @@ impl ProtectedCaller for LLVMProtectedCaller {
|
||||
}
|
||||
|
||||
impl UserTrapper for Placeholder {
|
||||
unsafe fn do_early_trap(&self, _data: Box<dyn Any>) -> ! {
|
||||
unimplemented!("do early trap")
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
|
||||
throw_any(Box::leak(data))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ pub use self::error::Result;
|
||||
#[doc(inline)]
|
||||
pub use self::import::IsExport;
|
||||
#[doc(inline)]
|
||||
pub use self::instance::Instance;
|
||||
pub use self::instance::{DynFunc, Instance};
|
||||
#[doc(inline)]
|
||||
pub use self::module::Module;
|
||||
#[doc(inline)]
|
||||
|
@ -32,11 +32,11 @@ fn get_wasm() -> Vec<u8> {
|
||||
wat2wasm(WAT).unwrap()
|
||||
}
|
||||
|
||||
fn foobar(ctx: &mut Ctx) -> i32 {
|
||||
fn foobar(_ctx: &mut Ctx) -> i32 {
|
||||
42
|
||||
}
|
||||
|
||||
fn do_panic(ctx: &mut Ctx) -> Result<i32, String> {
|
||||
fn do_panic(_ctx: &mut Ctx) -> Result<i32, String> {
|
||||
Err("error".to_string())
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user