mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Allocate and free stack frames
This commit is contained in:
parent
036503c750
commit
4f55b7a56e
3 changed files with 43 additions and 21 deletions
|
@ -10,8 +10,8 @@ use roc_module::symbol::Symbol;
|
||||||
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
|
|
||||||
use crate::layout::{WasmLayout};
|
use crate::layout::WasmLayout;
|
||||||
use crate::{PTR_TYPE, copy_memory, LocalId};
|
use crate::{allocate_stack_frame, copy_memory, free_stack_frame, LocalId, PTR_TYPE};
|
||||||
|
|
||||||
// Don't allocate any constant data at address zero or near it. Would be valid, but bug-prone.
|
// Don't allocate any constant data at address zero or near it. Would be valid, but bug-prone.
|
||||||
// Follow Emscripten's example by using 1kB (4 bytes would probably do)
|
// Follow Emscripten's example by using 1kB (4 bytes would probably do)
|
||||||
|
@ -110,14 +110,17 @@ impl<'a> WasmBackend<'a> {
|
||||||
|
|
||||||
self.build_stmt(&proc.body, &proc.ret_layout)?;
|
self.build_stmt(&proc.body, &proc.ret_layout)?;
|
||||||
|
|
||||||
// functions must end with an End instruction/opcode
|
let mut final_instructions = Vec::with_capacity(self.instructions.len() + 10);
|
||||||
self.instructions.push(Instruction::End);
|
allocate_stack_frame(&mut final_instructions, self.stack_memory as i32);
|
||||||
|
final_instructions.extend(self.instructions.clone());
|
||||||
|
free_stack_frame(&mut final_instructions, self.stack_memory as i32);
|
||||||
|
final_instructions.push(Instruction::End);
|
||||||
|
|
||||||
let function_def = builder::function()
|
let function_def = builder::function()
|
||||||
.with_signature(signature)
|
.with_signature(signature)
|
||||||
.body()
|
.body()
|
||||||
.with_locals(self.locals.clone())
|
.with_locals(self.locals.clone())
|
||||||
.with_instructions(Instructions::new(self.instructions.clone()))
|
.with_instructions(Instructions::new(final_instructions))
|
||||||
.build() // body
|
.build() // body
|
||||||
.build(); // function
|
.build(); // function
|
||||||
|
|
||||||
|
@ -130,13 +133,13 @@ impl<'a> WasmBackend<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol, kind: LocalKind) -> LocalId {
|
fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol, kind: LocalKind) -> LocalId {
|
||||||
self.stack_memory += layout.stack_memory();
|
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
LocalKind::Parameter => {
|
LocalKind::Parameter => {
|
||||||
|
// Don't increment stack_memory! Structs are allocated in caller's stack memory and passed as pointers.
|
||||||
self.arg_types.push(layout.value_type());
|
self.arg_types.push(layout.value_type());
|
||||||
}
|
}
|
||||||
LocalKind::Variable => {
|
LocalKind::Variable => {
|
||||||
|
self.stack_memory += layout.stack_memory();
|
||||||
self.locals.push(Local::new(1, layout.value_type()));
|
self.locals.push(Local::new(1, layout.value_type()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +231,13 @@ impl<'a> WasmBackend<'a> {
|
||||||
let to = LocalId(0);
|
let to = LocalId(0);
|
||||||
let copy_size: u32 = *size;
|
let copy_size: u32 = *size;
|
||||||
let copy_alignment_bytes: u32 = *alignment_bytes;
|
let copy_alignment_bytes: u32 = *alignment_bytes;
|
||||||
copy_memory(&mut self.instructions, from, to, copy_size, copy_alignment_bytes)?;
|
copy_memory(
|
||||||
|
&mut self.instructions,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
copy_size,
|
||||||
|
copy_alignment_bytes,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub const ALIGN_8: u32 = 3;
|
||||||
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
|
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct LocalId(u32);
|
pub struct LocalId(u32);
|
||||||
|
|
||||||
pub struct Env<'a> {
|
pub struct Env<'a> {
|
||||||
pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot
|
pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot
|
||||||
|
@ -152,3 +152,23 @@ fn copy_memory(
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allocate_stack_frame(instructions: &mut Vec<Instruction>, size: i32) {
|
||||||
|
if size == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instructions.push(GetGlobal(STACK_POINTER_GLOBAL_ID));
|
||||||
|
instructions.push(I32Const(size));
|
||||||
|
instructions.push(I32Sub);
|
||||||
|
instructions.push(SetGlobal(STACK_POINTER_GLOBAL_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_stack_frame(instructions: &mut Vec<Instruction>, size: i32) {
|
||||||
|
if size == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instructions.push(GetGlobal(STACK_POINTER_GLOBAL_ID));
|
||||||
|
instructions.push(I32Const(size));
|
||||||
|
instructions.push(I32Add);
|
||||||
|
instructions.push(SetGlobal(STACK_POINTER_GLOBAL_ID));
|
||||||
|
}
|
||||||
|
|
|
@ -35,20 +35,12 @@ pub trait Wasm32TestResult {
|
||||||
fn build_wrapper_body(main_function_index: u32) -> Vec<Instruction>;
|
fn build_wrapper_body(main_function_index: u32) -> Vec<Instruction>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_wrapper_body_prelude(stack_memory_size: usize) -> Vec<Instruction> {
|
|
||||||
vec![
|
|
||||||
GetGlobal(STACK_POINTER_GLOBAL_ID),
|
|
||||||
I32Const(stack_memory_size as i32),
|
|
||||||
I32Sub,
|
|
||||||
SetGlobal(STACK_POINTER_GLOBAL_ID),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! build_wrapper_body_primitive {
|
macro_rules! build_wrapper_body_primitive {
|
||||||
($store_instruction: expr, $align: expr) => {
|
($store_instruction: expr, $align: expr) => {
|
||||||
fn build_wrapper_body(main_function_index: u32) -> Vec<Instruction> {
|
fn build_wrapper_body(main_function_index: u32) -> Vec<Instruction> {
|
||||||
const MAX_ALIGNED_SIZE: usize = 16;
|
const MAX_ALIGNED_SIZE: i32 = 16;
|
||||||
let mut instructions = build_wrapper_body_prelude(MAX_ALIGNED_SIZE);
|
let mut instructions = Vec::with_capacity(9);
|
||||||
|
allocate_stack_frame(&mut instructions, MAX_ALIGNED_SIZE);
|
||||||
instructions.extend([
|
instructions.extend([
|
||||||
GetGlobal(STACK_POINTER_GLOBAL_ID),
|
GetGlobal(STACK_POINTER_GLOBAL_ID),
|
||||||
//
|
//
|
||||||
|
@ -76,7 +68,8 @@ macro_rules! wasm_test_result_primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_wrapper_body_stack_memory(main_function_index: u32, size: usize) -> Vec<Instruction> {
|
fn build_wrapper_body_stack_memory(main_function_index: u32, size: usize) -> Vec<Instruction> {
|
||||||
let mut instructions = build_wrapper_body_prelude(size);
|
let mut instructions = Vec::with_capacity(8);
|
||||||
|
allocate_stack_frame(&mut instructions, size as i32);
|
||||||
instructions.extend([
|
instructions.extend([
|
||||||
//
|
//
|
||||||
// Call the main function with the allocated address to write the result.
|
// Call the main function with the allocated address to write the result.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue