test_gen: pass Wasm linking test without DCE

This commit is contained in:
Brian Carroll 2022-12-10 12:20:29 +00:00
parent b585bd5fde
commit 9fef0c319f
No known key found for this signature in database
GPG key ID: 5C7B2EC4101703C0
2 changed files with 61 additions and 41 deletions

View file

@ -6,7 +6,7 @@ extern fn js_unused() i32;
extern fn roc__app_proc_1_exposed() i32; extern fn roc__app_proc_1_exposed() i32;
export fn host_called_indirectly_from_roc() i32 { fn host_called_indirectly_from_roc() i32 {
return 0x40; return 0x40;
} }
@ -14,11 +14,11 @@ export fn host_called_directly_from_roc() i32 {
return 0x80 | host_called_indirectly_from_roc() | js_called_indirectly_from_roc(); return 0x80 | host_called_indirectly_from_roc() | js_called_indirectly_from_roc();
} }
export fn host_called_indirectly_from_main() i32 { fn host_called_indirectly_from_main() i32 {
return 0x100; return 0x100;
} }
export fn host_called_directly_from_main() i32 { fn host_called_directly_from_main() i32 {
return 0x200 | host_called_indirectly_from_main() | js_called_indirectly_from_main(); return 0x200 | host_called_indirectly_from_main() | js_called_indirectly_from_main();
} }

View file

