mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
wasm: implement Stmt::RuntimeError
This commit is contained in:
parent
0d08c97e44
commit
8c5fe2ae22
2 changed files with 31 additions and 22 deletions
|
@ -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
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue