mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Generate a test "platform" with libc allocator functions
This commit is contained in:
parent
e9f920827e
commit
b8f40011b9
3 changed files with 149 additions and 28 deletions
|
@ -241,8 +241,7 @@ impl<'a> Serialize for ImportSection<'a> {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionSection<'a> {
|
pub struct FunctionSection<'a> {
|
||||||
/// Private. See WasmModule::add_function_signature
|
pub signature_indices: Vec<'a, u32>,
|
||||||
signature_indices: Vec<'a, u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FunctionSection<'a> {
|
impl<'a> FunctionSection<'a> {
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
|
use bumpalo::collections::vec::Vec;
|
||||||
|
use bumpalo::Bump;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
|
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
|
||||||
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_can::builtins::builtin_defs_map;
|
use roc_can::builtins::builtin_defs_map;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_gen_wasm::wasm_module::linking::{WasmObjectSymbol, WASM_SYM_UNDEFINED};
|
||||||
|
use roc_gen_wasm::wasm_module::sections::{Import, ImportDesc};
|
||||||
|
use roc_gen_wasm::wasm_module::{
|
||||||
|
CodeBuilder, Export, ExportType, LocalId, Signature, SymInfo, ValueType, WasmModule,
|
||||||
|
};
|
||||||
use roc_gen_wasm::MEMORY_NAME;
|
use roc_gen_wasm::MEMORY_NAME;
|
||||||
|
|
||||||
use tempfile::{TempDir, tempdir};
|
|
||||||
|
|
||||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||||
|
|
||||||
std::thread_local! {
|
std::thread_local! {
|
||||||
|
@ -115,6 +121,9 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
||||||
main_fn_index as u32,
|
main_fn_index as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We can either generate the test platform or write an external source file, whatever works
|
||||||
|
generate_test_platform(&mut wasm_module, arena);
|
||||||
|
|
||||||
let mut module_bytes = std::vec::Vec::with_capacity(4096);
|
let mut module_bytes = std::vec::Vec::with_capacity(4096);
|
||||||
wasm_module.serialize_mut(&mut module_bytes);
|
wasm_module.serialize_mut(&mut module_bytes);
|
||||||
|
|
||||||
|
@ -131,15 +140,17 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
||||||
let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped
|
let tmp_dir: TempDir; // directory for normal test runs, deleted when dropped
|
||||||
let debug_dir: String; // persistent directory for debugging
|
let debug_dir: String; // persistent directory for debugging
|
||||||
|
|
||||||
let dirpath: &Path =
|
let dirpath: &Path = if DEBUG_WASM_FILE {
|
||||||
if DEBUG_WASM_FILE {
|
|
||||||
// Directory name based on a hash of the Roc source
|
// Directory name based on a hash of the Roc source
|
||||||
let mut hash_state = DefaultHasher::new();
|
let mut hash_state = DefaultHasher::new();
|
||||||
src.hash(&mut hash_state);
|
src.hash(&mut hash_state);
|
||||||
let src_hash = hash_state.finish();
|
let src_hash = hash_state.finish();
|
||||||
debug_dir = format!("/tmp/roc/gen_wasm/{:016x}", src_hash);
|
debug_dir = format!("/tmp/roc/gen_wasm/{:016x}", src_hash);
|
||||||
std::fs::create_dir_all(&debug_dir).unwrap();
|
std::fs::create_dir_all(&debug_dir).unwrap();
|
||||||
println!("Debug command:\n\twasm-objdump -sdx {}/final.wasm", &debug_dir);
|
println!(
|
||||||
|
"Debug command:\n\twasm-objdump -sdx {}/final.wasm",
|
||||||
|
&debug_dir
|
||||||
|
);
|
||||||
Path::new(&debug_dir)
|
Path::new(&debug_dir)
|
||||||
} else {
|
} else {
|
||||||
tmp_dir = tempdir().unwrap();
|
tmp_dir = tempdir().unwrap();
|
||||||
|
@ -271,3 +282,123 @@ pub fn identity<T>(value: T) -> T {
|
||||||
pub(crate) use assert_evals_to;
|
pub(crate) use assert_evals_to;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use assert_wasm_evals_to;
|
pub(crate) use assert_wasm_evals_to;
|
||||||
|
|
||||||
|
fn wrap_libc_fn<'a>(
|
||||||
|
module: &mut WasmModule<'a>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
roc_name: &'a str,
|
||||||
|
libc_name: &'a str,
|
||||||
|
params: &'a [(ValueType, bool)],
|
||||||
|
ret_type: Option<ValueType>,
|
||||||
|
) {
|
||||||
|
let symbol_table = module.linking.symbol_table_mut();
|
||||||
|
|
||||||
|
// Type signatures
|
||||||
|
let mut wrapper_signature = Signature {
|
||||||
|
param_types: Vec::with_capacity_in(params.len(), arena),
|
||||||
|
ret_type,
|
||||||
|
};
|
||||||
|
let mut libc_signature = Signature {
|
||||||
|
param_types: Vec::with_capacity_in(params.len(), arena),
|
||||||
|
ret_type,
|
||||||
|
};
|
||||||
|
for (ty, used) in params.iter() {
|
||||||
|
wrapper_signature.param_types.push(*ty);
|
||||||
|
if *used {
|
||||||
|
libc_signature.param_types.push(*ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Import a function from libc
|
||||||
|
*/
|
||||||
|
let libc_signature_index = module.types.insert(libc_signature);
|
||||||
|
|
||||||
|
// Import
|
||||||
|
let import_index = module.import.entries.len() as u32;
|
||||||
|
module.import.entries.push(Import {
|
||||||
|
module: "env",
|
||||||
|
name: libc_name.to_string(),
|
||||||
|
description: ImportDesc::Func {
|
||||||
|
signature_index: libc_signature_index,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Linker info
|
||||||
|
let libc_sym_idx = symbol_table.len() as u32;
|
||||||
|
symbol_table.push(SymInfo::Function(WasmObjectSymbol::Imported {
|
||||||
|
flags: WASM_SYM_UNDEFINED,
|
||||||
|
index: import_index,
|
||||||
|
}));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Export a wrapper function
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Declaration
|
||||||
|
let wrapper_sig_index = module.types.insert(wrapper_signature);
|
||||||
|
module.function.signature_indices.push(wrapper_sig_index);
|
||||||
|
|
||||||
|
// Body
|
||||||
|
let mut code_builder = CodeBuilder::new(arena);
|
||||||
|
let mut num_libc_args = 0;
|
||||||
|
for (i, (_, used)) in params.iter().enumerate() {
|
||||||
|
if *used {
|
||||||
|
code_builder.get_local(LocalId(i as u32));
|
||||||
|
num_libc_args += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
code_builder.call(
|
||||||
|
import_index,
|
||||||
|
libc_sym_idx,
|
||||||
|
num_libc_args,
|
||||||
|
ret_type.is_some(),
|
||||||
|
);
|
||||||
|
code_builder.build_fn_header(&[], 0, None);
|
||||||
|
let wrapper_index = module.code.code_builders.len() as u32;
|
||||||
|
module.code.code_builders.push(code_builder);
|
||||||
|
|
||||||
|
// Export
|
||||||
|
module.export.entries.push(Export {
|
||||||
|
name: roc_name.to_string(),
|
||||||
|
ty: ExportType::Func,
|
||||||
|
index: wrapper_index,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Linker symbol
|
||||||
|
symbol_table.push(SymInfo::Function(WasmObjectSymbol::Defined {
|
||||||
|
flags: 0,
|
||||||
|
index: wrapper_index,
|
||||||
|
name: roc_name.to_string(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_test_platform<'a>(module: &mut WasmModule<'a>, arena: &'a Bump) {
|
||||||
|
use ValueType::I32;
|
||||||
|
|
||||||
|
wrap_libc_fn(
|
||||||
|
module,
|
||||||
|
arena,
|
||||||
|
"roc_alloc",
|
||||||
|
"malloc",
|
||||||
|
// only the first argument of roc_alloc is passed to malloc
|
||||||
|
&[(I32, true), (I32, false)],
|
||||||
|
Some(I32),
|
||||||
|
);
|
||||||
|
wrap_libc_fn(
|
||||||
|
module,
|
||||||
|
arena,
|
||||||
|
"roc_dealloc",
|
||||||
|
"free",
|
||||||
|
&[(I32, true), (I32, false)],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
wrap_libc_fn(
|
||||||
|
module,
|
||||||
|
arena,
|
||||||
|
"roc_realloc",
|
||||||
|
"realloc",
|
||||||
|
&[(I32, true), (I32, false), (I32, true), (I32, false)],
|
||||||
|
Some(I32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -300,16 +300,7 @@ fn long_str_literal() {
|
||||||
fn small_str_concat_empty_first_arg() {
|
fn small_str_concat_empty_first_arg() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
r#"Str.concat "" "JJJJJJJ""#,
|
r#"Str.concat "" "JJJJJJJ""#,
|
||||||
[
|
[0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0b1000_0111],
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0x4a,
|
|
||||||
0b1000_0111
|
|
||||||
],
|
|
||||||
[u8; 8]
|
[u8; 8]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue