refactor: reorganize crate hierarchy
This commit is contained in:
@@ -0,0 +1,531 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use fix_lang::{BuiltinId, StringId};
|
||||
use num_enum::TryFromPrimitive;
|
||||
use string_interner::Symbol as _;
|
||||
|
||||
pub mod disassembler;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct InstructionPtr(pub usize);
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, TryFromPrimitive)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum Op {
|
||||
PushSmi,
|
||||
PushBigInt,
|
||||
PushFloat,
|
||||
PushString,
|
||||
PushNull,
|
||||
PushTrue,
|
||||
PushFalse,
|
||||
|
||||
LoadLocal,
|
||||
LoadOuter,
|
||||
StoreLocal,
|
||||
AllocLocals,
|
||||
|
||||
MakeThunk,
|
||||
MakeClosure,
|
||||
MakePatternClosure,
|
||||
|
||||
Call,
|
||||
DispatchPrimOp,
|
||||
|
||||
MakeAttrs,
|
||||
MakeEmptyAttrs,
|
||||
SelectStatic,
|
||||
SelectDynamic,
|
||||
HasAttrPathStatic,
|
||||
HasAttrPathDynamic,
|
||||
HasAttrStatic,
|
||||
HasAttrDynamic,
|
||||
HasAttrResolve,
|
||||
JumpIfSelectSucceeded,
|
||||
JumpIfSelectFailed,
|
||||
|
||||
MakeList,
|
||||
MakeEmptyList,
|
||||
|
||||
OpAdd,
|
||||
OpSub,
|
||||
OpMul,
|
||||
OpDiv,
|
||||
OpEq,
|
||||
OpNeq,
|
||||
OpLt,
|
||||
OpGt,
|
||||
OpLeq,
|
||||
OpGeq,
|
||||
OpConcat,
|
||||
OpUpdate,
|
||||
|
||||
OpNeg,
|
||||
OpNot,
|
||||
|
||||
JumpIfFalse,
|
||||
JumpIfTrue,
|
||||
Jump,
|
||||
|
||||
CoerceToString,
|
||||
|
||||
ConcatStrings,
|
||||
ResolvePath,
|
||||
|
||||
Assert,
|
||||
|
||||
LookupWith,
|
||||
|
||||
LoadBuiltins,
|
||||
LoadBuiltin,
|
||||
|
||||
LoadReplBinding,
|
||||
LoadScopedBinding,
|
||||
|
||||
Return,
|
||||
|
||||
Illegal,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, TryFromPrimitive)]
|
||||
pub enum OperandType {
|
||||
Const,
|
||||
BigInt,
|
||||
Local,
|
||||
BuiltinConst,
|
||||
Builtins,
|
||||
ReplBinding,
|
||||
ScopedImportBinding,
|
||||
}
|
||||
|
||||
pub enum Const {
|
||||
Smi(i32),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(StringId),
|
||||
Path(StringId),
|
||||
PrimOp {
|
||||
id: BuiltinId,
|
||||
arity: u8,
|
||||
dispatch_ip: u32,
|
||||
},
|
||||
Null,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, TryFromPrimitive)]
|
||||
pub enum AttrKeyType {
|
||||
Static,
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
pub enum OperandData {
|
||||
Const(u32),
|
||||
BigInt(i64),
|
||||
Local { layer: u8, idx: u32 },
|
||||
BuiltinConst(StringId),
|
||||
Builtins,
|
||||
ReplBinding(StringId),
|
||||
ScopedImportBinding { slot_id: u32, name: StringId },
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum PrimOpPhase {
|
||||
Abort,
|
||||
Add,
|
||||
AddErrorContext,
|
||||
|
||||
All,
|
||||
AllCallPred,
|
||||
AllCheck,
|
||||
|
||||
Any,
|
||||
AnyCallPred,
|
||||
AnyCheck,
|
||||
|
||||
AppendContext,
|
||||
AttrNames,
|
||||
AttrValues,
|
||||
BaseNameOf,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
Break,
|
||||
CatAttrs,
|
||||
Ceil,
|
||||
CompareVersions,
|
||||
ConcatLists,
|
||||
ConcatMap,
|
||||
ConcatStringsSep,
|
||||
ConvertHash,
|
||||
|
||||
DeepSeq,
|
||||
DeepSeqPush,
|
||||
DeepSeqLoop,
|
||||
|
||||
Derivation,
|
||||
DerivationStrict,
|
||||
DirOf,
|
||||
Div,
|
||||
Elem,
|
||||
ElemAt,
|
||||
FetchGit,
|
||||
FetchMercurial,
|
||||
FetchTarball,
|
||||
FetchTree,
|
||||
FetchUrl,
|
||||
|
||||
FilterForceList,
|
||||
FilterCallPred,
|
||||
FilterCheck,
|
||||
|
||||
FilterSource,
|
||||
FindFile,
|
||||
Floor,
|
||||
FoldlStrict,
|
||||
FoldlStrictEmpty,
|
||||
FoldlStrictCall1,
|
||||
FoldlStrictCall2,
|
||||
FoldlStrictUpdate,
|
||||
FromJSON,
|
||||
FromTOML,
|
||||
FunctionArgs,
|
||||
GenList,
|
||||
GenericClosure,
|
||||
GetAttr,
|
||||
GetContext,
|
||||
GetEnv,
|
||||
GroupBy,
|
||||
HasAttr,
|
||||
HasContext,
|
||||
HashFile,
|
||||
HashString,
|
||||
Head,
|
||||
Import,
|
||||
IntersectAttrs,
|
||||
IsAttrs,
|
||||
IsBool,
|
||||
IsFloat,
|
||||
IsFunction,
|
||||
IsInt,
|
||||
IsList,
|
||||
IsNull,
|
||||
IsPath,
|
||||
IsString,
|
||||
Length,
|
||||
LessThan,
|
||||
ListToAttrs,
|
||||
Map,
|
||||
MapAttrs,
|
||||
Match,
|
||||
Mul,
|
||||
ParseDrvName,
|
||||
Partition,
|
||||
Path,
|
||||
PathExists,
|
||||
Placeholder,
|
||||
ReadDir,
|
||||
ReadFile,
|
||||
ReadFileType,
|
||||
RemoveAttrs,
|
||||
ReplaceStrings,
|
||||
ScopedImport,
|
||||
Seq,
|
||||
Sort,
|
||||
Split,
|
||||
SplitVersion,
|
||||
StorePath,
|
||||
StringLength,
|
||||
Sub,
|
||||
Substring,
|
||||
Tail,
|
||||
Throw,
|
||||
ToFile,
|
||||
ToJSON,
|
||||
ToPath,
|
||||
ToString,
|
||||
ToXML,
|
||||
Trace,
|
||||
TryEval,
|
||||
TypeOf,
|
||||
UnsafeDiscardStringContext,
|
||||
UnsafeGetAttrPos,
|
||||
Warn,
|
||||
ZipAttrsWith,
|
||||
|
||||
ForceResultShallow,
|
||||
ForceResultShallowPush,
|
||||
ForceResultShallowLoop,
|
||||
ForceResultDeepFinish,
|
||||
|
||||
EqStep,
|
||||
EqForce,
|
||||
|
||||
CallPattern,
|
||||
CallFunctor1,
|
||||
CallFunctor2,
|
||||
|
||||
ImportFinalize,
|
||||
ScopedImportFinalize,
|
||||
|
||||
AppendContextLoop,
|
||||
AppendContextEntryForced,
|
||||
AppendContextOutputsForced,
|
||||
AppendContextOutputElementLoop,
|
||||
AppendContextOutputElementForced,
|
||||
|
||||
UnsafeDiscardOutputDependency,
|
||||
|
||||
Illegal,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for PrimOpPhase {
|
||||
type Error = u8;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
if (0..Self::Illegal as u8).contains(&value) {
|
||||
Ok(unsafe { std::mem::transmute::<u8, Self>(value) })
|
||||
} else {
|
||||
Err(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimOpPhase {
|
||||
pub fn entry_for_builtin(id: BuiltinId) -> Self {
|
||||
use BuiltinId::*;
|
||||
match id {
|
||||
Abort => Self::Abort,
|
||||
Add => Self::Add,
|
||||
AddErrorContext => Self::AddErrorContext,
|
||||
All => Self::All,
|
||||
Any => Self::Any,
|
||||
AppendContext => Self::AppendContext,
|
||||
AttrNames => Self::AttrNames,
|
||||
AttrValues => Self::AttrValues,
|
||||
BaseNameOf => Self::BaseNameOf,
|
||||
BitAnd => Self::BitAnd,
|
||||
BitOr => Self::BitOr,
|
||||
BitXor => Self::BitXor,
|
||||
Break => Self::Break,
|
||||
CatAttrs => Self::CatAttrs,
|
||||
Ceil => Self::Ceil,
|
||||
CompareVersions => Self::CompareVersions,
|
||||
ConcatLists => Self::ConcatLists,
|
||||
ConcatMap => Self::ConcatMap,
|
||||
ConcatStringsSep => Self::ConcatStringsSep,
|
||||
ConvertHash => Self::ConvertHash,
|
||||
DeepSeq => Self::DeepSeq,
|
||||
Derivation => Self::Derivation,
|
||||
DerivationStrict => Self::DerivationStrict,
|
||||
DirOf => Self::DirOf,
|
||||
Div => Self::Div,
|
||||
Elem => Self::Elem,
|
||||
ElemAt => Self::ElemAt,
|
||||
FetchGit => Self::FetchGit,
|
||||
FetchMercurial => Self::FetchMercurial,
|
||||
FetchTarball => Self::FetchTarball,
|
||||
FetchTree => Self::FetchTree,
|
||||
FetchUrl => Self::FetchUrl,
|
||||
Filter => Self::FilterForceList,
|
||||
FilterSource => Self::FilterSource,
|
||||
FindFile => Self::FindFile,
|
||||
Floor => Self::Floor,
|
||||
FoldlStrict => Self::FoldlStrict,
|
||||
FromJSON => Self::FromJSON,
|
||||
FromTOML => Self::FromTOML,
|
||||
FunctionArgs => Self::FunctionArgs,
|
||||
GenList => Self::GenList,
|
||||
GenericClosure => Self::GenericClosure,
|
||||
GetAttr => Self::GetAttr,
|
||||
GetContext => Self::GetContext,
|
||||
GetEnv => Self::GetEnv,
|
||||
GroupBy => Self::GroupBy,
|
||||
HasAttr => Self::HasAttr,
|
||||
HasContext => Self::HasContext,
|
||||
HashFile => Self::HashFile,
|
||||
HashString => Self::HashString,
|
||||
Head => Self::Head,
|
||||
Import => Self::Import,
|
||||
IntersectAttrs => Self::IntersectAttrs,
|
||||
IsAttrs => Self::IsAttrs,
|
||||
IsBool => Self::IsBool,
|
||||
IsFloat => Self::IsFloat,
|
||||
IsFunction => Self::IsFunction,
|
||||
IsInt => Self::IsInt,
|
||||
IsList => Self::IsList,
|
||||
IsNull => Self::IsNull,
|
||||
IsPath => Self::IsPath,
|
||||
IsString => Self::IsString,
|
||||
Length => Self::Length,
|
||||
LessThan => Self::LessThan,
|
||||
ListToAttrs => Self::ListToAttrs,
|
||||
Map => Self::Map,
|
||||
MapAttrs => Self::MapAttrs,
|
||||
Match => Self::Match,
|
||||
Mul => Self::Mul,
|
||||
ParseDrvName => Self::ParseDrvName,
|
||||
Partition => Self::Partition,
|
||||
Path => Self::Path,
|
||||
PathExists => Self::PathExists,
|
||||
Placeholder => Self::Placeholder,
|
||||
ReadDir => Self::ReadDir,
|
||||
ReadFile => Self::ReadFile,
|
||||
ReadFileType => Self::ReadFileType,
|
||||
RemoveAttrs => Self::RemoveAttrs,
|
||||
ReplaceStrings => Self::ReplaceStrings,
|
||||
ScopedImport => Self::ScopedImport,
|
||||
Seq => Self::Seq,
|
||||
Sort => Self::Sort,
|
||||
Split => Self::Split,
|
||||
SplitVersion => Self::SplitVersion,
|
||||
StorePath => Self::StorePath,
|
||||
StringLength => Self::StringLength,
|
||||
Sub => Self::Sub,
|
||||
Substring => Self::Substring,
|
||||
Tail => Self::Tail,
|
||||
Throw => Self::Throw,
|
||||
ToFile => Self::ToFile,
|
||||
ToJSON => Self::ToJSON,
|
||||
ToPath => Self::ToPath,
|
||||
ToString => Self::ToString,
|
||||
ToXML => Self::ToXML,
|
||||
Trace => Self::Trace,
|
||||
TryEval => Self::TryEval,
|
||||
TypeOf => Self::TypeOf,
|
||||
UnsafeDiscardStringContext => Self::UnsafeDiscardStringContext,
|
||||
UnsafeDiscardOutputDependency => Self::UnsafeDiscardOutputDependency,
|
||||
UnsafeGetAttrPos => Self::UnsafeGetAttrPos,
|
||||
Warn => Self::Warn,
|
||||
ZipAttrsWith => Self::ZipAttrsWith,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ip(self) -> u32 {
|
||||
self as u32 * 2
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BytecodeReader<'a> {
|
||||
bytecode: &'a [u8],
|
||||
pc: usize,
|
||||
inst_start_pc: usize,
|
||||
}
|
||||
|
||||
impl<'a> BytecodeReader<'a> {
|
||||
pub fn new(bytecode: &'a [u8], pc: usize) -> Self {
|
||||
Self {
|
||||
bytecode,
|
||||
pc,
|
||||
inst_start_pc: pc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_after_op(bytecode: &'a [u8], inst_start_pc: usize) -> Self {
|
||||
Self {
|
||||
bytecode,
|
||||
pc: inst_start_pc + 1,
|
||||
inst_start_pc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
fn read_array<const N: usize>(&mut self) -> [u8; N] {
|
||||
let ret = self.bytecode[self.pc..self.pc + N]
|
||||
.try_into()
|
||||
.expect("read_array failed");
|
||||
self.pc += N;
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_op(&mut self) -> Op {
|
||||
self.inst_start_pc = self.pc;
|
||||
let byte = self.bytecode[self.pc];
|
||||
if !likely_stable::likely((0..Op::Illegal as u8).contains(&byte)) {
|
||||
panic!("unknown opcode: {byte:#04x}")
|
||||
}
|
||||
self.pc += 1;
|
||||
unsafe { std::mem::transmute::<u8, Op>(byte) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_u8(&mut self) -> u8 {
|
||||
let val = self.bytecode[self.pc];
|
||||
self.pc += 1;
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_u16(&mut self) -> u16 {
|
||||
u16::from_le_bytes(self.read_array())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_u32(&mut self) -> u32 {
|
||||
u32::from_le_bytes(self.read_array())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_i32(&mut self) -> i32 {
|
||||
i32::from_le_bytes(self.read_array())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_i64(&mut self) -> i64 {
|
||||
i64::from_le_bytes(self.read_array())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_f64(&mut self) -> f64 {
|
||||
f64::from_le_bytes(self.read_array())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_string_id(&mut self) -> StringId {
|
||||
let raw = self.read_u32();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
StringId(string_interner::symbol::SymbolU32::try_from_usize(raw as usize).unwrap())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_operand_data(&mut self) -> OperandData {
|
||||
let tag = self.read_u8();
|
||||
let Ok(ty) = OperandType::try_from_primitive(tag)
|
||||
.map_err(|err| panic!("unknown operand tag: {:#04x}", err.number));
|
||||
match ty {
|
||||
OperandType::Const => OperandData::Const(self.read_u32()),
|
||||
OperandType::BigInt => OperandData::BigInt(self.read_i64()),
|
||||
OperandType::Local => {
|
||||
let layer = self.read_u8();
|
||||
let idx = self.read_u32();
|
||||
OperandData::Local { layer, idx }
|
||||
}
|
||||
OperandType::BuiltinConst => OperandData::BuiltinConst(self.read_string_id()),
|
||||
OperandType::Builtins => OperandData::Builtins,
|
||||
OperandType::ReplBinding => OperandData::ReplBinding(self.read_string_id()),
|
||||
OperandType::ScopedImportBinding => {
|
||||
let slot_id = self.read_u32();
|
||||
let name = self.read_string_id();
|
||||
OperandData::ScopedImportBinding { slot_id, name }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pc(&self) -> usize {
|
||||
self.pc
|
||||
}
|
||||
|
||||
pub fn set_pc(&mut self, pc: usize) {
|
||||
self.pc = pc;
|
||||
}
|
||||
|
||||
pub fn inst_start_pc(&self) -> usize {
|
||||
self.inst_start_pc
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user