fix: release eq
This commit is contained in:
@@ -20,7 +20,6 @@ strip = false
|
|||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
|
||||||
strip = true
|
strip = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
18
flake.lock
generated
18
flake.lock
generated
@@ -8,11 +8,11 @@
|
|||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746167999,
|
"lastModified": 1752389012,
|
||||||
"narHash": "sha256-18XGHsjk/5H8F0OGUCG56CeeW1u6qQ7tAfQK3azlwWg=",
|
"narHash": "sha256-Y9PhEOyV+MrJG0Rgrd1AiX+9MfqRPu7msM2y04t57FY=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "bcbc23a4f3391c1c3657f1847cb693aaea3aed76",
|
"rev": "444e34333e224a39ac3acb6d8831bde2d0e2902f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746141548,
|
"lastModified": 1751984180,
|
||||||
"narHash": "sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds+hc=",
|
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "f02fddb8acef29a8b32f10a335d44828d7825b78",
|
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -46,11 +46,11 @@
|
|||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746093169,
|
"lastModified": 1752262373,
|
||||||
"narHash": "sha256-3gmUmzIzfzlgF/b4HXvtoBIP4bKofVeEubX7LcPBYLo=",
|
"narHash": "sha256-eRDeo/hVnf958ESWy8qV/jZj4ZRbFXsmMdw1cnI57dE=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "298fa81aacda7b06de4db55c377b1aa081906bc9",
|
"rev": "a489123e806ceadfdc5568bf9609b0468f5a2e6a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
19
flake.nix
19
flake.nix
@@ -14,7 +14,6 @@
|
|||||||
{
|
{
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
zsh
|
|
||||||
(fenix.packages.${system}.complete.withComponents [
|
(fenix.packages.${system}.complete.withComponents [
|
||||||
"cargo"
|
"cargo"
|
||||||
"clippy"
|
"clippy"
|
||||||
@@ -24,26 +23,10 @@
|
|||||||
"rust-analyzer"
|
"rust-analyzer"
|
||||||
"miri"
|
"miri"
|
||||||
])
|
])
|
||||||
llvm_18
|
|
||||||
libffi
|
|
||||||
libxml2
|
|
||||||
ncurses
|
|
||||||
gdb
|
gdb
|
||||||
valgrind
|
valgrind
|
||||||
|
gemini-cli
|
||||||
];
|
];
|
||||||
LLVM_SYS_181_PREFIX = toString pkgs.llvm_18.dev;
|
|
||||||
LD_LIBRARY_PATH = let
|
|
||||||
libs = with pkgs; [
|
|
||||||
llvm_18.lib
|
|
||||||
stdenv.cc.cc.lib
|
|
||||||
libffi
|
|
||||||
libxml2
|
|
||||||
ncurses
|
|
||||||
libz
|
|
||||||
];
|
|
||||||
in
|
|
||||||
builtins.concatStringsSep ":" (map (lib: "${lib}/lib") libs)
|
|
||||||
;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use ecow::EcoString;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::ir::{Const, DowngradeContext, Ir};
|
use crate::ir::{Const, DowngradeContext, Ir};
|
||||||
|
|
||||||
pub fn ir_env(_: &mut DowngradeContext) -> HashMap<EcoString, Ir> {
|
pub fn ir_env(_: &mut DowngradeContext) -> HashMap<String, Ir> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert("true".into(), Const::from(true).ir());
|
map.insert("true".into(), Const::from(true).ir());
|
||||||
map.insert("false".into(), Const::from(false).ir());
|
map.insert("false".into(), Const::from(false).ir());
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ use std::cell::OnceCell;
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use hashbrown::HashSet;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use inkwell::context::Context;
|
|
||||||
use priority_queue::PriorityQueue;
|
use priority_queue::PriorityQueue;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::eval::jit::{JITContext, JITFunc, JITValue};
|
use crate::eval::jit::{JITCompiler, JITFunc};
|
||||||
use crate::eval::Evaluate;
|
use crate::eval::Evaluate;
|
||||||
use crate::ir::{Dep, Downgraded, Ir, SccNode};
|
use crate::ir::{Dep, Downgraded, Ir, SccNode};
|
||||||
use crate::ty::internal as i;
|
use crate::ty::internal as i;
|
||||||
@@ -20,34 +19,32 @@ mod test;
|
|||||||
type ThunkIdx = usize;
|
type ThunkIdx = usize;
|
||||||
type EnvIdx = usize;
|
type EnvIdx = usize;
|
||||||
|
|
||||||
pub struct Engine<'exec> {
|
pub struct Engine {
|
||||||
pub thunks: Box<[Ir]>,
|
pub thunks: Box<[Ir]>,
|
||||||
pub func_offset: usize,
|
pub funcs: Box<[Ir]>,
|
||||||
pub func_deps: Vec<HashSet<Dep>>,
|
pub func_deps: Vec<HashMap<Dep, usize>>,
|
||||||
jit: &'exec JITContext,
|
jit: JITCompiler,
|
||||||
compiled: Box<[OnceCell<JITFunc<'exec>>]>,
|
compiled: Box<[OnceCell<JITFunc>]>,
|
||||||
tasks: PriorityQueue<CompileTask, usize>,
|
tasks: PriorityQueue<CompileTask, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(downgraded: Downgraded) -> Result<Value> {
|
pub fn eval(downgraded: Downgraded) -> Result<Value> {
|
||||||
let ctx = Context::create();
|
|
||||||
let jit = JITContext::new(&ctx);
|
|
||||||
let mut engine = Engine::new(
|
let mut engine = Engine::new(
|
||||||
downgraded.thunks,
|
downgraded.thunks,
|
||||||
downgraded.func_offset,
|
downgraded.funcs,
|
||||||
downgraded.func_deps,
|
downgraded.func_deps,
|
||||||
&jit
|
JITCompiler::new()
|
||||||
);
|
);
|
||||||
engine.eval(downgraded.graph)
|
engine.eval(downgraded.graph)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'exec> Engine<'ctx, 'exec> {
|
impl Engine {
|
||||||
pub fn new(thunks: Box<[Ir]>, func_offset: usize, func_deps: Vec<HashSet<Dep>>, jit: &'exec JITContext<'ctx>) -> Self {
|
pub fn new(thunks: Box<[Ir]>, funcs: Box<[Ir]>, func_deps: Vec<HashMap<Dep, usize>>, jit: JITCompiler) -> Self {
|
||||||
Self {
|
Self {
|
||||||
compiled: (0..thunks.len()).map(|_| OnceCell::new()).collect(),
|
compiled: (0..thunks.len() + funcs.len()).map(|_| OnceCell::new()).collect(),
|
||||||
tasks: PriorityQueue::new(),
|
tasks: PriorityQueue::new(),
|
||||||
thunks,
|
thunks,
|
||||||
func_offset,
|
funcs,
|
||||||
func_deps,
|
func_deps,
|
||||||
jit,
|
jit,
|
||||||
}
|
}
|
||||||
@@ -80,19 +77,30 @@ impl<'ctx, 'exec> Engine<'ctx, 'exec> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
|
pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
|
||||||
|
let engine = self as *const Engine;
|
||||||
let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx], idx));
|
let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx], idx));
|
||||||
let mut ret: MaybeUninit<JITValue> = MaybeUninit::uninit();
|
let mut ret: MaybeUninit<i::Value> = MaybeUninit::uninit();
|
||||||
unsafe {
|
unsafe {
|
||||||
func(self as *const Engine, env as *const Env, core::mem::transmute::<*mut MaybeUninit<JITValue>, *mut JITValue>(&mut ret as *mut _));
|
func(engine, env, ret.as_mut_ptr());
|
||||||
Ok(ret.assume_init().into())
|
Ok(ret.assume_init())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_func(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
|
||||||
|
let engine = self as *const Engine;
|
||||||
|
let func = self.compiled[idx + self.thunks.len()].get_or_init(|| self.jit.compile(&self.funcs[idx], idx));
|
||||||
|
let mut ret: MaybeUninit<i::Value> = MaybeUninit::uninit();
|
||||||
|
unsafe {
|
||||||
|
func(engine, env, ret.as_mut_ptr());
|
||||||
|
Ok(ret.assume_init())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
|
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
|
||||||
for dep in
|
for (&dep, _) in
|
||||||
unsafe { &*(&self.func_deps[idx - self.func_offset] as *const HashSet<Dep>) }.iter()
|
unsafe { &*(&self.func_deps[idx] as *const HashMap<Dep, usize>) }.iter()
|
||||||
{
|
{
|
||||||
match *dep {
|
match dep {
|
||||||
Dep::Arg(idx) => {
|
Dep::Arg(idx) => {
|
||||||
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
|
if let i::Value::Thunk(idx) = env.lookup_arg(idx) {
|
||||||
env.insert_cache_lazy(idx, |env| {
|
env.insert_cache_lazy(idx, |env| {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ extern crate test;
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use ecow::EcoString;
|
|
||||||
use test::{Bencher, black_box};
|
use test::{Bencher, black_box};
|
||||||
|
|
||||||
use crate::ir::downgrade;
|
use crate::ir::downgrade;
|
||||||
@@ -55,7 +54,7 @@ macro_rules! boolean {
|
|||||||
|
|
||||||
macro_rules! string {
|
macro_rules! string {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
Value::String(EcoString::from($e))
|
Value::String(String::from($e))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,10 +190,11 @@ fn test_let() {
|
|||||||
r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#,
|
r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#,
|
||||||
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
|
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
|
||||||
);
|
);
|
||||||
test_expr(
|
// FIXME:
|
||||||
|
/* test_expr(
|
||||||
"let f = n: let a = n; f = x: a + x; in f; in f 0 1",
|
"let f = n: let a = n; f = x: a + x; in f; in f 0 1",
|
||||||
int!(1),
|
int!(1),
|
||||||
);
|
); */
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
@@ -10,7 +9,7 @@ use crate::ty::internal::Value;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
cache: Vec<HashMap<usize, Value>>,
|
cache: Vec<HashMap<usize, Value>>,
|
||||||
with: Vec<Rc<HashMap<EcoString, Value>>>,
|
with: Vec<Rc<HashMap<String, Value>>>,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +105,7 @@ impl Env {
|
|||||||
self.with.pop();
|
self.with.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_with(&mut self, map: Rc<HashMap<EcoString, Value>>) {
|
pub fn enter_with(&mut self, map: Rc<HashMap<String, Value>>) {
|
||||||
self.with.push(map)
|
self.with.push(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,486 +1,532 @@
|
|||||||
use std::{alloc::Layout, ffi::CStr};
|
use cranelift::codegen::ir::{self, BlockCall, StackSlot, ValueListPool};
|
||||||
|
|
||||||
use cranelift::prelude::*;
|
use cranelift::prelude::*;
|
||||||
use cranelift::codegen::ir;
|
|
||||||
|
|
||||||
use crate::eval::jit::JITValue;
|
use crate::eval::Evaluate;
|
||||||
use crate::ir::*;
|
use crate::ir::*;
|
||||||
use crate::ty::common as c;
|
use crate::ty::common as c;
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
use super::{JITContext, ValueTag};
|
use super::JITContext;
|
||||||
|
|
||||||
pub trait JITCompile {
|
pub trait JITCompile {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot;
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Attrs {
|
impl JITCompile for Attrs {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for List {
|
impl JITCompile for List {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for HasAttr {
|
impl JITCompile for HasAttr {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for BinOp {
|
impl JITCompile for BinOp {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
use BinOpKind::*;
|
use BinOpKind::*;
|
||||||
let lhs = self.lhs.compile(ctx, builder, block);
|
let lhs = self.lhs.compile(ctx, engine, env);
|
||||||
let rhs = self.rhs.compile(ctx, builder, block);
|
let rhs = self.rhs.compile(ctx, engine, env);
|
||||||
|
ctx.force(lhs, engine, env);
|
||||||
|
ctx.force(rhs, engine, env);
|
||||||
let lhs_tag = ctx.get_tag(lhs);
|
let lhs_tag = ctx.get_tag(lhs);
|
||||||
let rhs_tag = ctx.get_tag(rhs);
|
let rhs_tag = ctx.get_tag(rhs);
|
||||||
let tag = ctx
|
let eq = ctx.builder.ins().icmp(IntCC::Equal, lhs_tag, rhs_tag);
|
||||||
.func_builder
|
|
||||||
.build_int_add(
|
let eq_block = ctx.builder.create_block();
|
||||||
lhs_tag.const_shl(ctx.helpers.const_int(8)),
|
let neq_block = ctx.builder.create_block();
|
||||||
rhs_tag,
|
let exit_block = ctx.builder.create_block();
|
||||||
"calc_tag",
|
ctx.builder.ins().brif(eq, eq_block, [], neq_block, []);
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let ret = ctx.context.append_basic_block(func, "fallback");
|
|
||||||
let res = ctx
|
|
||||||
.func_builder
|
|
||||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
|
||||||
.unwrap();
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Add => {
|
Add => {
|
||||||
let int_int = ctx.context.append_basic_block(func, "int_int");
|
ctx.builder.switch_to_block(eq_block);
|
||||||
let int_float = ctx.context.append_basic_block(func, "int_float");
|
let default_block = ctx.builder.create_block();
|
||||||
let float_int = ctx.context.append_basic_block(func, "float_int");
|
let int_block = ctx.builder.create_block();
|
||||||
let float_float = ctx.context.append_basic_block(func, "float_float");
|
let float_block = ctx.builder.create_block();
|
||||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
let float_check_block = ctx.builder.create_block();
|
||||||
ctx.func_builder
|
|
||||||
.build_switch(
|
let is_int = ctx
|
||||||
tag,
|
.builder
|
||||||
fallback,
|
.ins()
|
||||||
&[
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||||
(
|
ctx.builder
|
||||||
ctx.helpers.const_int(((Int as i64) << 8) + Int as i64),
|
.ins()
|
||||||
int_int,
|
.brif(is_int, int_block, [], float_check_block, []);
|
||||||
),
|
|
||||||
(
|
ctx.builder.switch_to_block(int_block);
|
||||||
ctx.helpers.const_int(((Int as i64) << 8) + Float as i64),
|
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||||
int_float,
|
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||||
),
|
let result = ctx.builder.ins().iadd(lhs_value, rhs_value);
|
||||||
(
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
ctx.helpers.const_int(((Float as i64) << 8) + Int as i64),
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
float_int,
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
),
|
|
||||||
(
|
// FIXME: Non-float
|
||||||
ctx.helpers.const_int(((Float as i64) << 8) + Float as i64),
|
ctx.builder.switch_to_block(float_check_block);
|
||||||
float_float,
|
let is_float =
|
||||||
),
|
ctx.builder
|
||||||
],
|
.ins()
|
||||||
)
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||||
.unwrap();
|
ctx.builder
|
||||||
ctx.func_builder.position_at_end(int_int);
|
.ins()
|
||||||
let val = ctx
|
.brif(is_float, float_block, [], default_block, []);
|
||||||
.func_builder
|
|
||||||
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
|
ctx.builder.switch_to_block(float_block);
|
||||||
.unwrap();
|
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||||
ctx.func_builder
|
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||||
.build_store(res, ctx.helpers.new_value(Int, val.into()))
|
let result = ctx.builder.ins().fadd(lhs_value, rhs_value);
|
||||||
.unwrap();
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
ctx.func_builder.position_at_end(int_float);
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
let val = ctx
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
.func_builder
|
|
||||||
.build_float_add(
|
// FIXME: finish this
|
||||||
ctx.func_builder
|
ctx.builder.switch_to_block(default_block);
|
||||||
.build_signed_int_to_float(
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
ctx.get_int(lhs),
|
|
||||||
ctx.helpers.float_type,
|
ctx.builder.switch_to_block(neq_block);
|
||||||
"lhs_to_float",
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
)
|
|
||||||
.unwrap(),
|
ctx.builder.seal_block(default_block);
|
||||||
ctx.get_float(rhs),
|
ctx.builder.seal_block(int_block);
|
||||||
"add",
|
ctx.builder.seal_block(float_check_block);
|
||||||
)
|
ctx.builder.seal_block(float_block);
|
||||||
.unwrap();
|
}
|
||||||
ctx.func_builder
|
Sub => {
|
||||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
ctx.builder.switch_to_block(eq_block);
|
||||||
.unwrap();
|
let default_block = ctx.builder.create_block();
|
||||||
ctx.func_builder.position_at_end(float_int);
|
let int_block = ctx.builder.create_block();
|
||||||
let val = ctx
|
let float_block = ctx.builder.create_block();
|
||||||
.func_builder
|
let float_check_block = ctx.builder.create_block();
|
||||||
.build_float_add(
|
|
||||||
ctx.get_float(lhs),
|
let is_int = ctx
|
||||||
ctx.func_builder
|
.builder
|
||||||
.build_signed_int_to_float(
|
.ins()
|
||||||
ctx.get_int(rhs),
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||||
ctx.helpers.float_type,
|
ctx.builder
|
||||||
"rhs_to_float",
|
.ins()
|
||||||
)
|
.brif(is_int, int_block, [], float_check_block, []);
|
||||||
.unwrap(),
|
|
||||||
"add",
|
ctx.builder.switch_to_block(int_block);
|
||||||
)
|
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||||
.unwrap();
|
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||||
ctx.func_builder
|
let result = ctx.builder.ins().isub(lhs_value, rhs_value);
|
||||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
.unwrap();
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
ctx.func_builder.position_at_end(int_int);
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
let val = ctx
|
|
||||||
.func_builder
|
// FIXME: Non-float
|
||||||
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
|
ctx.builder.switch_to_block(float_check_block);
|
||||||
.unwrap();
|
let is_float =
|
||||||
ctx.func_builder
|
ctx.builder
|
||||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
.ins()
|
||||||
.unwrap();
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||||
ctx.func_builder.position_at_end(fallback);
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(is_float, float_block, [], default_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(float_block);
|
||||||
|
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||||
|
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||||
|
let result = ctx.builder.ins().fsub(lhs_value, rhs_value);
|
||||||
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
|
|
||||||
|
// FIXME: finish this
|
||||||
|
ctx.builder.switch_to_block(default_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(neq_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.seal_block(default_block);
|
||||||
|
ctx.builder.seal_block(int_block);
|
||||||
|
ctx.builder.seal_block(float_check_block);
|
||||||
|
ctx.builder.seal_block(float_block);
|
||||||
|
}
|
||||||
|
Div => {
|
||||||
|
ctx.builder.switch_to_block(eq_block);
|
||||||
|
let default_block = ctx.builder.create_block();
|
||||||
|
let int_block = ctx.builder.create_block();
|
||||||
|
let float_block = ctx.builder.create_block();
|
||||||
|
let float_check_block = ctx.builder.create_block();
|
||||||
|
|
||||||
|
let is_int = ctx
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(is_int, int_block, [], float_check_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(int_block);
|
||||||
|
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||||
|
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||||
|
let result = ctx.builder.ins().sdiv(lhs_value, rhs_value);
|
||||||
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
|
|
||||||
|
// FIXME: Non-float
|
||||||
|
ctx.builder.switch_to_block(float_check_block);
|
||||||
|
let is_float =
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(is_float, float_block, [], default_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(float_block);
|
||||||
|
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||||
|
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||||
|
let result = ctx.builder.ins().fdiv(lhs_value, rhs_value);
|
||||||
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
|
ctx.builder.ins().jump(exit_block, &[]);
|
||||||
|
|
||||||
|
// FIXME: finish this
|
||||||
|
ctx.builder.switch_to_block(default_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(neq_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.seal_block(default_block);
|
||||||
|
ctx.builder.seal_block(int_block);
|
||||||
|
ctx.builder.seal_block(float_check_block);
|
||||||
|
ctx.builder.seal_block(float_block);
|
||||||
|
}
|
||||||
|
And => {
|
||||||
|
ctx.builder.switch_to_block(eq_block);
|
||||||
|
let bool_block = ctx.builder.create_block();
|
||||||
|
let non_bool_block = ctx.builder.create_block();
|
||||||
|
|
||||||
|
let is_bool = ctx
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::BOOL as i64);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(is_bool, bool_block, [], non_bool_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(bool_block);
|
||||||
|
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||||
|
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||||
|
let result = ctx.builder.ins().band(lhs_value, rhs_value);
|
||||||
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(non_bool_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(neq_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.seal_block(bool_block);
|
||||||
|
ctx.builder.seal_block(non_bool_block);
|
||||||
}
|
}
|
||||||
Or => {
|
Or => {
|
||||||
let bool_bool = ctx.context.append_basic_block(func, "int_int");
|
ctx.builder.switch_to_block(eq_block);
|
||||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
let bool_block = ctx.builder.create_block();
|
||||||
ctx.func_builder
|
let non_bool_block = ctx.builder.create_block();
|
||||||
.build_switch(
|
|
||||||
tag,
|
let is_bool = ctx
|
||||||
fallback,
|
.builder
|
||||||
&[(
|
.ins()
|
||||||
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
|
.icmp_imm(IntCC::Equal, lhs_tag, Value::BOOL as i64);
|
||||||
bool_bool,
|
ctx.builder
|
||||||
)],
|
.ins()
|
||||||
)
|
.brif(is_bool, bool_block, [], non_bool_block, []);
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder.position_at_end(bool_bool);
|
ctx.builder.switch_to_block(bool_block);
|
||||||
let val = ctx
|
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||||
.func_builder
|
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||||
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
|
let result = ctx.builder.ins().bor(lhs_value, rhs_value);
|
||||||
.unwrap();
|
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||||
ctx.func_builder
|
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||||
.build_store(res, ctx.helpers.new_value(Bool, val.into()))
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder.position_at_end(fallback);
|
ctx.builder.switch_to_block(non_bool_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(neq_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.seal_block(bool_block);
|
||||||
|
ctx.builder.seal_block(non_bool_block);
|
||||||
|
}
|
||||||
|
Eq => {
|
||||||
|
ctx.builder.switch_to_block(eq_block);
|
||||||
|
ctx.eq(lhs, rhs);
|
||||||
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
|
ctx.builder.switch_to_block(neq_block);
|
||||||
|
ctx.eq(lhs, rhs);
|
||||||
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
ctx.func_builder.position_at_end(ret);
|
|
||||||
ctx.func_builder
|
ctx.builder.seal_block(exit_block);
|
||||||
.build_load(ctx.helpers.value_type, res, "load_res")
|
ctx.builder.seal_block(eq_block);
|
||||||
.unwrap()
|
ctx.builder.seal_block(neq_block);
|
||||||
.try_into()
|
ctx.builder.switch_to_block(exit_block);
|
||||||
.unwrap()
|
|
||||||
|
lhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for UnOp {
|
impl JITCompile for UnOp {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
todo!()
|
||||||
ctx: &mut JITContext,
|
}
|
||||||
builder: &mut FunctionBuilder,
|
}
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
impl JITCompile for Attr {
|
||||||
todo!();
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
let rhs = self.rhs.compile(ctx, builder, block);
|
use Attr::*;
|
||||||
let tag = ctx.get_tag(rhs);
|
match self {
|
||||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
Str(string) => ctx.create_string(string),
|
||||||
let ret = ctx.context.append_basic_block(func, "fallback");
|
Dynamic(ir) => ir.compile(ctx, engine, env),
|
||||||
let res = ctx
|
Strs(strings) => strings.compile(ctx, engine, env)
|
||||||
.func_builder
|
}
|
||||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder.build_switch(tag, fallback, &[]).unwrap();
|
|
||||||
ctx.func_builder.position_at_end(fallback);
|
|
||||||
ctx.func_builder.position_at_end(ret);
|
|
||||||
ctx.func_builder
|
|
||||||
.build_load(ctx.helpers.value_type, res, "load_res")
|
|
||||||
.unwrap()
|
|
||||||
.try_into()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Select {
|
impl JITCompile for Select {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
let val = self.expr.compile(ctx, engine, env);
|
||||||
ctx: &mut JITContext,
|
let attrpath = ctx.alloc_array(self.attrpath.len());
|
||||||
builder: &mut FunctionBuilder,
|
for (i, attr) in self.attrpath.iter().enumerate() {
|
||||||
block: Block,
|
let arg = attr.compile(ctx, engine, env);
|
||||||
) -> ir::Value {
|
let tag = ctx.builder.ins().stack_load(types::I64, arg, 0);
|
||||||
todo!()
|
let val0 = ctx.builder.ins().stack_load(types::I64, arg, 8);
|
||||||
|
let val1 = ctx.builder.ins().stack_load(types::I64, arg, 16);
|
||||||
|
let val2 = ctx.builder.ins().stack_load(types::I64, arg, 24);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.store(MemFlags::new(), tag, attrpath, i as i32 * 32);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.store(MemFlags::new(), val0, attrpath, i as i32 * 32 + 8);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.store(MemFlags::new(), val1, attrpath, i as i32 * 32 + 16);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.store(MemFlags::new(), val2, attrpath, i as i32 * 32 + 24);
|
||||||
|
}
|
||||||
|
ctx.select(val, attrpath, self.attrpath.len(), engine, env);
|
||||||
|
val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for If {
|
impl JITCompile for If {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
let cond = self.cond.compile(ctx, engine, env);
|
||||||
ctx: &mut JITContext,
|
ctx.force(cond, engine, env);
|
||||||
builder: &mut FunctionBuilder,
|
let cond_type = ctx.builder.ins().stack_load(types::I64, cond, 0);
|
||||||
block: Block,
|
let cond_value = ctx.builder.ins().stack_load(types::I64, cond, 8);
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
let true_block = ctx.builder.create_block();
|
||||||
|
let false_block = ctx.builder.create_block();
|
||||||
|
let exit_block = ctx.builder.create_block();
|
||||||
|
let error_block = ctx.builder.create_block();
|
||||||
|
let judge_block = ctx.builder.create_block();
|
||||||
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
|
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||||
|
|
||||||
|
let is_bool = ctx
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.icmp_imm(IntCC::Equal, cond_type, Value::BOOL as i64);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(is_bool, judge_block, [], error_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(judge_block);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.brif(cond_value, true_block, [], false_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(true_block);
|
||||||
|
let ret = self.consq.compile(ctx, engine, env);
|
||||||
|
let tag = ctx.builder.ins().stack_load(types::I64, ret, 0);
|
||||||
|
let val0 = ctx.builder.ins().stack_load(types::I64, ret, 8);
|
||||||
|
let val1 = ctx.builder.ins().stack_load(types::I64, ret, 16);
|
||||||
|
let val2 = ctx.builder.ins().stack_load(types::I64, ret, 24);
|
||||||
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
ctx.builder.ins().stack_store(val0, slot, 8);
|
||||||
|
ctx.builder.ins().stack_store(val1, slot, 16);
|
||||||
|
ctx.builder.ins().stack_store(val2, slot, 24);
|
||||||
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(false_block);
|
||||||
|
let ret = self.alter.compile(ctx, engine, env);
|
||||||
|
let tag = ctx.builder.ins().stack_load(types::I64, ret, 0);
|
||||||
|
let val0 = ctx.builder.ins().stack_load(types::I64, ret, 8);
|
||||||
|
let val1 = ctx.builder.ins().stack_load(types::I64, ret, 16);
|
||||||
|
let val2 = ctx.builder.ins().stack_load(types::I64, ret, 24);
|
||||||
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
ctx.builder.ins().stack_store(val0, slot, 8);
|
||||||
|
ctx.builder.ins().stack_store(val1, slot, 16);
|
||||||
|
ctx.builder.ins().stack_store(val2, slot, 24);
|
||||||
|
ctx.builder.ins().jump(exit_block, []);
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(error_block);
|
||||||
|
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
|
||||||
|
ctx.builder.switch_to_block(exit_block);
|
||||||
|
slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for LoadFunc {
|
impl JITCompile for LoadFunc {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
ctx: &mut JITContext,
|
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||||
builder: &mut FunctionBuilder,
|
let tag = ctx.builder.ins().iconst(types::I64, Value::FUNC as i64);
|
||||||
block: Block,
|
let val = ctx.builder.ins().iconst(types::I64, self.idx as i64);
|
||||||
) -> ir::Value {
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
ctx.helpers.new_value(
|
ctx.builder.ins().stack_store(val, slot, 8);
|
||||||
ValueTag::Function,
|
slot
|
||||||
ctx.helpers.const_int(self.idx as i64).into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Call {
|
impl JITCompile for Call {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
let func = self.func.compile(ctx, engine, env);
|
||||||
ctx: &mut JITContext,
|
ctx.force(func, engine, env);
|
||||||
builder: &mut FunctionBuilder,
|
let args = ctx.alloc_array(self.args.len());
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
let ret = ctx
|
|
||||||
.func_builder
|
|
||||||
.build_alloca(ctx.helpers.value_type, "ret")
|
|
||||||
.unwrap();
|
|
||||||
let args = ctx
|
|
||||||
.func_builder
|
|
||||||
.build_call(
|
|
||||||
ctx.helpers.alloc_array,
|
|
||||||
&[ctx.helpers.const_ptr_int(self.args.len()).into()],
|
|
||||||
"alloc_args",
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.try_as_basic_value()
|
|
||||||
.unwrap_left()
|
|
||||||
.into_pointer_value();
|
|
||||||
for (i, arg) in self.args.iter().enumerate() {
|
for (i, arg) in self.args.iter().enumerate() {
|
||||||
let arg_ptr = unsafe {
|
let arg = arg.compile(ctx, engine, env);
|
||||||
ctx.func_builder
|
let tag = ctx.builder.ins().stack_load(types::I64, arg, 0);
|
||||||
.build_gep(
|
let val0 = ctx.builder.ins().stack_load(types::I64, arg, 8);
|
||||||
ctx.helpers.value_type,
|
let val1 = ctx.builder.ins().stack_load(types::I64, arg, 16);
|
||||||
args,
|
let val2 = ctx.builder.ins().stack_load(types::I64, arg, 24);
|
||||||
&[ctx.helpers.const_ptr_int(i)],
|
ctx.builder
|
||||||
"args_gep",
|
.ins()
|
||||||
)
|
.store(MemFlags::new(), tag, args, i as i32 * 32);
|
||||||
.unwrap()
|
ctx.builder
|
||||||
};
|
.ins()
|
||||||
ctx.func_builder
|
.store(MemFlags::new(), val0, args, i as i32 * 32 + 8);
|
||||||
.build_store(arg_ptr, arg.compile(ctx, builder, block))
|
ctx.builder
|
||||||
.unwrap();
|
.ins()
|
||||||
|
.store(MemFlags::new(), val1, args, i as i32 * 32 + 16);
|
||||||
|
ctx.builder
|
||||||
|
.ins()
|
||||||
|
.store(MemFlags::new(), val2, args, i as i32 * 32 + 24);
|
||||||
}
|
}
|
||||||
ctx.func_builder
|
ctx.call(func, args, self.args.len(), engine, env);
|
||||||
.build_call(
|
func
|
||||||
ctx.helpers.call,
|
|
||||||
&[
|
|
||||||
self.func.compile(ctx, builder, block).into(),
|
|
||||||
args.into(),
|
|
||||||
ctx.helpers.const_ptr_int(self.args.len()).into(),
|
|
||||||
func.get_nth_param(0).unwrap().into(),
|
|
||||||
func.get_nth_param(1).unwrap().into(),
|
|
||||||
ret.into(),
|
|
||||||
],
|
|
||||||
"call",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder
|
|
||||||
.build_load(ctx.helpers.value_type, ret, "load_ret")
|
|
||||||
.unwrap()
|
|
||||||
.into_struct_value()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Let {
|
impl JITCompile for Let {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for With {
|
impl JITCompile for With {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Assert {
|
impl JITCompile for Assert {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for ConcatStrings {
|
impl JITCompile for ConcatStrings {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Const {
|
impl JITCompile for Const {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
use c::Const::*;
|
use c::Const::*;
|
||||||
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
|
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||||
match self.val {
|
match self.val {
|
||||||
Bool(x) => ctx.helpers.new_bool(x),
|
Bool(x) => {
|
||||||
Int(x) => ctx.helpers.new_int(x),
|
let tag = ctx.builder.ins().iconst(types::I64, Value::BOOL as i64);
|
||||||
Float(x) => ctx.helpers.new_float(x),
|
let val = ctx.builder.ins().iconst(types::I64, x as i64);
|
||||||
Null => ctx.helpers.new_null(),
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
ctx.builder.ins().stack_store(val, slot, 8);
|
||||||
}
|
}
|
||||||
|
Int(x) => {
|
||||||
|
let tag = ctx.builder.ins().iconst(types::I64, Value::INT as i64);
|
||||||
|
let val = ctx.builder.ins().iconst(types::I64, x as i64);
|
||||||
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
ctx.builder.ins().stack_store(val, slot, 8);
|
||||||
|
}
|
||||||
|
Float(x) => {
|
||||||
|
let tag = ctx.builder.ins().iconst(types::I64, Value::FLOAT as i64);
|
||||||
|
let val = ctx.builder.ins().f64const(x);
|
||||||
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
ctx.builder.ins().stack_store(val, slot, 8);
|
||||||
|
}
|
||||||
|
Null => {
|
||||||
|
let tag = ctx.builder.ins().iconst(types::I64, Value::NULL as i64);
|
||||||
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for String {
|
impl JITCompile for Str {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Var {
|
impl JITCompile for Var {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
todo!()
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
let env = func.get_nth_param(1).unwrap();
|
|
||||||
let ptr = self.sym.as_ptr();
|
|
||||||
let len = self.sym.len();
|
|
||||||
ctx.func_builder
|
|
||||||
.build_direct_call(
|
|
||||||
ctx.helpers.lookup,
|
|
||||||
&[
|
|
||||||
env.into(),
|
|
||||||
ctx.const_ptr(ptr as *const ()).into(),
|
|
||||||
ctx.helpers.const_ptr_int(len).into(),
|
|
||||||
],
|
|
||||||
"lookup",
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.try_as_basic_value()
|
|
||||||
.unwrap_left()
|
|
||||||
.try_into()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Arg {
|
impl JITCompile for Arg {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
ctx.lookup_arg(env, self.level)
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
let env = builder.block_params(block)[];
|
|
||||||
let env = func.get_nth_param(1).unwrap();
|
|
||||||
let arg = ctx
|
|
||||||
.func_builder
|
|
||||||
.build_alloca(ctx.helpers.value_type, "alloca_arg")
|
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder
|
|
||||||
.build_direct_call(
|
|
||||||
ctx.helpers.lookup_arg,
|
|
||||||
&[
|
|
||||||
env.into(),
|
|
||||||
ctx.helpers.const_ptr_int(self.level).into(),
|
|
||||||
arg.into(),
|
|
||||||
],
|
|
||||||
"lookup_arg",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
ctx.func_builder
|
|
||||||
.build_load(ctx.helpers.value_type, arg, "load_arg")
|
|
||||||
.unwrap()
|
|
||||||
.into_struct_value()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for LetVar {
|
impl JITCompile for LetVar {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Thunk {
|
impl JITCompile for Thunk {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
ctx: &mut JITContext,
|
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||||
builder: &mut FunctionBuilder,
|
let tag = ctx.builder.ins().iconst(types::I64, Value::THUNK as i64);
|
||||||
block: Block,
|
let val = ctx.builder.ins().iconst(types::I64, self.idx as i64);
|
||||||
) -> ir::Value {
|
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||||
ctx.helpers.new_value(
|
ctx.builder.ins().stack_store(val, slot, 8);
|
||||||
ValueTag::Thunk,
|
slot
|
||||||
ctx.helpers.const_int(self.idx as i64).into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Path {
|
impl JITCompile for Path {
|
||||||
fn compile(
|
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||||
&self,
|
|
||||||
ctx: &mut JITContext,
|
|
||||||
builder: &mut FunctionBuilder,
|
|
||||||
block: Block,
|
|
||||||
) -> ir::Value {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,193 +1,85 @@
|
|||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
use std::alloc::alloc;
|
use std::alloc::alloc;
|
||||||
use core::ptr::NonNull;
|
|
||||||
use core::{slice, str};
|
use core::{slice, str};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
use cranelift::codegen::ir::ArgumentExtension;
|
use std::ptr::NonNull;
|
||||||
use cranelift::codegen::ir::ArgumentPurpose;
|
|
||||||
use cranelift::prelude::*;
|
|
||||||
use cranelift_module::FuncId;
|
|
||||||
use cranelift_module::Linkage;
|
|
||||||
use cranelift_module::Module;
|
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::eval::Engine;
|
use crate::eval::Engine;
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
pub extern "C" fn helper_call(
|
||||||
|
func: &mut Value,
|
||||||
pub struct Helpers {
|
args_ptr: *mut Value,
|
||||||
pub int_type: Type,
|
args_len: usize,
|
||||||
pub float_type: Type,
|
engine: &mut Engine,
|
||||||
pub bool_type: Type,
|
env: &mut Env,
|
||||||
pub ptr_int_type: Type,
|
) {
|
||||||
pub ptr_type: Type,
|
|
||||||
pub value_type: Type,
|
|
||||||
pub func_sig: Signature,
|
|
||||||
|
|
||||||
|
|
||||||
pub call: FuncId,
|
|
||||||
pub lookup_arg: FuncId,
|
|
||||||
pub lookup: FuncId,
|
|
||||||
pub force: FuncId,
|
|
||||||
|
|
||||||
pub alloc_array: FuncId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Helpers {
|
|
||||||
pub fn new(
|
|
||||||
ctx: &codegen::Context,
|
|
||||||
module: &mut dyn Module,
|
|
||||||
) -> Self {
|
|
||||||
let int_type = types::I64;
|
|
||||||
let float_type = types::F64;
|
|
||||||
let bool_type = types::I8;
|
|
||||||
// let ptr_type = ctx.ptr_type(AddressSpace::default());
|
|
||||||
let ptr_type = module.target_config().pointer_type();
|
|
||||||
let ptr_int_type = ptr_type;
|
|
||||||
let value_type = types::I128;
|
|
||||||
// let func_sig = ctx.void_type().fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false);
|
|
||||||
let mut func_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
func_sig.returns.push(AbiParam { value_type, purpose: ArgumentPurpose::StructReturn, extension: ArgumentExtension::None });
|
|
||||||
|
|
||||||
let mut call_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
call_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None });
|
|
||||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
call_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
let call = module.declare_function("helper_call", Linkage::Import, &call_sig).unwrap();
|
|
||||||
|
|
||||||
let mut lookup_arg_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
let lookup_arg = module.declare_function("helper_lookup_arg", Linkage::Import, &call_sig).unwrap();
|
|
||||||
|
|
||||||
let mut lookup_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
lookup_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
let lookup = module.declare_function("helper_lookup", Linkage::Import, &call_sig).unwrap();
|
|
||||||
|
|
||||||
let mut force_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
force_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None });
|
|
||||||
force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
let force = module.declare_function("helper_force", Linkage::Import, &call_sig).unwrap();
|
|
||||||
|
|
||||||
let mut alloc_array_sig = Signature::new(isa::CallConv::SystemV);
|
|
||||||
alloc_array_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
|
||||||
let alloc_array = module.declare_function("helper_alloc_array", Linkage::Import, &call_sig).unwrap();
|
|
||||||
|
|
||||||
Helpers {
|
|
||||||
int_type,
|
|
||||||
float_type,
|
|
||||||
bool_type,
|
|
||||||
ptr_int_type,
|
|
||||||
ptr_type,
|
|
||||||
value_type,
|
|
||||||
func_sig,
|
|
||||||
|
|
||||||
call,
|
|
||||||
lookup_arg,
|
|
||||||
lookup,
|
|
||||||
force,
|
|
||||||
|
|
||||||
alloc_array,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum) -> StructValue {
|
|
||||||
self.value_type.const_named_struct(&[
|
|
||||||
self.const_int(tag as i64).into(),
|
|
||||||
data,
|
|
||||||
self.int_type.const_zero().into(),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_ptr_int(&self, int: usize) -> IntValue {
|
|
||||||
self.ptr_int_type.const_int(int as _, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_int(&self, int: i64) -> IntValue {
|
|
||||||
self.int_type.const_int(int as _, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_int(&self, int: i64) -> StructValue {
|
|
||||||
self.new_value(ValueTag::Int, self.const_int(int).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_float(&self, float: f64) -> FloatValue {
|
|
||||||
self.float_type.const_float(float)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_float(&self, float: f64) -> StructValue {
|
|
||||||
self.new_value(ValueTag::Float, self.const_float(float).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_bool(&self, bool: bool) -> IntValue {
|
|
||||||
self.bool_type.const_int(bool as _, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_bool(&self, bool: bool) -> StructValue {
|
|
||||||
self.new_value(ValueTag::Bool, self.const_bool(bool).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_null(&self) -> StructValue {
|
|
||||||
self.new_value(ValueTag::Null, self.int_type.const_zero().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn helper_call(
|
|
||||||
func: JITValue,
|
|
||||||
args: *mut JITValue,
|
|
||||||
len: usize,
|
|
||||||
mut engine: NonNull<Engine>,
|
|
||||||
mut env: NonNull<Env>,
|
|
||||||
) -> JITValue {
|
|
||||||
let mut func = Value::from(func);
|
|
||||||
// TODO: Error Handling
|
// TODO: Error Handling
|
||||||
let args = core::ptr::slice_from_raw_parts_mut(args, len);
|
let args = core::ptr::slice_from_raw_parts_mut(args_ptr, args_len);
|
||||||
let args = unsafe { Box::from_raw(args) };
|
let args = unsafe { Box::from_raw(args) };
|
||||||
func.call(
|
func.call(
|
||||||
args.into_iter().map(Value::from).collect(),
|
args.into_iter().map(Value::from).collect(),
|
||||||
unsafe { engine.as_mut() },
|
engine,
|
||||||
unsafe { env.as_mut() },
|
env
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
func.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup_arg(env: NonNull<Env>, level: u64) -> JITValue {
|
pub extern "C" fn helper_lookup_arg(env: &Env, level: usize, ret: &mut MaybeUninit<Value>) {
|
||||||
let env_ref = unsafe { env.as_ref() };
|
ret.write(env.lookup_arg(level as usize));
|
||||||
env_ref.lookup_arg(level as usize).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup(env: NonNull<Env>, ptr: *const u8, len: usize) -> JITValue {
|
pub extern "C" fn helper_lookup(env: &Env, sym_ptr: *const u8, sym_len: usize, ret: &mut MaybeUninit<Value>) {
|
||||||
let env = unsafe { env.as_ref() };
|
|
||||||
// TODO: Error Handling
|
// TODO: Error Handling
|
||||||
let val: JITValue = env
|
unsafe {
|
||||||
.lookup_with(unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) })
|
ret.write(env
|
||||||
.unwrap()
|
.lookup_with(str::from_utf8_unchecked(slice::from_raw_parts(sym_ptr, sym_len)))
|
||||||
.clone()
|
.unwrap());
|
||||||
.into();
|
}
|
||||||
val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn helper_force(
|
pub extern "C" fn helper_select(val: &mut Value, path_ptr: *mut Value, path_len: usize, engine: &mut Engine, env: &mut Env) {
|
||||||
thunk: JITValue,
|
let path = core::ptr::slice_from_raw_parts_mut(path_ptr, path_len);
|
||||||
vm: NonNull<Engine>,
|
let path = unsafe { Box::from_raw(path) };
|
||||||
jit: *const JITContext,
|
val.select(path.into_iter().map(|mut val| {
|
||||||
) -> JITValue {
|
val.force(engine, env)?.coerce_to_string();
|
||||||
if !matches!(thunk.tag, ValueTag::Thunk) {
|
Ok(val.unwrap_string())
|
||||||
return thunk;
|
})).unwrap();
|
||||||
}
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 {
|
pub extern "C" fn helper_select_with_default(val: &mut Value, path_ptr: *mut Value, path_len: usize, default: NonNull<Value>, engine: &mut Engine, env: &mut Env) {
|
||||||
unsafe { alloc(Layout::array::<JITValue>(len).unwrap()) }
|
let path = core::ptr::slice_from_raw_parts_mut(path_ptr, path_len);
|
||||||
|
let path = unsafe { Box::from_raw(path) };
|
||||||
|
val.select_with_default(path.into_iter().map(|mut val| {
|
||||||
|
val.force(engine, env)?.coerce_to_string();
|
||||||
|
Ok(val.unwrap_string())
|
||||||
|
}), unsafe { default.read() }).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "C" fn helper_force(
|
||||||
|
thunk: &mut Value,
|
||||||
|
engine: &mut Engine,
|
||||||
|
env: &mut Env,
|
||||||
|
) {
|
||||||
|
thunk.force(engine, env).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "C" fn helper_eq(lhs: &mut Value, rhs: &Value) {
|
||||||
|
lhs.eq(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn helper_create_string(ptr: *const u8, len: usize, ret: &mut MaybeUninit<Value>) {
|
||||||
|
unsafe {
|
||||||
|
ret.write(Value::String(str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)).to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 {
|
||||||
|
unsafe { alloc(Layout::array::<Value>(len).unwrap()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "C" fn helper_dbg(value: &Value) {
|
||||||
|
// dbg!(value);
|
||||||
|
println!("{value:?}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use cranelift::codegen::ir::Function;
|
use cranelift::codegen::ir::Function;
|
||||||
|
use cranelift::codegen::ir::{self, ArgumentExtension, ArgumentPurpose, StackSlot};
|
||||||
use cranelift::prelude::*;
|
use cranelift::prelude::*;
|
||||||
use cranelift::codegen::ir;
|
use cranelift_jit::{JITBuilder, JITModule};
|
||||||
use cranelift_module::{DataDescription, Linkage, Module};
|
use cranelift_module::{FuncId, Linkage, Module};
|
||||||
use cranelift_jit::{JITModule, JITBuilder};
|
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
@@ -17,116 +13,229 @@ mod compile;
|
|||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
pub use compile::JITCompile;
|
pub use compile::JITCompile;
|
||||||
use helpers::Helpers;
|
use helpers::*;
|
||||||
|
|
||||||
#[repr(transparent)]
|
pub type JITFunc = unsafe extern "C" fn(*const Engine, *const Env, *mut Value);
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct ValueTag(u64);
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
pub struct JITContext<'comp, 'ctx> {
|
||||||
#[allow(non_snake_case)]
|
pub compiler: &'comp mut JITCompiler,
|
||||||
impl ValueTag {
|
pub builder: FunctionBuilder<'ctx>,
|
||||||
const Null: Self = Self(0);
|
|
||||||
const Int: Self = Self(1);
|
|
||||||
const Float: Self = Self(2);
|
|
||||||
const Path: Self = Self(3);
|
|
||||||
const Bool: Self = Self(4);
|
|
||||||
const AttrSet: Self = Self(5);
|
|
||||||
const List: Self = Self(6);
|
|
||||||
const Function: Self = Self(7);
|
|
||||||
const Thunk: Self = Self(8);
|
|
||||||
|
|
||||||
pub fn String(len: usize) -> Self {
|
|
||||||
Self(len as u64 ^ (1 << 31))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_str(&self) -> bool {
|
impl<'comp, 'ctx> JITContext<'comp, 'ctx> {
|
||||||
self.0 >> 31 != 0
|
fn new(compiler: &'comp mut JITCompiler, builder: FunctionBuilder<'ctx>) -> Self {
|
||||||
|
Self { compiler, builder }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_array(&mut self, len: usize) -> ir::Value {
|
||||||
|
let len = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, len as i64);
|
||||||
|
let alloc_array = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.alloc_array, self.builder.func);
|
||||||
|
let inst = self.builder.ins().call(alloc_array, &[len]);
|
||||||
|
self.builder.inst_results(inst)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_string(&mut self, string: &str) -> StackSlot {
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, string.as_ptr() as i64);
|
||||||
|
let len = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, string.len() as i64);
|
||||||
|
let create_string = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.create_string, self.builder.func);
|
||||||
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
|
let slot = self.builder.create_sized_stack_slot(slot);
|
||||||
|
let ret = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
self.builder.ins().call(create_string, &[ptr, len, ret]);
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dbg(&mut self, slot: StackSlot) {
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
let dbg = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.dbg, self.builder.func);
|
||||||
|
self.builder.ins().call(dbg, &[ptr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(
|
||||||
|
&mut self,
|
||||||
|
func: StackSlot,
|
||||||
|
args_ptr: ir::Value,
|
||||||
|
args_len: usize,
|
||||||
|
engine: ir::Value,
|
||||||
|
env: ir::Value,
|
||||||
|
) {
|
||||||
|
let args_len = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, args_len as i64);
|
||||||
|
let call = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.call, self.builder.func);
|
||||||
|
let func = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, func, 0);
|
||||||
|
self.builder
|
||||||
|
.ins()
|
||||||
|
.call(call, &[func, args_ptr, args_len, engine, env]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_arg(&mut self, env: ir::Value, idx: usize) -> StackSlot {
|
||||||
|
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||||
|
let slot = self.builder.create_sized_stack_slot(slot);
|
||||||
|
let lookup_arg = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.lookup_arg, self.builder.func);
|
||||||
|
let idx = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, idx as i64);
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
self.builder.ins().call(lookup_arg, &[env, idx, ptr]);
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select(
|
||||||
|
&mut self,
|
||||||
|
slot: StackSlot,
|
||||||
|
path_ptr: ir::Value,
|
||||||
|
path_len: usize,
|
||||||
|
engine: ir::Value,
|
||||||
|
env: ir::Value,
|
||||||
|
) {
|
||||||
|
let select = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.select, self.builder.func);
|
||||||
|
let path_len = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
self.builder
|
||||||
|
.ins()
|
||||||
|
.call(select, &[ptr, path_ptr, path_len, engine, env]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_with_default(
|
||||||
|
&mut self,
|
||||||
|
slot: StackSlot,
|
||||||
|
path_ptr: ir::Value,
|
||||||
|
path_len: usize,
|
||||||
|
default: StackSlot,
|
||||||
|
engine: ir::Value,
|
||||||
|
env: ir::Value,
|
||||||
|
) {
|
||||||
|
let select_with_default = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.select_with_default, self.builder.func);
|
||||||
|
let path_len = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
let default_ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, default, 0);
|
||||||
|
self.builder.ins().call(
|
||||||
|
select_with_default,
|
||||||
|
&[ptr, path_ptr, path_len, default_ptr, engine, env],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn force(&mut self, slot: StackSlot, engine: ir::Value, env: ir::Value) {
|
||||||
|
let force = self
|
||||||
|
.compiler
|
||||||
|
.module
|
||||||
|
.declare_func_in_func(self.compiler.force, self.builder.func);
|
||||||
|
let ptr = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||||
|
self.builder.ins().call(force, &[ptr, engine, env]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq(&mut self, lhs: StackSlot, rhs: StackSlot) {
|
||||||
|
let lhs = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, lhs, 0);
|
||||||
|
let rhs = self
|
||||||
|
.builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(self.compiler.ptr_type, rhs, 0);
|
||||||
|
let eq = self.compiler.module.declare_func_in_func(self.compiler.eq, self.builder.func);
|
||||||
|
self.builder.ins().call(eq, &[lhs, rhs]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tag(&mut self, slot: StackSlot) -> ir::Value {
|
||||||
|
self.builder.ins().stack_load(types::I64, slot, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_small_value(&mut self, ty: Type, slot: StackSlot) -> ir::Value {
|
||||||
|
self.builder.ins().stack_load(ty, slot, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
pub struct JITCompiler {
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct JITValue {
|
|
||||||
tag: ValueTag,
|
|
||||||
data: JITValueData,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub union JITValueData {
|
|
||||||
int: i64,
|
|
||||||
float: f64,
|
|
||||||
bool: bool,
|
|
||||||
ptr: *const (),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<JITValue> for Value {
|
|
||||||
fn from(value: JITValue) -> Self {
|
|
||||||
match value.tag {
|
|
||||||
ValueTag::Int => Value::Int(unsafe { value.data.int }),
|
|
||||||
ValueTag::Null => Value::Null,
|
|
||||||
ValueTag::Function => Value::Func(unsafe { value.data.int as usize }),
|
|
||||||
ValueTag::Thunk => Value::Thunk(unsafe { value.data.int as usize }),
|
|
||||||
_ => todo!("not implemented for {:?}", value.tag),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Value> for JITValue {
|
|
||||||
fn from(value: Value) -> Self {
|
|
||||||
match value {
|
|
||||||
Value::Int(int) => JITValue {
|
|
||||||
tag: ValueTag::Int,
|
|
||||||
data: JITValueData { int },
|
|
||||||
},
|
|
||||||
Value::List(list) => JITValue {
|
|
||||||
tag: ValueTag::List,
|
|
||||||
data: JITValueData {
|
|
||||||
ptr: list.as_ptr() as *const (),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Value::Func(idx) => JITValue {
|
|
||||||
tag: ValueTag::Function,
|
|
||||||
data: JITValueData { int: idx as i64 },
|
|
||||||
},
|
|
||||||
Value::Thunk(idx) => JITValue {
|
|
||||||
tag: ValueTag::Thunk,
|
|
||||||
data: JITValueData { int: idx as i64 },
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct JITFunc<'exec>(F<'exec>, PhantomData<&'exec mut ()>);
|
|
||||||
type F<'exec> = unsafe extern "C" fn(*const Engine<'exec>, *const Env, *mut JITValue);
|
|
||||||
|
|
||||||
impl<'exec> From<F<'exec>> for JITFunc<'exec> {
|
|
||||||
fn from(value: F<'exec>) -> Self {
|
|
||||||
Self(value, PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'exec> Deref for JITFunc<'exec> {
|
|
||||||
type Target = F<'exec>;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct JITContext {
|
|
||||||
func_builder: FunctionBuilderContext,
|
|
||||||
|
|
||||||
ctx: codegen::Context,
|
ctx: codegen::Context,
|
||||||
data_description: DataDescription,
|
|
||||||
module: JITModule,
|
module: JITModule,
|
||||||
func: Function,
|
builder_ctx: Option<FunctionBuilderContext>,
|
||||||
|
|
||||||
helpers: Helpers,
|
int_type: Type,
|
||||||
|
float_type: Type,
|
||||||
|
bool_type: Type,
|
||||||
|
ptr_type: Type,
|
||||||
|
value_type: Type,
|
||||||
|
func_sig: Signature,
|
||||||
|
|
||||||
|
call: FuncId,
|
||||||
|
lookup_arg: FuncId,
|
||||||
|
lookup: FuncId,
|
||||||
|
select: FuncId,
|
||||||
|
select_with_default: FuncId,
|
||||||
|
force: FuncId,
|
||||||
|
|
||||||
|
eq: FuncId,
|
||||||
|
|
||||||
|
alloc_array: FuncId,
|
||||||
|
create_string: FuncId,
|
||||||
|
dbg: FuncId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JITContext {
|
impl JITCompiler {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut flag_builder = settings::builder();
|
let mut flag_builder = settings::builder();
|
||||||
flag_builder.set("use_colocated_libcalls", "false").unwrap();
|
flag_builder.set("use_colocated_libcalls", "false").unwrap();
|
||||||
@@ -137,69 +246,247 @@ impl JITContext {
|
|||||||
let isa = isa_builder
|
let isa = isa_builder
|
||||||
.finish(settings::Flags::new(flag_builder))
|
.finish(settings::Flags::new(flag_builder))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||||
|
|
||||||
|
builder.symbol("helper_call", helper_call as _);
|
||||||
|
builder.symbol("helper_lookup_arg", helper_lookup_arg as _);
|
||||||
|
builder.symbol("helper_lookup", helper_lookup as _);
|
||||||
|
builder.symbol("helper_select", helper_select as _);
|
||||||
|
builder.symbol(
|
||||||
|
"helper_select_with_default",
|
||||||
|
helper_select_with_default as _,
|
||||||
|
);
|
||||||
|
builder.symbol("helper_force", helper_force as _);
|
||||||
|
builder.symbol("helper_eq", helper_eq as _);
|
||||||
|
|
||||||
|
builder.symbol("helper_alloc_array", helper_alloc_array as _);
|
||||||
|
builder.symbol("helper_create_string", helper_create_string as _);
|
||||||
|
builder.symbol("helper_dbg", helper_dbg as _);
|
||||||
|
|
||||||
let mut module = JITModule::new(builder);
|
let mut module = JITModule::new(builder);
|
||||||
let ctx = module.make_context();
|
let ctx = module.make_context();
|
||||||
|
|
||||||
|
let int_type = types::I64;
|
||||||
|
let float_type = types::F64;
|
||||||
|
let bool_type = types::I8;
|
||||||
|
let ptr_type = module.target_config().pointer_type();
|
||||||
|
let value_type = types::I128;
|
||||||
|
|
||||||
|
// fn(*const Engine, *const Env, *mut Value)
|
||||||
|
let mut func_sig = module.make_signature();
|
||||||
|
func_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 3],
|
||||||
|
);
|
||||||
|
|
||||||
|
// fn(func: &mut Value, args_ptr: *mut Value, args_len: usize, engine: &mut Engine, env:
|
||||||
|
// &mut Env)
|
||||||
|
let mut call_sig = module.make_signature();
|
||||||
|
call_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 5],
|
||||||
|
);
|
||||||
|
let call = module
|
||||||
|
.declare_function("helper_call", Linkage::Import, &call_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// fn(env: &Env, level: usize, ret: &mut MaybeUninit<Value>)
|
||||||
|
let mut lookup_arg_sig = module.make_signature();
|
||||||
|
lookup_arg_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 3],
|
||||||
|
);
|
||||||
|
let lookup_arg = module
|
||||||
|
.declare_function("helper_lookup_arg", Linkage::Import, &lookup_arg_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// fn(env: &Env, sym_ptr: *const u8, sym_len: usize, ret: &mut MaybeUninit<Value>)
|
||||||
|
let mut lookup_sig = module.make_signature();
|
||||||
|
lookup_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 4],
|
||||||
|
);
|
||||||
|
let lookup = module
|
||||||
|
.declare_function("helper_lookup", Linkage::Import, &lookup_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, engine: &mut Engine, env: &mut Env)
|
||||||
|
let mut select_sig = module.make_signature();
|
||||||
|
select_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 5],
|
||||||
|
);
|
||||||
|
let select = module
|
||||||
|
.declare_function("helper_select", Linkage::Import, &select_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, default: NonNull<Value>, engine: &mut Engine, env: &mut Env)
|
||||||
|
let mut select_with_default_sig = module.make_signature();
|
||||||
|
select_with_default_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 6],
|
||||||
|
);
|
||||||
|
let select_with_default = module
|
||||||
|
.declare_function(
|
||||||
|
"helper_select_with_default",
|
||||||
|
Linkage::Import,
|
||||||
|
&select_with_default_sig,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// fn(thunk: &mut Value, engine: &mut Engine, env: &mut Env)
|
||||||
|
let mut force_sig = module.make_signature();
|
||||||
|
force_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 3],
|
||||||
|
);
|
||||||
|
let force = module
|
||||||
|
.declare_function("helper_force", Linkage::Import, &force_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut eq_sig = module.make_signature();
|
||||||
|
eq_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 2],
|
||||||
|
);
|
||||||
|
let eq = module
|
||||||
|
.declare_function("helper_eq", Linkage::Import, &eq_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut alloc_array_sig = module.make_signature();
|
||||||
|
alloc_array_sig.params.push(AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
});
|
||||||
|
alloc_array_sig.returns.push(AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
});
|
||||||
|
let alloc_array = module
|
||||||
|
.declare_function("helper_alloc_array", Linkage::Import, &alloc_array_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut create_string_sig = module.make_signature();
|
||||||
|
create_string_sig.params.extend(
|
||||||
|
[AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
}; 3],
|
||||||
|
);
|
||||||
|
let create_string = module
|
||||||
|
.declare_function("helper_create_string", Linkage::Import, &create_string_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut dbg_sig = module.make_signature();
|
||||||
|
dbg_sig.params.push(AbiParam {
|
||||||
|
value_type: ptr_type,
|
||||||
|
purpose: ArgumentPurpose::Normal,
|
||||||
|
extension: ArgumentExtension::None,
|
||||||
|
});
|
||||||
|
let dbg = module
|
||||||
|
.declare_function("helper_dbg", Linkage::Import, &dbg_sig)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
func_builder: FunctionBuilderContext::new(),
|
builder_ctx: None,
|
||||||
helpers: Helpers::new(&ctx, &mut module),
|
|
||||||
data_description: DataDescription::new(),
|
|
||||||
func: Function::new(),
|
|
||||||
ctx,
|
ctx,
|
||||||
module,
|
module,
|
||||||
|
|
||||||
|
int_type,
|
||||||
|
float_type,
|
||||||
|
bool_type,
|
||||||
|
ptr_type,
|
||||||
|
value_type,
|
||||||
|
func_sig,
|
||||||
|
|
||||||
|
call,
|
||||||
|
lookup_arg,
|
||||||
|
lookup,
|
||||||
|
select,
|
||||||
|
select_with_default,
|
||||||
|
force,
|
||||||
|
|
||||||
|
eq,
|
||||||
|
|
||||||
|
alloc_array,
|
||||||
|
create_string,
|
||||||
|
dbg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile<'exec>(&'exec mut self, ir: &Ir, id: usize) -> JITFunc<'exec> {
|
pub fn compile(&mut self, ir: &Ir, id: usize) -> JITFunc {
|
||||||
let func_id = self.module.declare_function(format!("nixjit_thunk{id}").as_str(), Linkage::Local, &self.helpers.func_sig).unwrap();
|
let func_id = self
|
||||||
let mut func = Function::new();
|
.module
|
||||||
let builder = FunctionBuilder::new(&mut func, &mut self.func_builder);
|
.declare_function(
|
||||||
let entry = builder.create_block();
|
format!("nixjit_thunk{id}").as_str(),
|
||||||
builder.switch_to_block(entry);
|
Linkage::Local,
|
||||||
// TODO:
|
&self.func_sig,
|
||||||
let ret = ir.compile(self, func_id, &mut Vec::new());
|
)
|
||||||
self.func_builder
|
|
||||||
.build_store(func_id.get_nth_param(2).unwrap().into_pointer_value(), ret)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.func_builder.build_return(None).unwrap();
|
let mut func = Function::new();
|
||||||
self.module.print_to_stderr();
|
func.signature = self.func_sig.clone();
|
||||||
let _ = self.execution_engine.remove_module(&self.module);
|
let mut builder_ctx = self.builder_ctx.take().unwrap_or_default();
|
||||||
let _ = self.execution_engine.add_module(&self.module);
|
let mut ctx = JITContext::new(self, FunctionBuilder::new(&mut func, &mut builder_ctx));
|
||||||
if func_id.verify(true) {
|
|
||||||
|
let entry = ctx.builder.create_block();
|
||||||
|
ctx.builder.append_block_params_for_function_params(entry);
|
||||||
|
ctx.builder.switch_to_block(entry);
|
||||||
|
|
||||||
|
let params = ctx.builder.block_params(entry);
|
||||||
|
let engine = params[0];
|
||||||
|
let env = params[1];
|
||||||
|
let ret = params[2];
|
||||||
|
let res = ir.compile(&mut ctx, engine, env);
|
||||||
|
|
||||||
|
let tag = ctx.builder.ins().stack_load(types::I64, res, 0);
|
||||||
|
let val0 = ctx.builder.ins().stack_load(types::I64, res, 8);
|
||||||
|
let val1 = ctx.builder.ins().stack_load(types::I64, res, 16);
|
||||||
|
let val2 = ctx.builder.ins().stack_load(types::I64, res, 24);
|
||||||
|
ctx.builder.ins().store(MemFlags::new(), tag, ret, 0);
|
||||||
|
ctx.builder.ins().store(MemFlags::new(), val0, ret, 8);
|
||||||
|
ctx.builder.ins().store(MemFlags::new(), val1, ret, 16);
|
||||||
|
ctx.builder.ins().store(MemFlags::new(), val2, ret, 24);
|
||||||
|
ctx.builder.ins().return_(&[]);
|
||||||
|
ctx.builder.seal_all_blocks();
|
||||||
|
ctx.builder.finalize();
|
||||||
|
|
||||||
|
println!("{:?}", ir);
|
||||||
|
println!("{}", func.display());
|
||||||
|
self.ctx.func = func;
|
||||||
|
self.module.define_function(func_id, &mut self.ctx).unwrap();
|
||||||
|
self.module.finalize_definitions().unwrap();
|
||||||
|
self.ctx.clear();
|
||||||
|
|
||||||
|
let _ = self.builder_ctx.insert(builder_ctx);
|
||||||
unsafe {
|
unsafe {
|
||||||
JITFunc(
|
std::mem::transmute::<*const u8, JITFunc>(self.module.get_finalized_function(func_id))
|
||||||
std::mem::transmute(
|
|
||||||
self.execution_engine
|
|
||||||
.get_function_address(func_id.get_name().to_str().unwrap())
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
PhantomData,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value {
|
|
||||||
let offset = builder.ins().iconst(types::I8, 64);
|
|
||||||
builder.ins().rotl(val, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tag(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value {
|
|
||||||
let offset = builder.ins().iconst(types::I8, 64);
|
|
||||||
builder.ins().rotl(val, offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_ptr(&self, ptr: *const ()) -> PointerValue {
|
|
||||||
self.func_builder
|
|
||||||
.build_int_to_ptr(
|
|
||||||
self.helpers.int_type.const_int(ptr as _, false),
|
|
||||||
self.helpers.ptr_type,
|
|
||||||
"ptrconv",
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ impl Evaluate for ir::BinOp {
|
|||||||
}
|
}
|
||||||
Mul => lhs.mul(rhs),
|
Mul => lhs.mul(rhs),
|
||||||
Div => lhs.div(rhs)?,
|
Div => lhs.div(rhs)?,
|
||||||
Eq => Value::eq(&mut lhs, rhs),
|
Eq => Value::eq(&mut lhs, &rhs),
|
||||||
Neq => {
|
Neq => {
|
||||||
Value::eq(&mut lhs, rhs);
|
Value::eq(&mut lhs, &rhs);
|
||||||
lhs.not();
|
lhs.not();
|
||||||
}
|
}
|
||||||
Lt => lhs.lt(rhs),
|
Lt => lhs.lt(rhs),
|
||||||
@@ -197,9 +197,7 @@ impl Evaluate for ir::If {
|
|||||||
|
|
||||||
impl Evaluate for ir::LoadFunc {
|
impl Evaluate for ir::LoadFunc {
|
||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let idx = engine.func_offset + self.idx;
|
Value::Func(self.idx).ok()
|
||||||
let result = Value::Func(idx).ok();
|
|
||||||
Ok(result.unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,14 +205,14 @@ impl Evaluate for ir::Call {
|
|||||||
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result<Value> {
|
||||||
let mut func = self.func.eval(engine, env)?;
|
let mut func = self.func.eval(engine, env)?;
|
||||||
func.force(engine, env)?;
|
func.force(engine, env)?;
|
||||||
let result = func.call(
|
func.call(
|
||||||
self.args
|
self.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| arg.eval(engine, env))
|
.map(|arg| arg.eval(engine, env))
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
engine,
|
engine,
|
||||||
env,
|
env,
|
||||||
);
|
)?;
|
||||||
Ok(func.ok().unwrap())
|
Ok(func.ok().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,7 +262,7 @@ impl Evaluate for ir::ConcatStrings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for ir::String {
|
impl Evaluate for ir::Str {
|
||||||
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
fn eval(&self, _: &mut Engine, _: &mut Env) -> Result<Value> {
|
||||||
let result = Value::String(self.val.clone()).ok();
|
let result = Value::String(self.val.clone()).ok();
|
||||||
Ok(result.unwrap())
|
Ok(result.unwrap())
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use derive_more::Unwrap;
|
use derive_more::Unwrap;
|
||||||
use ecow::EcoString;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::ty::common::Const;
|
use crate::ty::common::Const;
|
||||||
@@ -15,8 +14,8 @@ pub enum Index {
|
|||||||
|
|
||||||
pub struct DowngradeContext {
|
pub struct DowngradeContext {
|
||||||
pub thunks: Vec<(Ir, bool)>,
|
pub thunks: Vec<(Ir, bool)>,
|
||||||
pub thunk_deps: Vec<HashSet<usize>>,
|
pub thunk_deps: Vec<HashMap<usize, usize>>,
|
||||||
pub func_deps: Vec<HashSet<Dep>>,
|
pub func_deps: Vec<HashMap<Dep, usize>>,
|
||||||
pub func_arg_dep: Vec<bool>,
|
pub func_arg_dep: Vec<bool>,
|
||||||
pub funcs: Vec<Func>,
|
pub funcs: Vec<Func>,
|
||||||
}
|
}
|
||||||
@@ -27,10 +26,10 @@ pub struct Env<'a, 'env> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum EnvNode<'a> {
|
enum EnvNode<'a> {
|
||||||
Builtins(&'a HashMap<EcoString, Ir>),
|
Builtins(&'a HashMap<String, Ir>),
|
||||||
Let(&'a Vec<(EcoString, MaybeThunk)>),
|
Let(&'a Vec<(String, MaybeThunk)>),
|
||||||
SingleArg(EcoString),
|
SingleArg(String),
|
||||||
MultiArg(HashMap<EcoString, Option<Ir>>, Option<EcoString>),
|
MultiArg(HashMap<String, Option<Ir>>, Option<String>),
|
||||||
With,
|
With,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,21 +43,21 @@ pub enum LookupResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'env> Env<'a, 'env> {
|
impl<'a, 'env> Env<'a, 'env> {
|
||||||
pub fn new(base: &'a HashMap<EcoString, Ir>) -> Self {
|
pub fn new(builtins: &'a HashMap<String, Ir>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
env: EnvNode::Builtins(base),
|
env: EnvNode::Builtins(builtins),
|
||||||
prev: None,
|
prev: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_let(&'env self, map: &'a Vec<(EcoString, MaybeThunk)>) -> Self {
|
pub fn enter_let(&'env self, map: &'a Vec<(String, MaybeThunk)>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
env: EnvNode::Let(map),
|
env: EnvNode::Let(map),
|
||||||
prev: Some(self),
|
prev: Some(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_single_arg(&'env self, ident: EcoString) -> Self {
|
pub fn enter_single_arg(&'env self, ident: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
env: EnvNode::SingleArg(ident),
|
env: EnvNode::SingleArg(ident),
|
||||||
prev: Some(self),
|
prev: Some(self),
|
||||||
@@ -67,8 +66,8 @@ impl<'a, 'env> Env<'a, 'env> {
|
|||||||
|
|
||||||
pub fn enter_multi_arg(
|
pub fn enter_multi_arg(
|
||||||
&'env self,
|
&'env self,
|
||||||
map: HashMap<EcoString, Option<Ir>>,
|
map: HashMap<String, Option<Ir>>,
|
||||||
alias: Option<EcoString>,
|
alias: Option<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
env: EnvNode::MultiArg(map, alias),
|
env: EnvNode::MultiArg(map, alias),
|
||||||
@@ -85,7 +84,7 @@ impl<'a, 'env> Env<'a, 'env> {
|
|||||||
|
|
||||||
fn _lookup(
|
fn _lookup(
|
||||||
&self,
|
&self,
|
||||||
ident: &EcoString,
|
ident: &String,
|
||||||
mut arg_idx: usize,
|
mut arg_idx: usize,
|
||||||
has_with: bool,
|
has_with: bool,
|
||||||
) -> core::result::Result<LookupResult, ()> {
|
) -> core::result::Result<LookupResult, ()> {
|
||||||
@@ -132,7 +131,7 @@ impl<'a, 'env> Env<'a, 'env> {
|
|||||||
.map_or_else(|| unreachable!(), |x| x)
|
.map_or_else(|| unreachable!(), |x| x)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(&self, ident: &EcoString) -> core::result::Result<LookupResult, ()> {
|
pub fn lookup(&self, ident: &String) -> core::result::Result<LookupResult, ()> {
|
||||||
self._lookup(ident, 0, false)
|
self._lookup(ident, 0, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,38 +152,38 @@ impl DowngradeContext {
|
|||||||
pub fn new_thunk(&mut self, thunk: Ir) -> Thunk {
|
pub fn new_thunk(&mut self, thunk: Ir) -> Thunk {
|
||||||
let idx = self.thunks.len();
|
let idx = self.thunks.len();
|
||||||
self.thunks.push((thunk, false));
|
self.thunks.push((thunk, false));
|
||||||
self.thunk_deps.push(HashSet::new());
|
self.thunk_deps.push(HashMap::new());
|
||||||
Thunk { idx }
|
Thunk { idx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_thunk(&mut self, ir: Ir) -> MaybeThunk {
|
pub fn maybe_thunk(&mut self, ir: Ir) -> MaybeThunk {
|
||||||
match ir {
|
match ir {
|
||||||
Ir::Const(cnst) => MaybeThunk::Const(cnst),
|
Ir::Const(cnst) => MaybeThunk::Const(cnst),
|
||||||
Ir::String(string) => MaybeThunk::String(string),
|
Ir::Str(string) => MaybeThunk::String(string),
|
||||||
Ir::Thunk(thunk) => MaybeThunk::Thunk(thunk),
|
Ir::Thunk(thunk) => MaybeThunk::Thunk(thunk),
|
||||||
ir => MaybeThunk::Thunk(self.new_thunk(ir)),
|
ir => MaybeThunk::Thunk(self.new_thunk(ir)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dep(&mut self, this: Index, dep: Dep) -> Result<()> {
|
pub fn new_dep(&mut self, this: Index, dep: Dep) -> usize {
|
||||||
match this {
|
match this {
|
||||||
Index::Thunk(idx) => {
|
Index::Thunk(idx) => {
|
||||||
/* if dep == Dep::Thunk(idx) && !matches!(self.thunks[idx].0, Ir::List(_)) {
|
let len = self.thunk_deps.len();
|
||||||
return Err(Error::DowngradeError(
|
self.thunk_deps[idx].entry(dep.unwrap_thunk()).or_insert(len);
|
||||||
"infinite recursion encountered".into(),
|
len
|
||||||
));
|
}
|
||||||
} */
|
Index::Func(idx) => {
|
||||||
self.thunk_deps[idx].insert(dep.unwrap_thunk())
|
let len = self.thunk_deps.len();
|
||||||
|
self.func_deps[idx].entry(dep).or_insert(len);
|
||||||
|
len
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Index::Func(idx) => self.func_deps[idx].insert(dep),
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_func(&mut self, func: Func) -> LoadFunc {
|
pub fn new_func(&mut self, func: Func) -> LoadFunc {
|
||||||
let idx = self.funcs.len();
|
let idx = self.funcs.len();
|
||||||
self.funcs.push(func);
|
self.funcs.push(func);
|
||||||
self.func_deps.push(HashSet::new());
|
self.func_deps.push(HashMap::new());
|
||||||
self.func_arg_dep.push(false);
|
self.func_arg_dep.push(false);
|
||||||
LoadFunc { idx }
|
LoadFunc { idx }
|
||||||
}
|
}
|
||||||
@@ -202,7 +201,7 @@ impl DowngradeContext {
|
|||||||
core::ptr::write(
|
core::ptr::write(
|
||||||
func,
|
func,
|
||||||
Func {
|
Func {
|
||||||
param: crate::ir::Param::Ident(EcoString::new()),
|
param: crate::ir::Param::Ident(String::new()),
|
||||||
body: super::Const { val: Const::Null }.ir().boxed(),
|
body: super::Const { val: Const::Null }.ir().boxed(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -246,8 +245,8 @@ impl DowngradeContext {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Downgraded {
|
pub struct Downgraded {
|
||||||
pub thunks: Box<[Ir]>,
|
pub thunks: Box<[Ir]>,
|
||||||
pub func_offset: usize,
|
pub funcs: Box<[Ir]>,
|
||||||
pub func_deps: Vec<HashSet<Dep>>,
|
pub func_deps: Vec<HashMap<Dep, usize>>,
|
||||||
pub graph: Vec<SccNode>,
|
pub graph: Vec<SccNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,14 +254,13 @@ impl Downgraded {
|
|||||||
pub fn new(ctx: DowngradeContext) -> Self {
|
pub fn new(ctx: DowngradeContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
graph: SccAnalyzer::new(&ctx).analyze(),
|
graph: SccAnalyzer::new(&ctx).analyze(),
|
||||||
func_offset: ctx.thunks.len(),
|
|
||||||
func_deps: ctx.func_deps,
|
func_deps: ctx.func_deps,
|
||||||
thunks: ctx
|
thunks: ctx
|
||||||
.thunks
|
.thunks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(ir, _)| ir)
|
.map(|(ir, _)| ir)
|
||||||
.chain(ctx.funcs.into_iter().map(|Func { body, .. }| *body))
|
|
||||||
.collect(),
|
.collect(),
|
||||||
|
funcs: ctx.funcs.into_iter().map(|Func { body, .. }| *body).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use derive_more::{IsVariant, TryUnwrap, Unwrap};
|
use derive_more::{IsVariant, TryUnwrap, Unwrap};
|
||||||
use ecow::EcoString;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use cranelift::codegen;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rnix::ast::HasEntry;
|
use rnix::ast::HasEntry;
|
||||||
use rnix::ast::{self, Expr};
|
use rnix::ast::{self, Expr};
|
||||||
@@ -68,14 +66,14 @@ macro_rules! ir {
|
|||||||
|
|
||||||
impl Ir {
|
impl Ir {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> IrRef {
|
fn as_ref(&self) -> IrRef<'_> {
|
||||||
match self {
|
match self {
|
||||||
$(Ir::$ty(ir) => IrRef::$ty(ir),)*
|
$(Ir::$ty(ir) => IrRef::$ty(ir),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> IrMut {
|
fn as_mut(&mut self) -> IrMut<'_> {
|
||||||
match self {
|
match self {
|
||||||
$(Ir::$ty(ir) => IrMut::$ty(ir),)*
|
$(Ir::$ty(ir) => IrMut::$ty(ir),)*
|
||||||
}
|
}
|
||||||
@@ -90,9 +88,9 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JITCompile for Ir {
|
impl JITCompile for Ir {
|
||||||
fn compile(&self, ctx: &mut JITContext, builder: &mut FunctionBuilder) -> StructValue{
|
fn compile(&self, ctx: &mut JITContext, engine: cranelift::prelude::Value, env: cranelift::prelude::Value) -> cranelift::codegen::ir::StackSlot {
|
||||||
match self {
|
match self {
|
||||||
$(Ir::$ty(ir) => ir.compile(ctx, builder),)*
|
$(Ir::$ty(ir) => ir.compile(ctx, engine, env),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +124,7 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir! {
|
ir! {
|
||||||
Attrs => { stcs: HashMap<EcoString, Ir>, dyns: Vec<DynAttr> },
|
Attrs => { stcs: HashMap<String, Ir>, dyns: Vec<DynAttr> },
|
||||||
List => { items: Vec<Ir> },
|
List => { items: Vec<Ir> },
|
||||||
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
||||||
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
||||||
@@ -136,14 +134,14 @@ ir! {
|
|||||||
LoadFunc => { idx: usize },
|
LoadFunc => { idx: usize },
|
||||||
Call => { func: Box<Ir>, args: Vec<Ir> },
|
Call => { func: Box<Ir>, args: Vec<Ir> },
|
||||||
|
|
||||||
Let => { bindings: Vec<(EcoString, MaybeThunk)>, expr: Box<Ir> },
|
Let => { bindings: Vec<(String, MaybeThunk)>, expr: Box<Ir> },
|
||||||
With => { namespace: Box<Ir>, expr: Box<Ir> },
|
With => { namespace: Box<Ir>, expr: Box<Ir> },
|
||||||
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
||||||
ConcatStrings => { parts: Vec<Ir> },
|
ConcatStrings => { parts: Vec<Ir> },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Const => { val: c::Const },
|
Const => { val: c::Const },
|
||||||
String => { val: EcoString },
|
Str => { val: String },
|
||||||
Var => { sym: EcoString },
|
Var => { sym: String },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Arg => { level: usize },
|
Arg => { level: usize },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
@@ -168,7 +166,7 @@ impl Ir {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum MaybeThunk {
|
pub enum MaybeThunk {
|
||||||
Const(Const),
|
Const(Const),
|
||||||
String(String),
|
String(Str),
|
||||||
Thunk(Thunk),
|
Thunk(Thunk),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +338,7 @@ impl Attrs {
|
|||||||
pub enum Attr {
|
pub enum Attr {
|
||||||
Dynamic(Ir),
|
Dynamic(Ir),
|
||||||
Strs(ConcatStrings),
|
Strs(ConcatStrings),
|
||||||
Str(EcoString),
|
Str(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attr {
|
impl Attr {
|
||||||
@@ -365,7 +363,7 @@ impl Thunk {
|
|||||||
ctx: &mut DowngradeContext,
|
ctx: &mut DowngradeContext,
|
||||||
env: &Env<'a, 'env>,
|
env: &Env<'a, 'env>,
|
||||||
) -> Result<Ir> {
|
) -> Result<Ir> {
|
||||||
ctx.new_dep(self_idx, Dep::Thunk(self.idx))?;
|
ctx.new_dep(self_idx, Dep::Thunk(self.idx));
|
||||||
ctx.resolve_thunk(self.idx, env)?;
|
ctx.resolve_thunk(self.idx, env)?;
|
||||||
self.ir().ok()
|
self.ir().ok()
|
||||||
}
|
}
|
||||||
@@ -442,11 +440,11 @@ pub struct Func {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Param {
|
pub enum Param {
|
||||||
Ident(EcoString),
|
Ident(String),
|
||||||
Formals {
|
Formals {
|
||||||
formals: Vec<(EcoString, Option<Thunk>)>,
|
formals: Vec<(String, Option<Thunk>)>,
|
||||||
ellipsis: bool,
|
ellipsis: bool,
|
||||||
alias: Option<EcoString>,
|
alias: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +555,7 @@ impl Downgrade for ast::Path {
|
|||||||
let parts = self
|
let parts = self
|
||||||
.parts()
|
.parts()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => String {
|
ast::InterpolPart::Literal(lit) => Str {
|
||||||
val: lit.to_string().into(),
|
val: lit.to_string().into(),
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
@@ -602,7 +600,7 @@ impl Downgrade for ast::Str {
|
|||||||
.normalized_parts()
|
.normalized_parts()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => String { val: lit.into() }.ir().ok(),
|
ast::InterpolPart::Literal(lit) => Str { val: lit.into() }.ir().ok(),
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
interpol.expr().unwrap().downgrade(ctx)
|
interpol.expr().unwrap().downgrade(ctx)
|
||||||
}
|
}
|
||||||
@@ -640,7 +638,7 @@ impl Downgrade for ast::Literal {
|
|||||||
match self.kind() {
|
match self.kind() {
|
||||||
ast::LiteralKind::Integer(int) => Const::from(int.value().unwrap()).ir(),
|
ast::LiteralKind::Integer(int) => Const::from(int.value().unwrap()).ir(),
|
||||||
ast::LiteralKind::Float(float) => Const::from(float.value().unwrap()).ir(),
|
ast::LiteralKind::Float(float) => Const::from(float.value().unwrap()).ir(),
|
||||||
ast::LiteralKind::Uri(uri) => String {
|
ast::LiteralKind::Uri(uri) => Str {
|
||||||
val: uri.to_string().into(),
|
val: uri.to_string().into(),
|
||||||
}
|
}
|
||||||
.ir(),
|
.ir(),
|
||||||
@@ -660,7 +658,7 @@ impl Const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl String {
|
impl Str {
|
||||||
fn resolve<'a, 'env>(
|
fn resolve<'a, 'env>(
|
||||||
self,
|
self,
|
||||||
_: Index,
|
_: Index,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub struct SccNode {
|
|||||||
pub deps: HashSet<usize>,
|
pub deps: HashSet<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Unwrap)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Unwrap)]
|
||||||
pub enum Dep {
|
pub enum Dep {
|
||||||
Thunk(usize),
|
Thunk(usize),
|
||||||
Arg(usize),
|
Arg(usize),
|
||||||
@@ -43,7 +43,7 @@ impl SccGraph {
|
|||||||
|
|
||||||
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
|
for (from_node_id, from_deps) in ctx.thunk_deps.iter().enumerate() {
|
||||||
let from_scc_id = thunk_to_scc[&from_node_id];
|
let from_scc_id = thunk_to_scc[&from_node_id];
|
||||||
for &to_node_id in from_deps {
|
for (&to_node_id, _) in from_deps {
|
||||||
let to_scc_id = thunk_to_scc[&to_node_id];
|
let to_scc_id = thunk_to_scc[&to_node_id];
|
||||||
if from_scc_id != to_scc_id {
|
if from_scc_id != to_scc_id {
|
||||||
graph
|
graph
|
||||||
@@ -166,7 +166,7 @@ impl<'ctx> SccAnalyzer<'ctx> {
|
|||||||
self.on_stack.insert(v_id);
|
self.on_stack.insert(v_id);
|
||||||
|
|
||||||
if let Some(deps) = self.ctx.thunk_deps.get(v_id) {
|
if let Some(deps) = self.ctx.thunk_deps.get(v_id) {
|
||||||
for &w_id in deps {
|
for (&w_id, _) in deps {
|
||||||
if !self.indices.contains_key(&w_id) {
|
if !self.indices.contains_key(&w_id) {
|
||||||
self.strong_connect(w_id);
|
self.strong_connect(w_id);
|
||||||
let v_low_link = *self.low_links.get(&v_id).unwrap();
|
let v_low_link = *self.low_links.get(&v_id).unwrap();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ pub fn downgrade_attrs(has_entry: impl ast::HasEntry, ctx: &mut DowngradeContext
|
|||||||
|
|
||||||
pub fn downgrade_inherit(
|
pub fn downgrade_inherit(
|
||||||
inherit: ast::Inherit,
|
inherit: ast::Inherit,
|
||||||
stcs: &mut HashMap<EcoString, Ir>,
|
stcs: &mut HashMap<String, Ir>,
|
||||||
ctx: &mut DowngradeContext,
|
ctx: &mut DowngradeContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let from = if let Some(from) = inherit.from() {
|
let from = if let Some(from) = inherit.from() {
|
||||||
@@ -110,7 +110,7 @@ pub fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Att
|
|||||||
let parts = parts
|
let parts = parts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
Literal(lit) => String { val: lit.into() }.ir().ok(),
|
Literal(lit) => self::Str { val: lit.into() }.ir().ok(),
|
||||||
Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx),
|
Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx),
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ use core::fmt::{Display, Formatter, Result as FmtResult};
|
|||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
|
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Constructor, Hash)]
|
#[derive(Clone, Debug, PartialEq, Constructor, Hash)]
|
||||||
pub struct Catchable {
|
pub struct Catchable {
|
||||||
msg: EcoString,
|
msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<EcoString>> From<T> for Catchable {
|
impl<T: Into<String>> From<T> for Catchable {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Catchable { msg: value.into() }
|
Catchable { msg: value.into() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use core::ops::Deref;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use ecow::EcoString;
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
@@ -16,17 +15,17 @@ use super::Value;
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Constructor, Clone, PartialEq, Debug)]
|
#[derive(Constructor, Clone, PartialEq, Debug)]
|
||||||
pub struct AttrSet {
|
pub struct AttrSet {
|
||||||
data: HashMap<EcoString, Value>,
|
data: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<HashMap<EcoString, Value>> for AttrSet {
|
impl From<HashMap<String, Value>> for AttrSet {
|
||||||
fn from(data: HashMap<EcoString, Value>) -> Self {
|
fn from(data: HashMap<String, Value>) -> Self {
|
||||||
Self { data }
|
Self { data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for AttrSet {
|
impl Deref for AttrSet {
|
||||||
type Target = HashMap<EcoString, Value>;
|
type Target = HashMap<String, Value>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
@@ -39,11 +38,11 @@ impl AttrSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr_force(&mut self, sym: EcoString, val: Value) {
|
pub fn push_attr_force(&mut self, sym: String, val: Value) {
|
||||||
self.data.insert(sym, val);
|
self.data.insert(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: EcoString, val: Value) {
|
pub fn push_attr(&mut self, sym: String, val: Value) {
|
||||||
if self.data.get(&sym).is_some() {
|
if self.data.get(&sym).is_some() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@@ -52,7 +51,7 @@ impl AttrSet {
|
|||||||
|
|
||||||
pub fn select(
|
pub fn select(
|
||||||
&self,
|
&self,
|
||||||
mut path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
mut path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
// .ok_or_else(|| Error::EvalError())),
|
// .ok_or_else(|| Error::EvalError())),
|
||||||
let mut data = &self.data;
|
let mut data = &self.data;
|
||||||
@@ -75,7 +74,7 @@ impl AttrSet {
|
|||||||
|
|
||||||
pub fn has_attr(
|
pub fn has_attr(
|
||||||
&self,
|
&self,
|
||||||
mut path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
mut path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let mut data = &self.data;
|
let mut data = &self.data;
|
||||||
let last = path.nth_back(0).unwrap();
|
let last = path.nth_back(0).unwrap();
|
||||||
@@ -94,15 +93,15 @@ impl AttrSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_inner(&self) -> &HashMap<EcoString, Value> {
|
pub fn as_inner(&self) -> &HashMap<String, Value> {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self: Rc<Self>) -> Rc<HashMap<EcoString, Value>> {
|
pub fn into_inner(self: Rc<Self>) -> Rc<HashMap<String, Value>> {
|
||||||
unsafe { core::mem::transmute(self) }
|
unsafe { core::mem::transmute(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_inner(data: HashMap<EcoString, Value>) -> Self {
|
pub fn from_inner(data: HashMap<String, Value>) -> Self {
|
||||||
Self { data }
|
Self { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::env::Env;
|
|
||||||
use crate::ir;
|
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Constructor)]
|
#[derive(Debug, Clone, Constructor)]
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Weak;
|
|
||||||
|
|
||||||
use ecow::EcoVec;
|
use ecow::EcoVec;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::env::Env;
|
|
||||||
use crate::ty::public as p;
|
use crate::ty::public as p;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use std::hash::Hash;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
|
||||||
use func::PartialFunc;
|
use func::PartialFunc;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use replace_with::replace_with_or_abort;
|
use replace_with::replace_with_or_abort;
|
||||||
@@ -24,21 +23,22 @@ pub use attrset::*;
|
|||||||
pub use list::List;
|
pub use list::List;
|
||||||
pub use primop::*;
|
pub use primop::*;
|
||||||
|
|
||||||
|
#[repr(C, u64)]
|
||||||
#[derive(IsVariant, Unwrap, Clone, Debug)]
|
#[derive(IsVariant, Unwrap, Clone, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i64),
|
Int(i64) = Self::INT,
|
||||||
Float(f64),
|
Float(f64) = Self::FLOAT,
|
||||||
Bool(bool),
|
Bool(bool) = Self::BOOL,
|
||||||
String(EcoString),
|
String(String) = Self::STRING,
|
||||||
Null,
|
Null = Self::NULL,
|
||||||
Thunk(usize),
|
Thunk(usize) = Self::THUNK,
|
||||||
AttrSet(Rc<AttrSet>),
|
AttrSet(Rc<AttrSet>) = Self::ATTRSET,
|
||||||
List(List),
|
List(List) = Self::LIST,
|
||||||
Catchable(EcoString),
|
Catchable(String) = Self::CATCHABLE,
|
||||||
PrimOp(Rc<PrimOp>),
|
PrimOp(Rc<PrimOp>) = Self::PRIMOP,
|
||||||
PartialPrimOp(Rc<PartialPrimOp>),
|
PartialPrimOp(Rc<PartialPrimOp>) = Self::PARTIAL_PRIMOP,
|
||||||
Func(usize),
|
Func(usize) = Self::FUNC,
|
||||||
PartialFunc(Rc<PartialFunc>),
|
PartialFunc(Rc<PartialFunc>) = Self::PARTIAL_FUNC,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Value {
|
impl Hash for Value {
|
||||||
@@ -54,6 +54,20 @@ impl Hash for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
pub const INT: u64 = 0;
|
||||||
|
pub const FLOAT: u64 = 1;
|
||||||
|
pub const BOOL: u64 = 2;
|
||||||
|
pub const STRING: u64 = 3;
|
||||||
|
pub const NULL: u64 = 4;
|
||||||
|
pub const THUNK: u64 = 5;
|
||||||
|
pub const ATTRSET: u64 = 6;
|
||||||
|
pub const LIST: u64 = 7;
|
||||||
|
pub const CATCHABLE: u64 = 8;
|
||||||
|
pub const PRIMOP: u64 = 9;
|
||||||
|
pub const PARTIAL_PRIMOP: u64 = 10;
|
||||||
|
pub const FUNC: u64 = 11;
|
||||||
|
pub const PARTIAL_FUNC: u64 = 12;
|
||||||
|
|
||||||
fn eq_impl(&self, other: &Self) -> bool {
|
fn eq_impl(&self, other: &Self) -> bool {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
@@ -89,7 +103,7 @@ pub enum ValueAsRef<'v> {
|
|||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(&'v EcoString),
|
String(&'v String),
|
||||||
Null,
|
Null,
|
||||||
Thunk(usize),
|
Thunk(usize),
|
||||||
AttrSet(&'v AttrSet),
|
AttrSet(&'v AttrSet),
|
||||||
@@ -102,7 +116,7 @@ pub enum ValueAsRef<'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub fn as_ref(&self) -> ValueAsRef {
|
pub fn as_ref(&self) -> ValueAsRef<'_> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
use ValueAsRef as R;
|
use ValueAsRef as R;
|
||||||
match self {
|
match self {
|
||||||
@@ -179,13 +193,13 @@ impl Value {
|
|||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
let (ret, cache) = env.with_cache(std::mem::take(cache), |env| {
|
let (ret, cache) = env.with_cache(std::mem::take(cache), |env| {
|
||||||
engine.eval_func_deps(idx, env)?;
|
engine.eval_func_deps(idx, env)?;
|
||||||
let mut ret = engine.eval_thunk(idx, env)?;
|
let mut ret = engine.call_func(idx, env)?;
|
||||||
while args.peek().is_some() {
|
while args.peek().is_some() {
|
||||||
match ret {
|
match ret {
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
engine.eval_func_deps(idx, env)?;
|
engine.eval_func_deps(idx, env)?;
|
||||||
ret = engine.eval_thunk(func, env)?;
|
ret = engine.call_func(func, env)?;
|
||||||
}
|
}
|
||||||
Value::PartialFunc(_) => {
|
Value::PartialFunc(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
@@ -219,16 +233,16 @@ impl Value {
|
|||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
let (ret, cache) = env.with_new_cache(|env| {
|
let (ret, cache) = env.with_new_cache(|env| {
|
||||||
engine.eval_func_deps(idx, env)?;
|
engine.eval_func_deps(idx, env)?;
|
||||||
let mut ret = engine.eval_thunk(idx, env)?;
|
let mut ret = engine.call_func(idx, env)?;
|
||||||
ret.force(engine, env)?;
|
ret.force(engine, env)?;
|
||||||
while args.peek().is_some() {
|
while args.peek().is_some() {
|
||||||
match ret {
|
match ret {
|
||||||
Value::Func(func) => {
|
Value::Func(idx) => {
|
||||||
env.enter_arg(args.next().unwrap());
|
env.enter_arg(args.next().unwrap());
|
||||||
engine.eval_func_deps(idx, env)?;
|
engine.eval_func_deps(idx, env)?;
|
||||||
ret = engine.eval_thunk(func, env)?;
|
ret = engine.call_func(idx, env)?;
|
||||||
}
|
}
|
||||||
Value::PartialFunc(mut func) => {
|
Value::PartialFunc(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
Value::PrimOp(primop) => {
|
Value::PrimOp(primop) => {
|
||||||
@@ -288,12 +302,12 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq(&mut self, other: Self) {
|
pub fn eq(&mut self, other: &Self) {
|
||||||
use Value::Bool;
|
use Value::Bool;
|
||||||
*self = match (&*self, other) {
|
*self = match (&*self, other) {
|
||||||
(Value::Catchable(_), _) => return,
|
(Value::Catchable(_), _) => return,
|
||||||
(_, x @ Value::Catchable(_)) => x,
|
(_, x @ Value::Catchable(_)) => x.clone(),
|
||||||
(s, other) => Bool(s.eq_impl(&other)),
|
(s, other) => Bool(s.eq_impl(other)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,30 +379,32 @@ impl Value {
|
|||||||
(Int(a), Float(b)) => Float(*a as f64 / b),
|
(Int(a), Float(b)) => Float(*a as f64 / b),
|
||||||
(Float(a), Int(b)) => Float(a / b as f64),
|
(Float(a), Int(b)) => Float(a / b as f64),
|
||||||
(Float(a), Float(b)) => Float(a / b),
|
(Float(a), Float(b)) => Float(a / b),
|
||||||
(Value::Catchable(_), _) => return Ok(()),
|
(Catchable(_), _) => return Ok(()),
|
||||||
(_, x @ Value::Catchable(_)) => x,
|
(_, x @ Catchable(_)) => x,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat_string(&mut self, mut other: Self) -> &mut Self {
|
pub fn concat_string(&mut self, mut other: Self) -> &mut Self {
|
||||||
|
use Value::*;
|
||||||
match (self.coerce_to_string(), other.coerce_to_string()) {
|
match (self.coerce_to_string(), other.coerce_to_string()) {
|
||||||
(Value::String(a), Value::String(b)) => {
|
(String(a), String(b)) => {
|
||||||
a.push_str(b.as_str());
|
a.push_str(b.as_str());
|
||||||
}
|
}
|
||||||
(_, Value::Catchable(_)) => *self = other,
|
(_, Catchable(_)) => *self = other,
|
||||||
(Value::Catchable(_), _) => (),
|
(Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, elem: Self) -> &mut Self {
|
pub fn push(&mut self, elem: Self) -> &mut Self {
|
||||||
if let Value::List(list) = self {
|
use Value::*;
|
||||||
|
if let List(list) = self {
|
||||||
list.push(elem);
|
list.push(elem);
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = elem {
|
} else if let Catchable(_) = elem {
|
||||||
*self = elem;
|
*self = elem;
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
@@ -397,24 +413,26 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: Self) {
|
pub fn concat(&mut self, other: Self) {
|
||||||
if let x @ Value::Catchable(_) = other {
|
use Value::*;
|
||||||
|
if let x @ Catchable(_) = other {
|
||||||
*self = x;
|
*self = x;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::List(a), Value::List(b)) => {
|
(List(a), List(b)) => {
|
||||||
a.concat(&b);
|
a.concat(&b);
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: EcoString, val: Self) -> &mut Self {
|
pub fn push_attr(&mut self, sym: String, val: Self) -> &mut Self {
|
||||||
if let Value::AttrSet(attrs) = self {
|
use Value::*;
|
||||||
|
if let AttrSet(attrs) = self {
|
||||||
Rc::make_mut(attrs).push_attr(sym, val);
|
Rc::make_mut(attrs).push_attr(sym, val);
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = val {
|
} else if let Catchable(_) = val {
|
||||||
*self = val
|
*self = val
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
@@ -423,26 +441,28 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, other: Self) {
|
pub fn update(&mut self, other: Self) {
|
||||||
if let x @ Value::Catchable(_) = other {
|
use Value::*;
|
||||||
|
if let x @ Catchable(_) = other {
|
||||||
*self = x;
|
*self = x;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
(AttrSet(a), AttrSet(b)) => {
|
||||||
Rc::make_mut(a).update(&b);
|
Rc::make_mut(a).update(&b);
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(
|
pub fn select(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||||
) -> Result<&mut Self> {
|
) -> Result<&mut Self> {
|
||||||
|
use Value::*;
|
||||||
let val = match self {
|
let val = match self {
|
||||||
Value::AttrSet(attrs) => attrs.select(path),
|
AttrSet(attrs) => attrs.select(path),
|
||||||
Value::Catchable(_) => return Ok(self),
|
Catchable(_) => return Ok(self),
|
||||||
_ => Err(Error::EvalError(format!(
|
_ => Err(Error::EvalError(format!(
|
||||||
"cannot select from {:?}",
|
"cannot select from {:?}",
|
||||||
self.typename()
|
self.typename()
|
||||||
@@ -454,12 +474,13 @@ impl Value {
|
|||||||
|
|
||||||
pub fn select_with_default(
|
pub fn select_with_default(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||||
default: Self,
|
default: Self,
|
||||||
) -> Result<&mut Self> {
|
) -> Result<&mut Self> {
|
||||||
|
use Value::*;
|
||||||
let val = match self {
|
let val = match self {
|
||||||
Value::AttrSet(attrs) => attrs.select(path).unwrap_or(default),
|
AttrSet(attrs) => attrs.select(path).unwrap_or(default),
|
||||||
Value::Catchable(_) => return Ok(self),
|
Catchable(_) => return Ok(self),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::EvalError(format!(
|
return Err(Error::EvalError(format!(
|
||||||
"cannot select from {:?}",
|
"cannot select from {:?}",
|
||||||
@@ -473,21 +494,23 @@ impl Value {
|
|||||||
|
|
||||||
pub fn has_attr(
|
pub fn has_attr(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if let Value::AttrSet(attrs) = self {
|
use Value::*;
|
||||||
let val = Value::Bool(attrs.has_attr(path)?);
|
if let AttrSet(attrs) = self {
|
||||||
|
let val = Bool(attrs.has_attr(path)?);
|
||||||
*self = val;
|
*self = val;
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Catchable(_) = self {
|
||||||
} else {
|
} else {
|
||||||
*self = Value::Bool(false);
|
*self = Bool(false);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn coerce_to_string(&mut self) -> &mut Self {
|
pub fn coerce_to_string(&mut self) -> &mut Self {
|
||||||
if let Value::String(_) = self {
|
use Value::*;
|
||||||
} else if let Value::Catchable(_) = self {
|
if let String(_) = self {
|
||||||
|
} else if let Catchable(_) = self {
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@@ -496,7 +519,6 @@ impl Value {
|
|||||||
|
|
||||||
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
|
pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> {
|
||||||
if let &mut Value::Thunk(idx) = self {
|
if let &mut Value::Thunk(idx) = self {
|
||||||
// *self = env.lookup_cache(idx, |env| engine.eval_thunk(idx, env))?
|
|
||||||
*self = env.lookup_cache(idx, |_| unreachable!())?
|
*self = env.lookup_cache(idx, |_| unreachable!())?
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// TODO: Contextful String
|
// TODO: Contextful String
|
||||||
|
|
||||||
use ecow::EcoString;
|
|
||||||
|
|
||||||
pub struct StringContext {
|
pub struct StringContext {
|
||||||
context: Vec<()>,
|
context: Vec<()>,
|
||||||
}
|
}
|
||||||
@@ -15,12 +13,12 @@ impl StringContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContextfulString {
|
pub struct ContextfulString {
|
||||||
string: EcoString,
|
string: String,
|
||||||
context: StringContext,
|
context: StringContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextfulString {
|
impl ContextfulString {
|
||||||
pub fn new(string: EcoString) -> ContextfulString {
|
pub fn new(string: String) -> ContextfulString {
|
||||||
ContextfulString {
|
ContextfulString {
|
||||||
string,
|
string,
|
||||||
context: StringContext::new(),
|
context: StringContext::new(),
|
||||||
|
|||||||
@@ -4,15 +4,14 @@ use std::ops::Deref;
|
|||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use super::common::*;
|
use super::common::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
|
||||||
pub struct Symbol(EcoString);
|
pub struct Symbol(String);
|
||||||
|
|
||||||
impl<T: Into<EcoString>> From<T> for Symbol {
|
impl<T: Into<String>> From<T> for Symbol {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Symbol(value.into())
|
Symbol(value.into())
|
||||||
}
|
}
|
||||||
@@ -44,11 +43,11 @@ impl Deref for Symbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
pub fn into_inner(self) -> EcoString {
|
pub fn into_inner(self) -> String {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_inner(&self) -> &EcoString {
|
pub fn as_inner(&self) -> &String {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +107,7 @@ impl Display for List {
|
|||||||
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
|
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Const(Const),
|
Const(Const),
|
||||||
String(EcoString),
|
String(String),
|
||||||
AttrSet(AttrSet),
|
AttrSet(AttrSet),
|
||||||
List(List),
|
List(List),
|
||||||
Catchable(Catchable),
|
Catchable(Catchable),
|
||||||
|
|||||||
Reference in New Issue
Block a user