From 07638caff0ef834bfac77440fa60995242892282 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Thu, 10 Oct 2024 19:01:12 +0200 Subject: [PATCH] starting the compiler wasm --- Cargo.lock | 3 + Cargo.toml | 4 +- depell/wasm-fmt/src/lib.rs | 14 ++-- depell/wasm-hbc/Cargo.toml | 4 + depell/wasm-hbc/src/lib.rs | 155 ++++++++++++++++++++++++++++++++++--- lang/src/codegen.rs | 10 +-- lang/src/parser.rs | 38 +++++---- lang/src/son.rs | 28 +------ 8 files changed, 193 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2cdd2a1..fff9be83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -808,6 +808,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-hbc" version = "0.1.0" +dependencies = [ + "hblang", +] [[package]] name = "wasm-hbfmt" diff --git a/Cargo.toml b/Cargo.toml index f1861be4..c02bdeab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,8 @@ hbjit = { path = "jit" } [profile.release] lto = true -debug = true -#strip = true +#debug = true +strip = true codegen-units = 1 panic = "abort" diff --git a/depell/wasm-fmt/src/lib.rs b/depell/wasm-fmt/src/lib.rs index 63924fbf..6d3130c0 100644 --- a/depell/wasm-fmt/src/lib.rs +++ b/depell/wasm-fmt/src/lib.rs @@ -28,6 +28,11 @@ pub fn handle_panic(_info: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable(); } +//#[no_mangle] +//static mut PANIC_MESSAGE: [u8; 1024] = [0; 1024]; +//#[no_mangle] +//static mut PANIC_MESSAGE_LEN: usize = 0; + #[global_allocator] static ALLOCATOR: ArenaAllocator = ArenaAllocator::new(); @@ -94,20 +99,15 @@ impl core::fmt::Write for Write<'_> { } } -//#[no_mangle] -//static mut PANIC_MESSAGE: [u8; 1024] = unsafe { core::mem::zeroed() }; -//#[no_mangle] -//static mut PANIC_MESSAGE_LEN: usize = 0; - #[no_mangle] -static mut OUTPUT: [u8; MAX_OUTPUT_SIZE] = unsafe { core::mem::zeroed() }; +static mut OUTPUT: [u8; MAX_OUTPUT_SIZE] = [0; MAX_OUTPUT_SIZE]; #[no_mangle] static mut OUTPUT_LEN: usize = 0; #[no_mangle] static MAX_INPUT: usize = MAX_INPUT_SIZE; #[no_mangle] -static mut INPUT: [u8; MAX_INPUT_SIZE] = unsafe { core::mem::zeroed() }; +static mut INPUT: [u8; MAX_INPUT_SIZE] = [0; MAX_INPUT_SIZE]; #[no_mangle] static mut INPUT_LEN: usize = 0; diff --git a/depell/wasm-hbc/Cargo.toml b/depell/wasm-hbc/Cargo.toml index 81927e1c..64697d9c 100644 --- a/depell/wasm-hbc/Cargo.toml +++ b/depell/wasm-hbc/Cargo.toml @@ -3,4 +3,8 @@ name = "wasm-hbc" version = "0.1.0" edition = "2021" +[lib] +crate-type = ["cdylib"] + [dependencies] +hblang.workspace = true diff --git a/depell/wasm-hbc/src/lib.rs b/depell/wasm-hbc/src/lib.rs index b93cf3ff..20a39a3e 100644 --- a/depell/wasm-hbc/src/lib.rs +++ b/depell/wasm-hbc/src/lib.rs @@ -1,14 +1,151 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +#![feature(alloc_error_handler)] +#![no_std] + +use { + alloc::{borrow::ToOwned, string::String, vec::Vec}, + core::{ + alloc::{GlobalAlloc, Layout}, + cell::UnsafeCell, + }, + hblang::{codegen::Codegen, parser::FileId}, +}; + +extern crate alloc; + +const ARENA_SIZE: usize = 4 * 128 * 1024; +const MAX_PANIC_SIZE: usize = 1024 * 4; +const MAX_INPUT_SIZE: usize = 32 * 4 * 1024; + +#[cfg(target_arch = "wasm32")] +#[panic_handler] +pub fn handle_panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + use core::fmt::Write; + let mut f = Write(&mut PANIC_MESSAGE[..]); + _ = writeln!(f, "{}", info); + PANIC_MESSAGE_LEN = 1024 - f.0.len(); + } + + core::arch::wasm32::unreachable(); } -#[cfg(test)] -mod tests { - use super::*; +#[no_mangle] +static mut PANIC_MESSAGE: [u8; MAX_PANIC_SIZE] = [0; MAX_PANIC_SIZE]; +#[no_mangle] +static mut PANIC_MESSAGE_LEN: usize = 0; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +#[global_allocator] +static ALLOCATOR: ArenaAllocator = ArenaAllocator::new(); + +#[cfg(target_arch = "wasm32")] +#[alloc_error_handler] +fn alloc_error(_: core::alloc::Layout) -> ! { + core::arch::wasm32::unreachable() +} + +#[repr(C, align(32))] +struct ArenaAllocator { + arena: UnsafeCell<[u8; ARENA_SIZE]>, + head: UnsafeCell<*mut u8>, +} + +impl ArenaAllocator { + const fn new() -> Self { + ArenaAllocator { + arena: UnsafeCell::new([0; ARENA_SIZE]), + head: UnsafeCell::new(core::ptr::null_mut()), + } + } + + unsafe fn reset(&self) { + (*self.head.get()) = self.arena.get().cast::().add(ARENA_SIZE); } } + +unsafe impl Sync for ArenaAllocator {} + +unsafe impl GlobalAlloc for ArenaAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let size = layout.size(); + let align = layout.align(); + + let until = self.arena.get() as *mut u8; + + let new_head = (*self.head.get()).sub(size); + let aligned_head = (new_head as usize & !(1 << (align - 1))) as *mut u8; + + if until > aligned_head { + return core::ptr::null_mut(); + } + + *self.head.get() = aligned_head; + aligned_head + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + /* lol */ + } +} + +#[no_mangle] +static MAX_INPUT: usize = MAX_INPUT_SIZE; +#[no_mangle] +static mut INPUT_LEN: usize = 0; +#[no_mangle] +static mut INPUT: [u8; MAX_INPUT_SIZE] = [0; MAX_INPUT_SIZE]; + +#[no_mangle] +unsafe fn compile_and_run() { + ALLOCATOR.reset(); + + struct File<'a> { + path: &'a str, + code: &'a mut str, + } + + let files = { + let mut input_bytes = + core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(INPUT).cast::(), INPUT_LEN); + + let mut files = Vec::with_capacity(32); + while let Some((&mut path_len, rest)) = input_bytes.split_first_chunk_mut() { + let (path, rest) = rest.split_at_mut(u16::from_le_bytes(path_len) as usize); + let (&mut code_len, rest) = rest.split_first_chunk_mut().unwrap(); + let (code, rest) = rest.split_at_mut(u16::from_le_bytes(code_len) as usize); + files.push(File { + path: core::str::from_utf8_unchecked(path), + code: core::str::from_utf8_unchecked_mut(code), + }); + input_bytes = rest; + } + files.sort_unstable_by_key(|f| f.path); + files + }; + + let files = { + let mut ctx = hblang::parser::ParserCtx::default(); + let paths = files.iter().map(|f| f.path).collect::>(); + let mut loader = |path: &str, _: &str| Ok(paths.binary_search(&path).unwrap() as FileId); + files + .into_iter() + .map(|f| { + hblang::parser::Ast::new( + f.path, + // since 'free' does nothing this is fine + String::from_raw_parts(f.code.as_mut_ptr(), f.code.len(), f.code.len()), + &mut ctx, + &mut loader, + ) + }) + .collect::>() + }; + + let code = { + let mut c = Codegen::default(); + c.files = files; + c.generate(); + let mut buf = Vec::with_capacity(1024 * 8); + c.assemble(&mut buf); + buf + }; +} diff --git a/lang/src/codegen.rs b/lang/src/codegen.rs index 5a9d2f48..c17aaa3a 100644 --- a/lang/src/codegen.rs +++ b/lang/src/codegen.rs @@ -2703,9 +2703,7 @@ impl Codegen { } fn report_log(&self, pos: Pos, msg: impl core::fmt::Display) { - let mut out = String::new(); - self.cfile().report_to(pos, msg, &mut out); - log::error!("{out}"); + log::error!("{}", self.cfile().report(pos, msg)); } #[track_caller] @@ -2716,13 +2714,11 @@ impl Codegen { #[track_caller] fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! { + log::debug!("{ast:#?}"); self.report( ast.pos(), format_args!( - "compiler does not (yet) know how to handle ({hint}):\n\ - {:}\n\ - info for weak people:\n\ - {ast:#?}", + "compiler does not (yet) know how to handle ({hint}):\n{}", self.ast_display(ast) ), ) diff --git a/lang/src/parser.rs b/lang/src/parser.rs index b63d2dc5..49277f2f 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -583,11 +583,7 @@ impl<'a, 'b> Parser<'a, 'b> { #[track_caller] fn report(&self, pos: Pos, msg: impl fmt::Display) -> ! { - log::error!("{}", { - let mut str = String::new(); - report_to(self.lexer.source(), self.path, pos, msg, &mut str); - str - }); + log::error!("{}", Report::new(self.lexer.source(), self.path, pos, msg)); unreachable!(); } @@ -1011,18 +1007,12 @@ impl AstInner<[Symbol]> { } } - pub fn report_to(&self, pos: Pos, msg: impl fmt::Display, out: &mut impl fmt::Write) { - report_to(&self.file, &self.path, pos, msg, out); + pub fn report(&self, pos: Pos, msg: D) -> Report { + Report::new(&self.file, &self.path, pos, msg) } } -pub fn report_to( - file: &str, - path: &str, - pos: Pos, - msg: impl fmt::Display, - out: &mut impl fmt::Write, -) { +fn report_to(file: &str, path: &str, pos: Pos, msg: impl fmt::Display, out: &mut impl fmt::Write) { let (line, mut col) = lexer::line_col(file.as_bytes(), pos); #[cfg(feature = "std")] let disp = crate::fs::display_rel_path(path); @@ -1038,6 +1028,26 @@ pub fn report_to( _ = writeln!(out, "{}^", " ".repeat(col - 1)); } +pub struct Report<'a, D> { + file: &'a str, + path: &'a str, + pos: Pos, + msg: D, +} + +impl<'a, D> Report<'a, D> { + pub fn new(file: &'a str, path: &'a str, pos: Pos, msg: D) -> Self { + Self { file, path, pos, msg } + } +} + +impl core::fmt::Display for Report<'_, D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + report_to(self.file, self.path, self.pos, &self.msg, f); + Ok(()) + } +} + #[derive(PartialEq, Eq, Hash)] pub struct Ast(NonNull>); diff --git a/lang/src/son.rs b/lang/src/son.rs index 96cab585..52eeebe2 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -1101,8 +1101,6 @@ impl Codegen { inps.push(m.node); } - let out = &mut String::new(); - self.report_log_to(pos, "returning here", out); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps); self.ci.nodes[NEVER].inputs.push(self.ci.ctrl); @@ -2153,20 +2151,6 @@ impl Codegen { } } - fn report_log(&self, pos: Pos, msg: impl core::fmt::Display) { - let mut buf = self.errors.borrow_mut(); - self.report_log_to(pos, msg, &mut *buf); - } - - fn report_log_to( - &self, - pos: Pos, - msg: impl core::fmt::Display, - out: &mut impl core::fmt::Write, - ) { - self.cfile().report_to(pos, msg, out); - } - #[track_caller] fn assert_report(&self, cond: bool, pos: Pos, msg: impl core::fmt::Display) { if !cond { @@ -2176,20 +2160,16 @@ impl Codegen { #[track_caller] fn report(&self, pos: Pos, msg: impl core::fmt::Display) { - self.report_log(pos, msg); + let mut buf = self.errors.borrow_mut(); + writeln!(buf, "{}", self.cfile().report(pos, msg)).unwrap(); } #[track_caller] fn report_unhandled_ast(&self, ast: &Expr, hint: &str) { + log::debug!("{ast:#?}"); self.report( ast.pos(), - fa!( - "compiler does not (yet) know how to handle ({hint}):\n\ - {:}\n\ - info for weak people:\n\ - {ast:#?}", - self.ast_display(ast) - ), + fa!("compiler does not (yet) know how to handle ({hint}):\n{}", self.ast_display(ast)), ); }