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