feat(vm): threaded VM
This commit is contained in:
Generated
+10
@@ -258,6 +258,15 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "3.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "countme"
|
name = "countme"
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
@@ -472,6 +481,7 @@ dependencies = [
|
|||||||
name = "fix-codegen"
|
name = "fix-codegen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"colored",
|
||||||
"fix-builtins",
|
"fix-builtins",
|
||||||
"fix-common",
|
"fix-common",
|
||||||
"fix-ir",
|
"fix-ir",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ hashbrown = { workspace = true }
|
|||||||
num_enum = { workspace = true }
|
num_enum = { workspace = true }
|
||||||
rnix = { workspace = true }
|
rnix = { workspace = true }
|
||||||
string-interner = { workspace = true }
|
string-interner = { workspace = true }
|
||||||
|
colored = "3.1.1"
|
||||||
|
|
||||||
fix-builtins = { path = "../fix-builtins" }
|
fix-builtins = { path = "../fix-builtins" }
|
||||||
fix-common = { path = "../fix-common" }
|
fix-common = { path = "../fix-common" }
|
||||||
|
|||||||
@@ -0,0 +1,366 @@
|
|||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
|
|
||||||
|
use crate::{InstructionPtr, Op};
|
||||||
|
|
||||||
|
pub trait DisassemblerContext {
|
||||||
|
fn resolve_string(&self, id: u32) -> &str;
|
||||||
|
fn get_code(&self) -> &[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Disassembler<'a, Ctx> {
|
||||||
|
code: &'a [u8],
|
||||||
|
ctx: &'a Ctx,
|
||||||
|
pc: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
|
||||||
|
pub fn new(ip: InstructionPtr, ctx: &'a Ctx) -> Self {
|
||||||
|
Self {
|
||||||
|
code: ctx.get_code(),
|
||||||
|
ctx,
|
||||||
|
pc: ip.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u8(&mut self) -> u8 {
|
||||||
|
let b = self.code[self.pc];
|
||||||
|
self.pc += 1;
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u16(&mut self) -> u16 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 2]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 2;
|
||||||
|
u16::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(&mut self) -> u32 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 4]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 4;
|
||||||
|
u32::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_i32(&mut self) -> i32 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 4]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 4;
|
||||||
|
i32::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_i64(&mut self) -> i64 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 8]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 8;
|
||||||
|
i64::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_f64(&mut self) -> f64 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 8]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 8;
|
||||||
|
f64::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble(&mut self) -> String {
|
||||||
|
self.disassemble_impl(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble_colored(&mut self) -> String {
|
||||||
|
self.disassemble_impl(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disassemble_impl(&mut self, color: bool) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
if color {
|
||||||
|
let _ = writeln!(out, "{}", "=== Bytecode Disassembly ===".bold().white());
|
||||||
|
let _ = writeln!(
|
||||||
|
out,
|
||||||
|
"{} {}",
|
||||||
|
"Length:".white(),
|
||||||
|
format!("{} bytes", self.code.len()).cyan()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = writeln!(out, "=== Bytecode Disassembly ===");
|
||||||
|
let _ = writeln!(out, "Length: {} bytes", self.code.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.pc < self.code.len() {
|
||||||
|
let start_pos = self.pc;
|
||||||
|
let op_byte = self.read_u8();
|
||||||
|
let (mnemonic, args) = self.decode_instruction(op_byte, start_pos);
|
||||||
|
|
||||||
|
let bytes_slice = &self.code[start_pos + 1..self.pc];
|
||||||
|
let mut chunks = bytes_slice.chunks(4);
|
||||||
|
|
||||||
|
let first_chunk = chunks.next().unwrap_or(&[]);
|
||||||
|
let bytes_str = {
|
||||||
|
let mut temp = format!("{:02x}", self.code[start_pos]);
|
||||||
|
for b in first_chunk {
|
||||||
|
let _ = write!(&mut temp, " {:02x}", b);
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
if color {
|
||||||
|
let sep = if args.is_empty() { "" } else { " " };
|
||||||
|
let _ = writeln!(
|
||||||
|
out,
|
||||||
|
"{} {:<14} | {}{}{}",
|
||||||
|
format!("{:04x}", start_pos).dimmed(),
|
||||||
|
bytes_str.green(),
|
||||||
|
mnemonic.yellow().bold(),
|
||||||
|
sep,
|
||||||
|
args.cyan()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let op_str = if args.is_empty() {
|
||||||
|
mnemonic.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{} {}", mnemonic, args)
|
||||||
|
};
|
||||||
|
let _ = writeln!(out, "{:04x} {:<14} | {}", start_pos, bytes_str, op_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk in chunks {
|
||||||
|
let bytes_str = {
|
||||||
|
let mut temp = String::from(" ");
|
||||||
|
for b in chunk {
|
||||||
|
let _ = write!(&mut temp, " {:02x}", b);
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
let extra_width = if start_pos > 0 {
|
||||||
|
start_pos.ilog2() >> 4
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if color {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
for _ in 0..extra_width {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
}
|
||||||
|
let _ = writeln!(out, " {:<14} |", bytes_str.green());
|
||||||
|
} else {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
for _ in 0..extra_width {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
}
|
||||||
|
let _ = writeln!(out, " {:<14} |", bytes_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_instruction(&mut self, op_byte: u8, current_pc: usize) -> (&'static str, String) {
|
||||||
|
let op = Op::try_from_primitive(op_byte).expect("invalid op code");
|
||||||
|
|
||||||
|
match op {
|
||||||
|
Op::PushSmi => {
|
||||||
|
let val = self.read_i32();
|
||||||
|
("PushSmi", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushBigInt => {
|
||||||
|
let val = self.read_i64();
|
||||||
|
("PushBigInt", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushFloat => {
|
||||||
|
let val = self.read_f64();
|
||||||
|
("PushFloat", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushString => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let s = self.ctx.resolve_string(idx);
|
||||||
|
let len = s.len();
|
||||||
|
let mut s_fmt = format!("{:?}", s);
|
||||||
|
if s_fmt.len() > 60 {
|
||||||
|
s_fmt.truncate(57);
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
write!(s_fmt, "...\" (total {len} bytes)").unwrap();
|
||||||
|
}
|
||||||
|
("PushString", format!("@{} {}", idx, s_fmt))
|
||||||
|
}
|
||||||
|
Op::PushNull => ("PushNull", String::new()),
|
||||||
|
Op::PushTrue => ("PushTrue", String::new()),
|
||||||
|
Op::PushFalse => ("PushFalse", String::new()),
|
||||||
|
|
||||||
|
Op::LoadLocal => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("LoadLocal", format!("[{}]", idx))
|
||||||
|
}
|
||||||
|
Op::LoadOuter => {
|
||||||
|
let depth = self.read_u8();
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("LoadOuter", format!("depth={} [{}]", depth, idx))
|
||||||
|
}
|
||||||
|
Op::StoreLocal => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("StoreLocal", format!("[{}]", idx))
|
||||||
|
}
|
||||||
|
Op::AllocLocals => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("AllocLocals", format!("count={}", count))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::MakeThunk => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
("MakeThunk", format!("-> {:04x}", offset))
|
||||||
|
}
|
||||||
|
Op::MakeClosure => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
let slots = self.read_u32();
|
||||||
|
("MakeClosure", format!("-> {:04x} slots={}", offset, slots))
|
||||||
|
}
|
||||||
|
Op::MakePatternClosure => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
let slots = self.read_u32();
|
||||||
|
let req_count = self.read_u16();
|
||||||
|
let opt_count = self.read_u16();
|
||||||
|
let ellipsis = self.read_u8() != 0;
|
||||||
|
|
||||||
|
let mut arg_str = format!(
|
||||||
|
"-> {:04x} slots={} req={} opt={} ...={})",
|
||||||
|
offset, slots, req_count, opt_count, ellipsis
|
||||||
|
);
|
||||||
|
|
||||||
|
arg_str.push_str(" Args=[");
|
||||||
|
for _ in 0..req_count {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
arg_str.push_str(&format!("Req({}) ", self.ctx.resolve_string(idx)));
|
||||||
|
}
|
||||||
|
for _ in 0..opt_count {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
arg_str.push_str(&format!("Opt({}) ", self.ctx.resolve_string(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let total_args = req_count + opt_count;
|
||||||
|
for _ in 0..total_args {
|
||||||
|
let _name_idx = self.read_u32();
|
||||||
|
let _span_id = self.read_u32();
|
||||||
|
}
|
||||||
|
arg_str.push(']');
|
||||||
|
|
||||||
|
("MakePatternClosure", arg_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::Call => ("Call", String::new()),
|
||||||
|
|
||||||
|
Op::MakeAttrs => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("MakeAttrs", format!("size={}", count))
|
||||||
|
}
|
||||||
|
Op::MakeEmptyAttrs => ("MakeEmptyAttrs", String::new()),
|
||||||
|
|
||||||
|
Op::Select => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
("Select", format!("path_len={} span={}", path_len, span_id))
|
||||||
|
}
|
||||||
|
Op::SelectDefault => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
(
|
||||||
|
"SelectDefault",
|
||||||
|
format!("path_len={} span={}", path_len, span_id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Op::HasAttr => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
("HasAttr", format!("path_len={}", path_len))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::MakeList => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("MakeList", format!("size={}", count))
|
||||||
|
}
|
||||||
|
Op::MakeEmptyList => ("MakeEmptyList", String::new()),
|
||||||
|
|
||||||
|
Op::OpAdd => ("OpAdd", String::new()),
|
||||||
|
Op::OpSub => ("OpSub", String::new()),
|
||||||
|
Op::OpMul => ("OpMul", String::new()),
|
||||||
|
Op::OpDiv => ("OpDiv", String::new()),
|
||||||
|
Op::OpEq => ("OpEq", String::new()),
|
||||||
|
Op::OpNeq => ("OpNeq", String::new()),
|
||||||
|
Op::OpLt => ("OpLt", String::new()),
|
||||||
|
Op::OpGt => ("OpGt", String::new()),
|
||||||
|
Op::OpLeq => ("OpLeq", String::new()),
|
||||||
|
Op::OpGeq => ("OpGeq", String::new()),
|
||||||
|
Op::OpConcat => ("OpConcat", String::new()),
|
||||||
|
Op::OpUpdate => ("OpUpdate", String::new()),
|
||||||
|
Op::OpNeg => ("OpNeg", String::new()),
|
||||||
|
Op::OpNot => ("OpNot", String::new()),
|
||||||
|
|
||||||
|
Op::JumpIfFalse => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
(
|
||||||
|
"JumpIfFalse",
|
||||||
|
format!("-> {:04x} offset={}", target, offset),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Op::JumpIfTrue => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
("JumpIfTrue", format!("-> {:04x} offset={}", target, offset))
|
||||||
|
}
|
||||||
|
Op::Jump => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
("Jump", format!("-> {:04x} offset={}", target, offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::ConcatStrings => {
|
||||||
|
let count = self.read_u16();
|
||||||
|
let force = self.read_u8();
|
||||||
|
("ConcatStrings", format!("count={} force={}", count, force))
|
||||||
|
}
|
||||||
|
Op::ResolvePath => ("ResolvePath", String::new()),
|
||||||
|
Op::Assert => {
|
||||||
|
let raw_idx = self.read_u32();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
("Assert", format!("text_id={} span={}", raw_idx, span_id))
|
||||||
|
}
|
||||||
|
Op::PushWith => ("PushWith", String::new()),
|
||||||
|
Op::PopWith => ("PopWith", String::new()),
|
||||||
|
Op::WithLookup => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
("WithLookup", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::LoadBuiltins => ("LoadBuiltins", String::new()),
|
||||||
|
Op::LoadBuiltin => {
|
||||||
|
let id = self.read_u8();
|
||||||
|
("LoadBuiltin", format!("id={}", id))
|
||||||
|
}
|
||||||
|
Op::MkPos => {
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
("MkPos", format!("id={}", span_id))
|
||||||
|
}
|
||||||
|
Op::LoadReplBinding => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
("LoadReplBinding", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
Op::LoadScopedBinding => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
("LoadScopedBinding", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
Op::Return => ("Return", String::new()),
|
||||||
|
Op::Illegal => ("Illegal", String::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ use num_enum::TryFromPrimitive;
|
|||||||
use rnix::TextRange;
|
use rnix::TextRange;
|
||||||
use string_interner::Symbol as _;
|
use string_interner::Symbol as _;
|
||||||
|
|
||||||
|
pub mod disassembler;
|
||||||
|
|
||||||
pub struct InstructionPtr(pub usize);
|
pub struct InstructionPtr(pub usize);
|
||||||
|
|
||||||
pub trait BytecodeContext {
|
pub trait BytecodeContext {
|
||||||
|
|||||||
+564
-895
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
|||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use gc_arena::Collect;
|
|
||||||
|
|
||||||
pub(super) struct Stack<const N: usize, T> {
|
|
||||||
inner: Box<[MaybeUninit<T>; N]>,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'gc, const N: usize, T: Collect<'gc> + 'gc> Collect<'gc> for Stack<N, T> {
|
|
||||||
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
|
|
||||||
fn trace<U: gc_arena::collect::Trace<'gc>>(&self, cc: &mut U) {
|
|
||||||
for item in self.inner[..self.len].iter() {
|
|
||||||
unsafe {
|
|
||||||
item.assume_init_ref().trace(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize, T> Default for Stack<N, T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize, T> Stack<N, T> {
|
|
||||||
pub(super) fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Box::new([const { MaybeUninit::uninit() }; N]),
|
|
||||||
len: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn push(&mut self, val: T) -> Result<(), T> {
|
|
||||||
if self.len == N {
|
|
||||||
return Err(val);
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
self.inner.get_unchecked_mut(self.len).write(val);
|
|
||||||
}
|
|
||||||
self.len += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn pop(&mut self) -> Option<T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let ret = unsafe {
|
|
||||||
self.inner
|
|
||||||
.get_unchecked_mut(self.len - 1)
|
|
||||||
.assume_init_read()
|
|
||||||
};
|
|
||||||
self.len -= 1;
|
|
||||||
Some(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn tos(&self) -> Option<&T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(unsafe { self.inner.get_unchecked(self.len - 1).assume_init_ref() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn tos_mut(&mut self) -> Option<&mut T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(unsafe { self.inner.get_unchecked_mut(self.len - 1).assume_init_mut() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn len(&self) -> usize {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+5
-5
@@ -263,11 +263,11 @@ impl<'gc> Value<'gc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn restrict(self) -> Option<StrictValue<'gc>> {
|
pub(crate) fn restrict(self) -> Result<StrictValue<'gc>, Gc<'gc, Thunk<'gc>>> {
|
||||||
if !self.is::<Thunk<'gc>>() {
|
if let Some(thunk) = self.as_gc::<Thunk<'gc>>() {
|
||||||
Some(StrictValue(self))
|
Err(thunk)
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(StrictValue(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,7 @@ pub(crate) enum ThunkState<'gc> {
|
|||||||
arg: Value<'gc>,
|
arg: Value<'gc>,
|
||||||
},
|
},
|
||||||
Blackhole,
|
Blackhole,
|
||||||
Evaluated(Value<'gc>),
|
Evaluated(StrictValue<'gc>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Collect, Debug)]
|
#[derive(Collect, Debug)]
|
||||||
|
|||||||
+18
-1
@@ -2,6 +2,7 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use fix_codegen::disassembler::{Disassembler, DisassemblerContext};
|
||||||
use fix_codegen::{BytecodeContext, InstructionPtr};
|
use fix_codegen::{BytecodeContext, InstructionPtr};
|
||||||
use fix_common::{StringId, Symbol};
|
use fix_common::{StringId, Symbol};
|
||||||
use fix_error::{Error, Result, Source};
|
use fix_error::{Error, Result, Source};
|
||||||
@@ -10,7 +11,7 @@ use fix_ir::{Ir, IrRef, RawIrRef, ThunkId};
|
|||||||
use fix_vm::{ForceMode, StaticValue, Vm, VmContext};
|
use fix_vm::{ForceMode, StaticValue, Vm, VmContext};
|
||||||
use ghost_cell::{GhostCell, GhostToken};
|
use ghost_cell::{GhostCell, GhostToken};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use string_interner::DefaultStringInterner;
|
use string_interner::{DefaultStringInterner, Symbol as _};
|
||||||
|
|
||||||
// mod fetcher;
|
// mod fetcher;
|
||||||
// mod nar;
|
// mod nar;
|
||||||
@@ -105,6 +106,10 @@ impl Evaluator {
|
|||||||
Ok(ip)
|
Ok(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn disassemble_colored(&self, ip: InstructionPtr) -> String {
|
||||||
|
Disassembler::new(ip, self).disassemble_colored()
|
||||||
|
}
|
||||||
|
|
||||||
fn downgrade_ctx<'a, 'bump, 'id>(
|
fn downgrade_ctx<'a, 'bump, 'id>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
bump: &'bump Bump,
|
bump: &'bump Bump,
|
||||||
@@ -553,3 +558,15 @@ impl BytecodeContext for Evaluator {
|
|||||||
self.constants.insert(val)
|
self.constants.insert(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DisassemblerContext for Evaluator {
|
||||||
|
fn get_code(&self) -> &[u8] {
|
||||||
|
&self.bytecode
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
fn resolve_string(&self, id: u32) -> &str {
|
||||||
|
let id = string_interner::symbol::SymbolU32::try_from_usize(id as usize).unwrap();
|
||||||
|
self.strings.resolve(id).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+5
-5
@@ -40,7 +40,7 @@ struct ExprSource {
|
|||||||
file: Option<PathBuf>,
|
file: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_compile(eval: &mut Evaluator, src: ExprSource, _silent: bool) -> Result<()> {
|
fn run_compile(eval: &mut Evaluator, src: ExprSource, silent: bool) -> Result<()> {
|
||||||
let src = if let Some(expr) = src.expr {
|
let src = if let Some(expr) = src.expr {
|
||||||
Source::new_eval(expr)?
|
Source::new_eval(expr)?
|
||||||
} else if let Some(file) = src.file {
|
} else if let Some(file) = src.file {
|
||||||
@@ -49,10 +49,10 @@ fn run_compile(eval: &mut Evaluator, src: ExprSource, _silent: bool) -> Result<(
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
match eval.compile_bytecode(src) {
|
match eval.compile_bytecode(src) {
|
||||||
Ok(_ip) => {
|
Ok(ip) => {
|
||||||
// if !silent {
|
if !silent {
|
||||||
// println!("{}", eval.disassemble_colored(ip));
|
println!("{}", eval.disassemble_colored(ip));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("{:?}", miette::Report::new(*err));
|
eprintln!("{:?}", miette::Report::new(*err));
|
||||||
|
|||||||
Reference in New Issue
Block a user