@ -18,8 +18,8 @@ use roc_mono::ir::{
UpdateModeId, UpdateModeId,
}; };
use roc_mono::layout::{Builtin, CapturesNiche, LambdaName, Layout, STLayoutInterner}; use roc_mono::layout::{Builtin, CapturesNiche, LambdaName, Layout, STLayoutInterner};
use roc_wasm_module::WasmModule; use roc_wasm_interp::{wasi, ImportDispatcher, Instance, WasiDispatcher};
use wasm3::{Environment, Module}; use roc_wasm_module::{Value, WasmModule};
const LINKING_TEST_HOST_WASM: &str = "build/wasm_linking_test_host.wasm"; const LINKING_TEST_HOST_WASM: &str = "build/wasm_linking_test_host.wasm";
const LINKING_TEST_HOST_NATIVE: &str = "build/wasm_linking_test_host"; const LINKING_TEST_HOST_NATIVE: &str = "build/wasm_linking_test_host";
@ -183,39 +183,61 @@ impl<'a> BackendInputs<'a> {
} }
} }
fn execute_wasm_module(final_module: WasmModule<'_>) -> i32 { struct TestDispatcher<'a> {
let mut wasm_bytes = Vec::with_capacity(final_module.size()); wasi: WasiDispatcher<'a>,
final_module.serialize(&mut wasm_bytes); }
let env = Environment::new().unwrap(); impl ImportDispatcher for TestDispatcher<'_> {
let rt = env.create_runtime(1024 * 60).unwrap(); fn dispatch(
&mut self,
module_name: &str,
function_name: &str,
arguments: &[Value],
memory: &mut [u8],
) -> Option<Value> {
if module_name == wasi::MODULE_NAME {
self.wasi.dispatch(function_name, arguments, memory)
} else if module_name == "env" {
match function_name {
"js_called_directly_from_roc" => Some(Value::I32(0x01)),
"js_called_indirectly_from_roc" => Some(Value::I32(0x02)),
"js_called_directly_from_main" => Some(Value::I32(0x04)),
"js_called_indirectly_from_main" => Some(Value::I32(0x08)),
"js_unused" => Some(Value::I32(0x10)),
_ => panic!("Unknown import env.{}", function_name),
}
} else {
panic!(
"TestDispatcher does not implement {}.{}",
module_name, function_name
);
}
}
}
let parsed_module = Module::parse(&env, &wasm_bytes[..]).unwrap(); fn execute_wasm_module<'a>(arena: &'a Bump, orig_module: WasmModule<'a>) -> Result<i32, String> {
let mut module = rt.load_module(parsed_module).unwrap(); // FIXME: see if we can skip serializing and re-parsing!
module // Some metadata seems to be left over from the host file. e.g. CodeSection::section_start
.link_closure("env", "js_called_directly_from_roc", |_, ()| Ok(0x01i32)) let module = {
.unwrap(); let mut buffer = Vec::with_capacity(orig_module.size());
module orig_module.serialize(&mut buffer);
.link_closure("env", "js_called_indirectly_from_roc", |_, ()| Ok(0x02i32)) WasmModule::preload(arena, &buffer, false).map_err(|e| format!("{:?}", e))?
.unwrap(); };
module
.link_closure("env", "js_called_directly_from_main", |_, ()| Ok(0x04i32)) let dispatcher = TestDispatcher {
.unwrap(); wasi: wasi::WasiDispatcher { args: &[] },
module };
.link_closure("env", "js_called_indirectly_from_main", |_, ()| Ok(0x08i32)) let is_debug_mode = true;
.unwrap(); let mut inst = Instance::for_module(&arena, &module, dispatcher, is_debug_mode)?;
module
.link_closure("env", "js_unused", |_, ()| Ok(0x10i32))
.unwrap_or_else(|_| {});
// In Zig, main can only return u8 or void, but our result is too wide for that. // In Zig, main can only return u8 or void, but our result is too wide for that.
// But I want to use main so that I can test that _start is created for it! // But I want to use main so that I can test that _start is created for it!
// So return void from main, and call another function to get the result. // So return void from main, and call another function to get the result.
let start = module.find_function::<(), ()>("_start").unwrap(); inst.call_export(&module, "_start", [])?;
start.call().unwrap(); inst.call_export(&module, "read_host_result", [])?
.ok_or(String::from("expected a return value"))?
let read_host_result = module.find_function::<(), i32>("read_host_result").unwrap(); .expect_i32()
read_host_result.call().unwrap() .map_err(|type_err| format!("{:?}", type_err))
} }
fn get_native_result() -> i32 { fn get_native_result() -> i32 {
@ -272,9 +294,7 @@ fn test_help(
expected_name_section_start expected_name_section_start
); );
let wasm_result = execute_wasm_module(final_module); let wasm_result = execute_wasm_module(&arena, final_module).unwrap();
// As well as having the right structure, it should return the right result!
assert_eq!(wasm_result, get_native_result()); assert_eq!(wasm_result, get_native_result());
} }
@ -282,11 +302,11 @@ const EXPECTED_HOST_IMPORT_NAMES: [&'static str; 9] = [
"__linear_memory", "__linear_memory",
"__stack_pointer", "__stack_pointer",
"js_called_indirectly_from_roc", "js_called_indirectly_from_roc",
"js_called_indirectly_from_main",
"js_unused", "js_unused",
"js_called_directly_from_roc", "js_called_directly_from_roc",
"js_called_directly_from_main", "js_called_directly_from_main",
"roc__app_proc_1_exposed", "roc__app_proc_1_exposed",
"js_called_indirectly_from_main",
"__indirect_function_table", "__indirect_function_table",
]; ];
@ -294,18 +314,18 @@ const EXPECTED_HOST_IMPORT_NAMES: [&'static str; 9] = [
fn test_linking_without_dce() { fn test_linking_without_dce() {
let expected_final_import_names = &[ let expected_final_import_names = &[
"js_called_indirectly_from_roc", "js_called_indirectly_from_roc",
"js_called_indirectly_from_main",
"js_unused", // not eliminated "js_unused", // not eliminated
"js_called_directly_from_roc", "js_called_directly_from_roc",
"js_called_directly_from_main", "js_called_directly_from_main",
"js_called_indirectly_from_main",
]; ];
let expected_name_section_start = &[ let expected_name_section_start = &[
(0, "js_called_indirectly_from_roc"), (0, "js_called_indirectly_from_roc"),
(1, "js_called_indirectly_from_main"), (1, "js_unused"), // not eliminated
(2, "js_unused"), // not eliminated (2, "js_called_directly_from_roc"),
(3, "js_called_directly_from_roc"), (3, "js_called_directly_from_main"),
(4, "js_called_directly_from_main"), (4, "js_called_indirectly_from_main"),
]; ];
let eliminate_dead_code = false; let eliminate_dead_code = false;