forked from AbleOS/holey-bytes
relaxing by optimizing the compiler
This commit is contained in:
parent
1ee8d464c6
commit
d293e02f62
|
@ -4,6 +4,7 @@ members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"]
|
|||
|
||||
[profile.release]
|
||||
lto = true
|
||||
debug = true
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ use {
|
|||
ty, Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||
TypedReloc, Types,
|
||||
},
|
||||
alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec},
|
||||
core::{fmt::Display, panic},
|
||||
alloc::{boxed::Box, string::String, vec::Vec},
|
||||
core::fmt::Display,
|
||||
};
|
||||
|
||||
type Offset = u32;
|
||||
|
@ -171,9 +171,9 @@ mod reg {
|
|||
|
||||
type Reg = u8;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(debug_assertions, feature = "std"))]
|
||||
type Bt = std::backtrace::Backtrace;
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg(not(all(debug_assertions, feature = "std")))]
|
||||
type Bt = ();
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
@ -209,15 +209,15 @@ mod reg {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(debug_assertions, feature = "std"))]
|
||||
impl Drop for Id {
|
||||
fn drop(&mut self) {
|
||||
let is_panicking = {
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(debug_assertions, feature = "std"))]
|
||||
{
|
||||
std::thread::panicking()
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg(not(all(debug_assertions, feature = "std")))]
|
||||
{
|
||||
false
|
||||
}
|
||||
|
@ -246,9 +246,9 @@ mod reg {
|
|||
self.max_used = self.max_used.max(reg);
|
||||
Id(
|
||||
reg,
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(debug_assertions, feature = "std"))]
|
||||
Some(std::backtrace::Backtrace::capture()),
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg(not(all(debug_assertions, feature = "std")))]
|
||||
Some(()),
|
||||
)
|
||||
}
|
||||
|
@ -883,9 +883,8 @@ impl Codegen {
|
|||
self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "inline function call");
|
||||
|
||||
if scope == self.ci.vars.len() {
|
||||
for ((arg, ty), carg) in
|
||||
args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs)
|
||||
{
|
||||
for ((arg, ti), carg) in args.iter().zip(sig.args.range()).zip(cargs) {
|
||||
let ty = self.tys.args[ti];
|
||||
let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc;
|
||||
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } });
|
||||
}
|
||||
|
@ -903,9 +902,11 @@ impl Codegen {
|
|||
self.ci.file = prev_file;
|
||||
self.ci.ret = prev_ret;
|
||||
|
||||
for var in self.ci.vars.drain(scope..).collect::<Vec<_>>() {
|
||||
let mut vars = std::mem::take(&mut self.ci.vars);
|
||||
for var in vars.drain(scope..) {
|
||||
self.ci.free_loc(var.value.loc);
|
||||
}
|
||||
self.ci.vars = vars;
|
||||
|
||||
if let Some(last_ret) = self.ci.ret_relocs.last()
|
||||
&& last_ret.offset as usize == self.ci.code.len() - 5
|
||||
|
@ -1796,26 +1797,32 @@ impl Codegen {
|
|||
id: self.ci.id,
|
||||
ret: self.ci.ret,
|
||||
task_base: self.ci.task_base,
|
||||
loops: self.ci.loops.clone(),
|
||||
vars: self
|
||||
.ci
|
||||
.vars
|
||||
.iter()
|
||||
.map(|v| Variable {
|
||||
..self.pool.cis.pop().unwrap_or_default()
|
||||
};
|
||||
ci.loops.extend(self.ci.loops.iter());
|
||||
ci.vars.extend(self.ci.vars.iter().map(|v| Variable {
|
||||
id: v.id,
|
||||
value: Value { ty: v.value.ty, loc: v.value.loc.as_ref() },
|
||||
})
|
||||
.collect(),
|
||||
stack_relocs: self.ci.stack_relocs.clone(),
|
||||
ret_relocs: self.ci.ret_relocs.clone(),
|
||||
loop_relocs: self.ci.loop_relocs.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
}));
|
||||
ci.stack_relocs.extend(self.ci.stack_relocs.iter());
|
||||
ci.ret_relocs.extend(self.ci.ret_relocs.iter());
|
||||
ci.loop_relocs.extend(self.ci.loop_relocs.iter());
|
||||
ci.regs.init();
|
||||
|
||||
core::mem::swap(&mut self.ci, &mut ci);
|
||||
let value = self.expr(expr).unwrap();
|
||||
self.ci.free_loc(value.loc);
|
||||
core::mem::swap(&mut self.ci, &mut ci);
|
||||
|
||||
ci.loops.clear();
|
||||
ci.vars.clear();
|
||||
ci.stack_relocs.clear();
|
||||
ci.ret_relocs.clear();
|
||||
ci.loop_relocs.clear();
|
||||
ci.code.clear();
|
||||
ci.relocs.clear();
|
||||
self.pool.cis.push(ci);
|
||||
|
||||
value.ty
|
||||
}
|
||||
|
||||
|
@ -2118,9 +2125,11 @@ impl Codegen {
|
|||
self.report(body.pos(), "expected all paths in the fucntion to return");
|
||||
}
|
||||
|
||||
for vars in self.ci.vars.drain(..).collect::<Vec<_>>() {
|
||||
self.ci.free_loc(vars.value.loc);
|
||||
let mut vars = std::mem::take(&mut self.ci.vars);
|
||||
for var in vars.drain(..) {
|
||||
self.ci.free_loc(var.value.loc);
|
||||
}
|
||||
self.ci.vars = vars;
|
||||
|
||||
self.ci.finalize();
|
||||
self.ci.emit(jala(ZERO, RET_ADDR, 0));
|
||||
|
@ -2570,8 +2579,8 @@ impl Codegen {
|
|||
let last_fn = self.tys.funcs.len();
|
||||
self.tys.funcs.push(Default::default());
|
||||
|
||||
self.tys.funcs[last_fn].code.append(&mut self.ci.code);
|
||||
self.tys.funcs[last_fn].relocs.append(&mut self.ci.relocs);
|
||||
self.tys.funcs[last_fn].code = std::mem::take(&mut self.ci.code);
|
||||
self.tys.funcs[last_fn].relocs = std::mem::take(&mut self.ci.relocs);
|
||||
|
||||
if is_on_stack {
|
||||
let size =
|
||||
|
@ -2603,7 +2612,11 @@ impl Codegen {
|
|||
self.run_vm();
|
||||
self.ct.vm.pc = prev_pc + self.ct.code.as_ptr() as usize;
|
||||
|
||||
self.tys.funcs.pop().unwrap();
|
||||
let func = self.tys.funcs.pop().unwrap();
|
||||
self.ci.code = func.code;
|
||||
self.ci.code.clear();
|
||||
self.ci.relocs = func.relocs;
|
||||
self.ci.relocs.clear();
|
||||
}
|
||||
|
||||
self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci));
|
||||
|
@ -2634,10 +2647,8 @@ impl Codegen {
|
|||
ty::Display::new(&self.tys, &self.files, ty)
|
||||
}
|
||||
|
||||
fn ast_display(&self, ast: &Expr) -> String {
|
||||
let mut s = String::new();
|
||||
parser::Formatter::new(&self.cfile().file).fmt(ast, &mut s).unwrap();
|
||||
s
|
||||
fn ast_display<'a>(&'a self, ast: &'a Expr<'a>) -> parser::Display<'a> {
|
||||
parser::Display::new(&self.cfile().file, ast)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
codegen,
|
||||
parser::{self, Ast},
|
||||
parser::{self, Ast, StackAlloc},
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{fmt::Write, num::NonZeroUsize},
|
||||
|
@ -288,21 +288,22 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Vec<Ast>> {
|
|||
Ok(id)
|
||||
};
|
||||
|
||||
let execute_task = |(_, path): Task| {
|
||||
let execute_task = |stack: &mut _, (_, path): Task| {
|
||||
let path = path.to_str().ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!("path contains invalid characters: {}", display_rel_path(&path)),
|
||||
)
|
||||
})?;
|
||||
Ok(Ast::new(path, std::fs::read_to_string(path)?, &|path, from| {
|
||||
Ok(Ast::new(path, std::fs::read_to_string(path)?, stack, &|path, from| {
|
||||
loader(path, from).map_err(|e| e.to_string())
|
||||
}))
|
||||
};
|
||||
|
||||
let thread = || {
|
||||
let mut stack = StackAlloc::default();
|
||||
while let Some(task @ (indx, ..)) = tasks.pop() {
|
||||
let res = execute_task(task);
|
||||
let res = execute_task(&mut stack, task);
|
||||
let mut ast = ast.lock().unwrap();
|
||||
let len = ast.len().max(indx as usize + 1);
|
||||
ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into()));
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
map_try_insert,
|
||||
extract_if,
|
||||
ptr_internals,
|
||||
iter_intersperse
|
||||
iter_intersperse,
|
||||
slice_from_ptr_range
|
||||
)]
|
||||
#![warn(clippy::dbg_macro)]
|
||||
#![allow(stable_features, internal_features)]
|
||||
|
@ -152,9 +153,9 @@ mod ty {
|
|||
Some(Self((pos << Self::LEN_BITS | len) as u32))
|
||||
}
|
||||
|
||||
pub fn view(self, slice: &[Id]) -> &[Id] {
|
||||
&slice[self.0 as usize >> Self::LEN_BITS..][..self.len()]
|
||||
}
|
||||
//pub fn view(self, slice: &[Id]) -> &[Id] {
|
||||
// &slice[self.0 as usize >> Self::LEN_BITS..][..self.len()]
|
||||
//}
|
||||
|
||||
pub fn range(self) -> Range<usize> {
|
||||
let start = self.0 as usize >> Self::LEN_BITS;
|
||||
|
@ -658,16 +659,19 @@ impl IdentInterner {
|
|||
#[derive(Default)]
|
||||
struct Types {
|
||||
syms: HashMap<SymKey, ty::Id>,
|
||||
|
||||
funcs: Vec<Func>,
|
||||
args: Vec<ty::Id>,
|
||||
globals: Vec<Global>,
|
||||
structs: Vec<Struct>,
|
||||
fields: Vec<Field>,
|
||||
fields_tmp: Vec<Field>,
|
||||
field_names: IdentInterner,
|
||||
ptrs: Vec<Ptr>,
|
||||
arrays: Vec<Array>,
|
||||
|
||||
fields_tmp: Vec<Field>,
|
||||
frontier_tmp: Vec<ty::Id>,
|
||||
reachable_globals: Vec<ty::Global>,
|
||||
reachable_funcs: Vec<ty::Func>,
|
||||
}
|
||||
|
||||
const HEADER_SIZE: usize = core::mem::size_of::<AbleOsExecutableHeader>();
|
||||
|
@ -756,12 +760,12 @@ impl Types {
|
|||
}
|
||||
|
||||
fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec<u8>) -> AbleOsExecutableHeader {
|
||||
let mut used_funcs = vec![];
|
||||
let mut used_globals = vec![];
|
||||
debug_assert!(self.frontier_tmp.is_empty());
|
||||
debug_assert!(self.reachable_funcs.is_empty());
|
||||
debug_assert!(self.reachable_globals.is_empty());
|
||||
|
||||
let mut frontier = vec![ty::Kind::Func(from).compress()];
|
||||
|
||||
while let Some(itm) = frontier.pop() {
|
||||
self.frontier_tmp.push(ty::Kind::Func(from).compress());
|
||||
while let Some(itm) = self.frontier_tmp.pop() {
|
||||
match itm.expand() {
|
||||
ty::Kind::Func(func) => {
|
||||
let fuc = &mut self.funcs[func as usize];
|
||||
|
@ -769,8 +773,8 @@ impl Types {
|
|||
continue;
|
||||
}
|
||||
fuc.offset = 0;
|
||||
used_funcs.push(func);
|
||||
frontier.extend(fuc.relocs.iter().map(|r| r.target));
|
||||
self.reachable_funcs.push(func);
|
||||
self.frontier_tmp.extend(fuc.relocs.iter().map(|r| r.target));
|
||||
}
|
||||
ty::Kind::Global(glob) => {
|
||||
let glb = &mut self.globals[glob as usize];
|
||||
|
@ -778,13 +782,13 @@ impl Types {
|
|||
continue;
|
||||
}
|
||||
glb.offset = 0;
|
||||
used_globals.push(glob);
|
||||
self.reachable_globals.push(glob);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
for &func in &used_funcs {
|
||||
for &func in &self.reachable_funcs {
|
||||
let fuc = &mut self.funcs[func as usize];
|
||||
fuc.offset = to.len() as _;
|
||||
to.extend(&fuc.code);
|
||||
|
@ -792,7 +796,7 @@ impl Types {
|
|||
|
||||
let code_length = to.len();
|
||||
|
||||
for &global in &used_globals {
|
||||
for global in self.reachable_globals.drain(..) {
|
||||
let global = &mut self.globals[global as usize];
|
||||
global.offset = to.len() as _;
|
||||
to.extend(&global.data);
|
||||
|
@ -800,7 +804,7 @@ impl Types {
|
|||
|
||||
let data_length = to.len() - code_length;
|
||||
|
||||
for func in used_funcs {
|
||||
for func in self.reachable_funcs.drain(..) {
|
||||
let fuc = &self.funcs[func as usize];
|
||||
for rel in &fuc.relocs {
|
||||
let offset = match rel.target.expand() {
|
||||
|
@ -1167,9 +1171,10 @@ fn test_parse_files(ident: &'static str, input: &'static str) -> Vec<parser::Ast
|
|||
.ok_or("Not Found".to_string())
|
||||
};
|
||||
|
||||
let mut stack = parser::StackAlloc::default();
|
||||
module_map
|
||||
.iter()
|
||||
.map(|&(path, content)| parser::Ast::new(path, content.to_owned(), &loader))
|
||||
.map(|&(path, content)| parser::Ast::new(path, content.to_owned(), &mut stack, &loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@ use {
|
|||
alloc::{boxed::Box, string::String, vec::Vec},
|
||||
core::{
|
||||
cell::UnsafeCell,
|
||||
fmt::{self, Write},
|
||||
ops::{Deref, Not},
|
||||
fmt::{self},
|
||||
marker::PhantomData,
|
||||
ops::Deref,
|
||||
ptr::NonNull,
|
||||
sync::atomic::AtomicUsize,
|
||||
},
|
||||
std::intrinsics::unlikely,
|
||||
};
|
||||
|
||||
pub type Pos = u32;
|
||||
|
@ -58,10 +60,11 @@ struct ScopeIdent {
|
|||
pub struct Parser<'a, 'b> {
|
||||
path: &'b str,
|
||||
loader: Loader<'b>,
|
||||
lexer: Lexer<'b>,
|
||||
lexer: Lexer<'a>,
|
||||
arena: &'b Arena<'a>,
|
||||
token: Token,
|
||||
symbols: &'b mut Symbols,
|
||||
stack: &'b mut StackAlloc,
|
||||
ns_bound: usize,
|
||||
trailing_sep: bool,
|
||||
packed: bool,
|
||||
|
@ -70,7 +73,12 @@ pub struct Parser<'a, 'b> {
|
|||
}
|
||||
|
||||
impl<'a, 'b> Parser<'a, 'b> {
|
||||
pub fn new(arena: &'b Arena<'a>, symbols: &'b mut Symbols, loader: Loader<'b>) -> Self {
|
||||
pub fn new(
|
||||
arena: &'b Arena<'a>,
|
||||
symbols: &'b mut Symbols,
|
||||
stack: &'b mut StackAlloc,
|
||||
loader: Loader<'b>,
|
||||
) -> Self {
|
||||
let mut lexer = Lexer::new("");
|
||||
Self {
|
||||
loader,
|
||||
|
@ -79,6 +87,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
path: "",
|
||||
arena,
|
||||
symbols,
|
||||
stack,
|
||||
ns_bound: 0,
|
||||
trailing_sep: false,
|
||||
packed: false,
|
||||
|
@ -87,7 +96,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn file(&mut self, input: &'b str, path: &'b str) -> &'a [Expr<'a>] {
|
||||
pub fn file(&mut self, input: &'a str, path: &'b str) -> &'a [Expr<'a>] {
|
||||
self.path = path;
|
||||
self.lexer = Lexer::new(input);
|
||||
self.token = self.lexer.next();
|
||||
|
@ -247,8 +256,8 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
(id.ident, bl)
|
||||
}
|
||||
|
||||
fn move_str(&mut self, range: Token) -> &'a str {
|
||||
self.arena.alloc_str(self.lexer.slice(range.range()))
|
||||
fn tok_str(&mut self, range: Token) -> &'a str {
|
||||
self.lexer.slice(range.range())
|
||||
}
|
||||
|
||||
fn unit_expr(&mut self) -> Expr<'a> {
|
||||
|
@ -278,7 +287,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
}
|
||||
T::Directive => E::Directive {
|
||||
pos: pos - 1, // need to undo the directive shift
|
||||
name: self.move_str(token),
|
||||
name: self.tok_str(token),
|
||||
args: {
|
||||
self.expect_advance(T::LParen);
|
||||
self.collect_list(T::Comma, T::RParen, Self::expr)
|
||||
|
@ -287,7 +296,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
T::True => E::Bool { pos, value: true },
|
||||
T::False => E::Bool { pos, value: false },
|
||||
T::Idk => E::Idk { pos },
|
||||
T::DQuote => E::String { pos, literal: self.move_str(token) },
|
||||
T::DQuote => E::String { pos, literal: self.tok_str(token) },
|
||||
T::Packed => {
|
||||
self.packed = true;
|
||||
let expr = self.unit_expr();
|
||||
|
@ -308,13 +317,13 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
self.collect_list(T::Comma, T::RBrace, |s| {
|
||||
let tok = s.token;
|
||||
if s.advance_if(T::Comment) {
|
||||
CommentOr::Comment { literal: s.move_str(tok), pos: tok.start }
|
||||
CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start }
|
||||
} else {
|
||||
let name = s.expect_advance(T::Ident);
|
||||
s.expect_advance(T::Colon);
|
||||
CommentOr::Or(StructField {
|
||||
pos: name.start,
|
||||
name: s.move_str(name),
|
||||
name: s.tok_str(name),
|
||||
ty: s.expr(),
|
||||
})
|
||||
}
|
||||
|
@ -338,7 +347,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
},
|
||||
T::Ident | T::CtIdent => {
|
||||
let (id, is_first) = self.resolve_ident(token);
|
||||
let name = self.move_str(token);
|
||||
let name = self.tok_str(token);
|
||||
E::Ident { pos, is_ct: token.kind == T::CtIdent, name, id, is_first }
|
||||
}
|
||||
T::If => E::If {
|
||||
|
@ -369,7 +378,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
s.expect_advance(T::Colon);
|
||||
Arg {
|
||||
pos: name.start,
|
||||
name: s.move_str(name),
|
||||
name: s.tok_str(name),
|
||||
is_ct: name.kind == T::CtIdent,
|
||||
id,
|
||||
ty: s.expr(),
|
||||
|
@ -426,7 +435,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
self.expect_advance(T::RParen);
|
||||
expr
|
||||
}
|
||||
T::Comment => Expr::Comment { pos, literal: self.move_str(token) },
|
||||
T::Comment => Expr::Comment { pos, literal: self.tok_str(token) },
|
||||
tok => self.report(token.start, format_args!("unexpected token: {tok:?}")),
|
||||
};
|
||||
|
||||
|
@ -457,7 +466,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
pos: token.start,
|
||||
name: {
|
||||
let token = self.expect_advance(T::Ident);
|
||||
self.move_str(token)
|
||||
self.tok_str(token)
|
||||
},
|
||||
},
|
||||
_ => break,
|
||||
|
@ -486,7 +495,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
ty: ty.map(|ty| self.arena.alloc(ty)),
|
||||
fields: self.collect_list(TokenKind::Comma, TokenKind::RBrace, |s| {
|
||||
let name_tok = s.advance_ident();
|
||||
let name = s.move_str(name_tok);
|
||||
let name = s.tok_str(name_tok);
|
||||
CtorField {
|
||||
pos: name_tok.start,
|
||||
name,
|
||||
|
@ -538,19 +547,13 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
end: TokenKind,
|
||||
mut f: impl FnMut(&mut Self) -> T,
|
||||
) -> &'a [T] {
|
||||
self.collect(|s| {
|
||||
s.advance_if(end).not().then(|| {
|
||||
let val = f(s);
|
||||
s.trailing_sep = s.advance_if(delim);
|
||||
val
|
||||
})
|
||||
})
|
||||
let mut view = self.stack.view();
|
||||
while !self.advance_if(end) {
|
||||
let val = f(self);
|
||||
self.trailing_sep = self.advance_if(delim);
|
||||
unsafe { self.stack.push(&mut view, val) };
|
||||
}
|
||||
|
||||
fn collect<T: Copy>(&mut self, mut f: impl FnMut(&mut Self) -> Option<T>) -> &'a [T] {
|
||||
// TODO: avoid this allocation
|
||||
let vec = core::iter::from_fn(|| f(self)).collect::<Vec<_>>();
|
||||
self.arena.alloc_slice(&vec)
|
||||
self.arena.alloc_slice(unsafe { self.stack.finalize(view) })
|
||||
}
|
||||
|
||||
fn advance_if(&mut self, kind: TokenKind) -> bool {
|
||||
|
@ -931,6 +934,22 @@ impl<'a, T: Copy> CommentOr<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Display<'a> {
|
||||
source: &'a str,
|
||||
expr: &'a Expr<'a>,
|
||||
}
|
||||
impl<'a> Display<'a> {
|
||||
pub fn new(source: &'a str, expr: &'a Expr<'a>) -> Self {
|
||||
Self { source, expr }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Display<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Formatter::new(self.source).fmt(self.expr, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
source: &'a str,
|
||||
depth: usize,
|
||||
|
@ -942,14 +961,14 @@ impl<'a> Formatter<'a> {
|
|||
Self { source, depth: 0, disp_buff: Default::default() }
|
||||
}
|
||||
|
||||
fn fmt_list<T: Poser>(
|
||||
fn fmt_list<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut String,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut String) -> fmt::Result,
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> fmt::Result,
|
||||
) -> fmt::Result {
|
||||
self.fmt_list_low(f, trailing, end, sep, list, |s, v, f| {
|
||||
fmt(s, v, f)?;
|
||||
|
@ -957,14 +976,14 @@ impl<'a> Formatter<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn fmt_list_low<T: Poser>(
|
||||
fn fmt_list_low<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut String,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut String) -> Result<bool, fmt::Error>,
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> Result<bool, fmt::Error>,
|
||||
) -> fmt::Result {
|
||||
if !trailing {
|
||||
let mut first = true;
|
||||
|
@ -1013,10 +1032,10 @@ impl<'a> Formatter<'a> {
|
|||
res
|
||||
}
|
||||
|
||||
fn fmt_paren(
|
||||
fn fmt_paren<F: core::fmt::Write>(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
f: &mut String,
|
||||
f: &mut F,
|
||||
cond: impl FnOnce(&Expr) -> bool,
|
||||
) -> fmt::Result {
|
||||
if cond(expr) {
|
||||
|
@ -1028,7 +1047,7 @@ impl<'a> Formatter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt(&mut self, expr: &Expr, f: &mut String) -> fmt::Result {
|
||||
pub fn fmt<F: core::fmt::Write>(&mut self, expr: &Expr, f: &mut F) -> fmt::Result {
|
||||
macro_rules! impl_parenter {
|
||||
($($name:ident => $pat:pat,)*) => {
|
||||
$(
|
||||
|
@ -1259,11 +1278,13 @@ impl AstInner<[Symbol]> {
|
|||
.0
|
||||
}
|
||||
|
||||
fn new(content: String, path: &str, loader: Loader) -> NonNull<Self> {
|
||||
fn new(file: Box<str>, path: &str, stack: &mut StackAlloc, loader: Loader) -> NonNull<Self> {
|
||||
let arena = Arena::default();
|
||||
let mut syms = Vec::new();
|
||||
let mut parser = Parser::new(&arena, &mut syms, loader);
|
||||
let exprs = parser.file(&content, path) as *const [Expr<'static>];
|
||||
let mut parser = Parser::new(&arena, &mut syms, stack, loader);
|
||||
let exprs =
|
||||
parser.file(unsafe { &*(&*file as *const _) }, path) as *const [Expr<'static>];
|
||||
drop(parser);
|
||||
|
||||
syms.sort_unstable_by_key(|s| s.name);
|
||||
|
||||
|
@ -1278,7 +1299,7 @@ impl AstInner<[Symbol]> {
|
|||
mem: arena.chunk.into_inner(),
|
||||
exprs,
|
||||
path: path.into(),
|
||||
file: content.into(),
|
||||
file,
|
||||
symbols: (),
|
||||
});
|
||||
core::ptr::addr_of_mut!((*inner).symbols)
|
||||
|
@ -1320,8 +1341,8 @@ pub fn report_to(
|
|||
pub struct Ast(NonNull<AstInner<[Symbol]>>);
|
||||
|
||||
impl Ast {
|
||||
pub fn new(path: &str, content: String, loader: Loader) -> Self {
|
||||
Self(AstInner::new(content, path, loader))
|
||||
pub fn new(path: &str, content: String, stack: &mut StackAlloc, loader: Loader) -> Self {
|
||||
Self(AstInner::new(content.into(), path, stack, loader))
|
||||
}
|
||||
|
||||
pub fn exprs(&self) -> &[Expr] {
|
||||
|
@ -1346,7 +1367,7 @@ impl Ast {
|
|||
|
||||
impl Default for Ast {
|
||||
fn default() -> Self {
|
||||
Self(AstInner::new(String::new(), "", &no_loader))
|
||||
Self(AstInner::new("".into(), "", &mut StackAlloc::default(), &no_loader))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1392,7 +1413,10 @@ impl Drop for Ast {
|
|||
fn drop(&mut self) {
|
||||
let inner = unsafe { self.0.as_ref() };
|
||||
if inner.ref_count.fetch_sub(1, core::sync::atomic::Ordering::Relaxed) == 1 {
|
||||
let layout = AstInner::layout(inner.symbols.len());
|
||||
let inner = unsafe { self.0.as_mut() };
|
||||
let len = inner.symbols.len();
|
||||
unsafe { core::ptr::drop_in_place(inner) };
|
||||
let layout = AstInner::layout(len);
|
||||
unsafe {
|
||||
alloc::alloc::dealloc(self.0.as_ptr() as _, layout);
|
||||
}
|
||||
|
@ -1408,6 +1432,84 @@ impl Deref for Ast {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct StackAllocView<T> {
|
||||
prev: usize,
|
||||
base: usize,
|
||||
_ph: PhantomData<T>,
|
||||
}
|
||||
|
||||
pub struct StackAlloc {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
impl StackAlloc {
|
||||
const MAX_ALIGN: usize = 16;
|
||||
|
||||
fn view<T: Copy>(&mut self) -> StackAllocView<T> {
|
||||
let prev = self.len;
|
||||
let align = core::mem::align_of::<T>();
|
||||
assert!(align <= Self::MAX_ALIGN);
|
||||
self.len = (self.len + align - 1) & !(align - 1);
|
||||
StackAllocView { base: self.len, prev, _ph: PhantomData }
|
||||
}
|
||||
|
||||
unsafe fn push<T: Copy>(&mut self, _view: &mut StackAllocView<T>, value: T) {
|
||||
if unlikely(self.len + core::mem::size_of::<T>() > self.cap) {
|
||||
let next_cap = self.cap.max(16 * 32).max(std::mem::size_of::<T>()) * 2;
|
||||
if self.cap == 0 {
|
||||
let layout =
|
||||
core::alloc::Layout::from_size_align_unchecked(next_cap, Self::MAX_ALIGN);
|
||||
self.data = alloc::alloc::alloc(layout);
|
||||
} else {
|
||||
let old_layout =
|
||||
core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN);
|
||||
self.data = alloc::alloc::realloc(self.data, old_layout, next_cap);
|
||||
}
|
||||
self.cap = next_cap;
|
||||
}
|
||||
|
||||
let dst = self.data.add(self.len) as *mut T;
|
||||
debug_assert!(
|
||||
dst.is_aligned(),
|
||||
"{:?} {:?} {} {} {}",
|
||||
dst,
|
||||
std::mem::size_of::<T>(),
|
||||
std::mem::align_of::<T>(),
|
||||
self.len,
|
||||
self.cap
|
||||
);
|
||||
self.len += core::mem::size_of::<T>();
|
||||
core::ptr::write(dst, value);
|
||||
}
|
||||
|
||||
unsafe fn finalize<T: Copy>(&mut self, view: StackAllocView<T>) -> &[T] {
|
||||
if unlikely(self.cap == 0) {
|
||||
return &[];
|
||||
}
|
||||
let slice = core::slice::from_ptr_range(
|
||||
self.data.add(view.base) as *const T..self.data.add(self.len) as *const T,
|
||||
);
|
||||
self.len = view.prev;
|
||||
slice
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StackAlloc {
|
||||
fn default() -> Self {
|
||||
Self { data: core::ptr::null_mut(), len: 0, cap: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StackAlloc {
|
||||
fn drop(&mut self) {
|
||||
let layout =
|
||||
unsafe { core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN) };
|
||||
unsafe { alloc::alloc::dealloc(self.data, layout) };
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Arena<'a> {
|
||||
chunk: UnsafeCell<ArenaChunk>,
|
||||
|
@ -1529,10 +1631,11 @@ impl Drop for ArenaChunk {
|
|||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use {alloc::borrow::ToOwned, std::string::String};
|
||||
use {crate::parser::StackAlloc, alloc::borrow::ToOwned, std::string::String};
|
||||
|
||||
pub fn format(ident: &str, input: &str) {
|
||||
let ast = super::Ast::new(ident, input.to_owned(), &|_, _| Ok(0));
|
||||
let ast =
|
||||
super::Ast::new(ident, input.to_owned(), &mut StackAlloc::default(), &|_, _| Ok(0));
|
||||
let mut output = String::new();
|
||||
crate::fs::format_to(&ast, input, &mut output).unwrap();
|
||||
|
||||
|
|
|
@ -2107,10 +2107,8 @@ impl Codegen {
|
|||
ty::Display::new(&self.tys, &self.files, ty)
|
||||
}
|
||||
|
||||
fn ast_display(&self, ast: &Expr) -> String {
|
||||
let mut s = String::new();
|
||||
parser::Formatter::new(&self.cfile().file).fmt(ast, &mut s).unwrap();
|
||||
s
|
||||
fn ast_display<'a>(&'a self, ast: &'a Expr<'a>) -> parser::Display<'a> {
|
||||
parser::Display::new(&self.cfile().file, ast)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
Loading…
Reference in a new issue