wasm: implement Stmt::RuntimeError

This commit is contained in:
Brian Carroll 2022-02-10 10:13:54 +00:00
parent 0d08c97e44
commit 8c5fe2ae22
2 changed files with 31 additions and 22 deletions

View file

@ -78,6 +78,9 @@ impl<'a> WasmBackend<'a> {
index: STACK_POINTER_GLOBAL_ID, index: STACK_POINTER_GLOBAL_ID,
}); });
// TODO: Read the actual address ranges of preloaded data sections, in case they do something unexpected
let next_constant_addr = CONST_SEGMENT_BASE_ADDR + module.data.bytes.len() as u32;
WasmBackend { WasmBackend {
env, env,
interns, interns,
@ -86,7 +89,7 @@ impl<'a> WasmBackend<'a> {
module, module,
layout_ids, layout_ids,
next_constant_addr: CONST_SEGMENT_BASE_ADDR, next_constant_addr,
fn_index_offset, fn_index_offset,
called_preload_fns: Vec::with_capacity_in(2, env.arena), called_preload_fns: Vec::with_capacity_in(2, env.arena),
proc_symbols, proc_symbols,
@ -529,7 +532,23 @@ impl<'a> WasmBackend<'a> {
} }
fn stmt_runtime_error(&mut self, msg: &'a str) { fn stmt_runtime_error(&mut self, msg: &'a str) {
todo!("RuntimeError {:?}", msg) // Create a zero-terminated version of the message string
let mut bytes = Vec::with_capacity_in(msg.len() + 1, self.env.arena);
bytes.extend_from_slice(msg.as_bytes());
bytes.push(0);
// Store it in the app's data section
let sym = self.create_symbol(msg);
let (linker_sym_index, elements_addr) = self.store_bytes_in_data_section(&bytes, sym);
// Pass its address to roc_panic
let tag_id = 0;
self.code_builder
.i32_const_mem_addr(elements_addr, linker_sym_index);
self.code_builder.i32_const(tag_id);
self.call_zig_builtin_after_loading_args("roc_panic", 2, false);
self.code_builder.unreachable_();
} }
/********************************************************** /**********************************************************
@ -540,7 +559,7 @@ impl<'a> WasmBackend<'a> {
fn expr(&mut self, sym: Symbol, expr: &Expr<'a>, layout: &Layout<'a>, storage: &StoredValue) { fn expr(&mut self, sym: Symbol, expr: &Expr<'a>, layout: &Layout<'a>, storage: &StoredValue) {
match expr { match expr {
Expr::Literal(lit) => self.expr_literal(lit, storage, sym, layout), Expr::Literal(lit) => self.expr_literal(lit, storage, sym),
Expr::Call(roc_mono::ir::Call { Expr::Call(roc_mono::ir::Call {
call_type, call_type,
@ -601,13 +620,7 @@ impl<'a> WasmBackend<'a> {
* Literals * Literals
*******************************************************************/ *******************************************************************/
fn expr_literal( fn expr_literal(&mut self, lit: &Literal<'a>, storage: &StoredValue, sym: Symbol) {
&mut self,
lit: &Literal<'a>,
storage: &StoredValue,
sym: Symbol,
layout: &Layout<'a>,
) {
let invalid_error = let invalid_error =
|| internal_error!("Literal value {:?} has invalid storage {:?}", lit, storage); || internal_error!("Literal value {:?} has invalid storage {:?}", lit, storage);
@ -670,8 +683,9 @@ impl<'a> WasmBackend<'a> {
self.code_builder.i64_const(str_as_int); self.code_builder.i64_const(str_as_int);
self.code_builder.i64_store(Align::Bytes4, offset); self.code_builder.i64_store(Align::Bytes4, offset);
} else { } else {
let bytes = string.as_bytes();
let (linker_sym_index, elements_addr) = let (linker_sym_index, elements_addr) =
self.expr_literal_big_str(string, sym, layout); self.store_bytes_in_data_section(bytes, sym);
self.code_builder.get_local(local_id); self.code_builder.get_local(local_id);
self.code_builder self.code_builder
@ -693,16 +707,11 @@ impl<'a> WasmBackend<'a> {
/// Create a string constant in the module data section /// Create a string constant in the module data section
/// Return the data we need for code gen: linker symbol index and memory address /// Return the data we need for code gen: linker symbol index and memory address
fn expr_literal_big_str( fn store_bytes_in_data_section(&mut self, bytes: &[u8], sym: Symbol) -> (u32, u32) {
&mut self,
string: &'a str,
sym: Symbol,
layout: &Layout<'a>,
) -> (u32, u32) {
// Place the segment at a 4-byte aligned offset // Place the segment at a 4-byte aligned offset
let segment_addr = round_up_to_alignment!(self.next_constant_addr, PTR_SIZE); let segment_addr = round_up_to_alignment!(self.next_constant_addr, PTR_SIZE);
let elements_addr = segment_addr + PTR_SIZE; let elements_addr = segment_addr + PTR_SIZE;
let length_with_refcount = 4 + string.len(); let length_with_refcount = 4 + bytes.len();
self.next_constant_addr = segment_addr + length_with_refcount as u32; self.next_constant_addr = segment_addr + length_with_refcount as u32;
let mut segment = DataSegment { let mut segment = DataSegment {
@ -713,14 +722,14 @@ impl<'a> WasmBackend<'a> {
// Prefix the string bytes with "infinite" refcount // Prefix the string bytes with "infinite" refcount
let refcount_max_bytes: [u8; 4] = (REFCOUNT_MAX as i32).to_le_bytes(); let refcount_max_bytes: [u8; 4] = (REFCOUNT_MAX as i32).to_le_bytes();
segment.init.extend_from_slice(&refcount_max_bytes); segment.init.extend_from_slice(&refcount_max_bytes);
segment.init.extend_from_slice(string.as_bytes()); segment.init.extend_from_slice(bytes);
let segment_index = self.module.data.append_segment(segment); let segment_index = self.module.data.append_segment(segment);
// Generate linker symbol // Generate linker symbol
let name = self let name = self
.layout_ids .layout_ids
.get(sym, layout) .get(sym, &Layout::Builtin(Builtin::Str))
.to_symbol_string(sym, self.interns); .to_symbol_string(sym, self.interns);
let linker_symbol = SymInfo::Data(DataSymbol::Defined { let linker_symbol = SymInfo::Data(DataSymbol::Defined {
@ -728,7 +737,7 @@ impl<'a> WasmBackend<'a> {
name: name.clone(), name: name.clone(),
segment_index, segment_index,
segment_offset: 4, segment_offset: 4,
size: string.len() as u32, size: bytes.len() as u32,
}); });
// Ensure the linker keeps the segment aligned when relocating it // Ensure the linker keeps the segment aligned when relocating it

View file

@ -850,7 +850,7 @@ impl Serialize for DataSegment<'_> {
#[derive(Debug)] #[derive(Debug)]
pub struct DataSection<'a> { pub struct DataSection<'a> {
count: u32, count: u32,
bytes: Vec<'a, u8>, pub bytes: Vec<'a, u8>,
} }
impl<'a> DataSection<'a> { impl<'a> DataSection<'a> {