Reenabled longjmp 🎉

This commit is contained in:
Syrus
2019-04-09 18:33:29 -07:00
parent b2446b567e
commit 02ed9f0e5f
13 changed files with 171 additions and 241 deletions

View File

@ -30,14 +30,7 @@ test_i64
test_i64_7z
test_i64_varargs
test_llvm_intrinsics
test_longjmp2
test_longjmp4
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

View File

@ -15,113 +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");
// }
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).dyn_call_iii.as_ref().expect("dyn_call_iii is None").call(index, a1, a2);
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");
get_emscripten_data(ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
0
}
}
}
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");
// }
let sp = get_emscripten_data(ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
debug!("emscripten::invoke_v pre call");
let func = get_emscripten_data(ctx).dyn_call_v.as_ref().expect("dyn_call_v is None");
let result = func.call(index);
debug!("emscripten::invoke_v post2 call");
match result {
Ok(v) => {
},
Err(e) => {
get_emscripten_data(ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
get_emscripten_data(ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
}
}
}
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");
let sp = get_emscripten_data(ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
debug!("emscripten::invoke_vii pre call");
let func = get_emscripten_data(ctx).dyn_call_vii.as_ref().expect("dyn_call_vii is None");
let result = func.call(index, a1, a2);
debug!("emscripten::invoke_vii post2 call");
match result {
Ok(v) => {
},
Err(e) => {
get_emscripten_data(ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
get_emscripten_data(ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
}
}
}
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
@ -279,29 +172,88 @@ 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");
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");
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,
@ -313,11 +265,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,
@ -330,13 +278,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,
@ -350,13 +292,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,
@ -372,29 +308,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,
@ -407,13 +342,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,
@ -427,13 +356,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,
@ -448,13 +371,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,
@ -470,13 +399,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,
@ -493,13 +429,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 {

View File

@ -39,16 +39,16 @@ pub fn __longjmp(ctx: &mut Ctx, env_addr: u32, val: c_int) {
/// _longjmp
pub fn _longjmp(ctx: &mut Ctx, env_addr: i32, val: c_int) {
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");
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");
panic!("longjmp");
}
extern "C" {
fn setjmp(env: *mut c_void) -> c_int;
fn longjmp(env: *mut c_void, val: c_int) -> !;

View File

@ -249,7 +249,7 @@ impl<'a> EmscriptenData<'a> {
stack_save,
stack_restore,
set_threw
set_threw,
}
}
}

View File

@ -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
// );
// }

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp2() {
assert_emscripten_output!(
"../../emtests/test_longjmp2.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp4() {
assert_emscripten_output!(
"../../emtests/test_longjmp4.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp_funcptr() {
assert_emscripten_output!(
"../../emtests/test_longjmp_funcptr.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp_repeat() {
assert_emscripten_output!(
"../../emtests/test_longjmp_repeat.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp_stacked() {
assert_emscripten_output!(
"../../emtests/test_longjmp_stacked.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp_throw() {
assert_emscripten_output!(
"../../emtests/test_longjmp_throw.wasm",

View File

@ -1,5 +1,4 @@
#[test]
#[ignore]
fn test_test_longjmp_unwind() {
assert_emscripten_output!(
"../../emtests/test_longjmp_unwind.wasm",