feat: lookup at downgrade time
works, but leaks memory
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -23,16 +23,6 @@ version = "1.0.98"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "archery"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8967cd1cc9e9e1954f644e14fbd6042fe9a37da96c52a67e44a2ac18261f8561"
|
|
||||||
dependencies = [
|
|
||||||
"static_assertions",
|
|
||||||
"triomphe",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -334,9 +324,7 @@ dependencies = [
|
|||||||
"inkwell",
|
"inkwell",
|
||||||
"itertools",
|
"itertools",
|
||||||
"regex",
|
"regex",
|
||||||
"replace_with",
|
|
||||||
"rnix",
|
"rnix",
|
||||||
"rpds",
|
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
@@ -410,12 +398,6 @@ version = "0.8.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "replace_with"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rnix"
|
name = "rnix"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
@@ -438,15 +420,6 @@ dependencies = [
|
|||||||
"text-size",
|
"text-size",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rpds"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4"
|
|
||||||
dependencies = [
|
|
||||||
"archery",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -506,12 +479,6 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "static_assertions"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.101"
|
version = "2.0.101"
|
||||||
@@ -580,12 +547,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "triomphe"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|||||||
@@ -23,13 +23,11 @@ strip = true
|
|||||||
rnix = "0.12"
|
rnix = "0.12"
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
itertools = "0.14"
|
itertools = "0.14"
|
||||||
rpds = "1.1"
|
|
||||||
derive_more = { version = "2.0", features = ["full"] }
|
derive_more = { version = "2.0", features = ["full"] }
|
||||||
ecow = "0.2"
|
ecow = "0.2"
|
||||||
regex = "1.11"
|
regex = "1.11"
|
||||||
hashbrown = "0.15"
|
hashbrown = "0.15"
|
||||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
||||||
gc-arena = { git = "https://github.com/kyren/gc-arena", rev = "d651e3b4363d525a2d502c2305bc73e291835c84", features= ["hashbrown"] }
|
gc-arena = { git = "https://github.com/kyren/gc-arena", rev = "d651e3b4363d525a2d502c2305bc73e291835c84", features= ["hashbrown"] }
|
||||||
replace_with = "0.1"
|
|
||||||
|
|
||||||
rustyline = { version = "15.0", optional = true }
|
rustyline = { version = "15.0", optional = true }
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
use gc_arena::{Gc, Mutation};
|
use gc_arena::{Gc, Mutation};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::env::{IrEnv, VmEnv};
|
use crate::env::VmEnv;
|
||||||
|
use crate::ir::{DowngradeContext, Ir};
|
||||||
|
use crate::ty::common::Const;
|
||||||
use crate::ty::internal::{AttrSet, CoW, PrimOp, Value};
|
use crate::ty::internal::{AttrSet, CoW, PrimOp, Value};
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
pub fn ir_env<'gc>(mc: &Mutation<'gc>) -> Gc<'gc, IrEnv<'gc>> {
|
pub fn ir_env(ctx: &mut DowngradeContext) -> HashMap<usize, Ir> {
|
||||||
// TODO:
|
let mut map = HashMap::new();
|
||||||
IrEnv::new(Gc::new(mc, HashMap::new()), mc)
|
map.insert(ctx.new_sym("true"), ctx.new_const(Const::Bool(true)).ir());
|
||||||
|
map.insert(ctx.new_sym("false"), ctx.new_const(Const::Bool(false)).ir());
|
||||||
|
|
||||||
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
||||||
@@ -78,15 +83,16 @@ pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> {
|
|||||||
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
||||||
}
|
}
|
||||||
let sym = vm.new_sym("builtins");
|
let sym = vm.new_sym("builtins");
|
||||||
let attrs = CoW::new_cyclic(
|
let mut attrs = CoW::new(AttrSet::new(map), mc);
|
||||||
|this| {
|
unsafe {
|
||||||
map.insert(sym, Value::AttrSet(this));
|
attrs.make_cyclic(|attrs, this| {
|
||||||
AttrSet::from_inner(map)
|
let _ = attrs.push_attr(sym, Value::AttrSet(this));
|
||||||
},
|
}, mc);
|
||||||
mc,
|
}
|
||||||
);
|
|
||||||
let builtins = Value::AttrSet(attrs);
|
let builtins = Value::AttrSet(attrs);
|
||||||
|
|
||||||
env_map.insert(sym, builtins);
|
env_map.insert(sym, builtins);
|
||||||
VmEnv::new(Gc::new(mc, env_map), mc)
|
// TODO:
|
||||||
|
// VmEnv::new(Gc::new(mc, env_map), mc)
|
||||||
|
VmEnv::new(Vec::new(), mc)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ pub enum OpCode {
|
|||||||
Const { idx: usize },
|
Const { idx: usize },
|
||||||
/// load a dynamic var onto stack
|
/// load a dynamic var onto stack
|
||||||
LookUp { sym: usize },
|
LookUp { sym: usize },
|
||||||
|
/// load a var from let binding onto stack
|
||||||
|
LookUpLet { level: usize, idx: usize },
|
||||||
/// load a thunk lazily onto stack
|
/// load a thunk lazily onto stack
|
||||||
LoadThunk { idx: usize },
|
LoadThunk { idx: usize },
|
||||||
/// load a thunk value onto stack
|
/// load a thunk value onto stack
|
||||||
@@ -31,6 +33,8 @@ pub enum OpCode {
|
|||||||
Call,
|
Call,
|
||||||
/// make a function
|
/// make a function
|
||||||
Func { idx: usize },
|
Func { idx: usize },
|
||||||
|
/// load a function argument
|
||||||
|
Arg { level: usize },
|
||||||
|
|
||||||
/// consume 1 element, assert TOS is true
|
/// consume 1 element, assert TOS is true
|
||||||
Assert,
|
Assert,
|
||||||
@@ -43,14 +47,14 @@ pub enum OpCode {
|
|||||||
/// push an empty attribute set onto stack
|
/// push an empty attribute set onto stack
|
||||||
AttrSet { cap: usize },
|
AttrSet { cap: usize },
|
||||||
/// finalize the recursive attribute set at TOS
|
/// finalize the recursive attribute set at TOS
|
||||||
FinalizeRec,
|
FinalizeLet,
|
||||||
/// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set`
|
/// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set`
|
||||||
PushStaticAttr { name: usize },
|
PushStaticAttr { name: usize },
|
||||||
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
||||||
PushDynamicAttr,
|
PushDynamicAttr,
|
||||||
|
|
||||||
/// push an empty list onto stack
|
/// push an empty list onto stack
|
||||||
List,
|
List { cap: usize },
|
||||||
/// [ .. list elem ] consume 1 element, push `elem` into `list`
|
/// [ .. list elem ] consume 1 element, push `elem` into `list`
|
||||||
PushElem,
|
PushElem,
|
||||||
|
|
||||||
@@ -75,8 +79,6 @@ pub enum OpCode {
|
|||||||
SelectDynamic,
|
SelectDynamic,
|
||||||
/// [ .. set sym default ] select `sym` from `set` or `default`
|
/// [ .. set sym default ] select `sym` from `set` or `default`
|
||||||
SelectDynamicOrDefault,
|
SelectDynamicOrDefault,
|
||||||
/// enter the let environment of the attribute set at TOS
|
|
||||||
EnterLetEnv,
|
|
||||||
/// enter the with environment of the attribute set at TOS
|
/// enter the with environment of the attribute set at TOS
|
||||||
EnterWithEnv,
|
EnterWithEnv,
|
||||||
/// exit current envrironment
|
/// exit current envrironment
|
||||||
|
|||||||
@@ -96,6 +96,18 @@ impl Compile for ir::Var {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Compile for ir::Arg {
|
||||||
|
fn compile(self, comp: &mut Compiler) {
|
||||||
|
comp.push(OpCode::Arg { level: self.level })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compile for ir::LetVar {
|
||||||
|
fn compile(self, comp: &mut Compiler) {
|
||||||
|
comp.push(OpCode::LookUpLet { level: self.level, idx: self.idx });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Compile for ir::Thunk {
|
impl Compile for ir::Thunk {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
comp.push(OpCode::LoadThunk { idx: self.idx });
|
comp.push(OpCode::LoadThunk { idx: self.idx });
|
||||||
@@ -113,7 +125,7 @@ impl Compile for ir::Attrs {
|
|||||||
for stc in self.stcs {
|
for stc in self.stcs {
|
||||||
let thunk = stc.1.is_thunk();
|
let thunk = stc.1.is_thunk();
|
||||||
stc.1.compile(comp);
|
stc.1.compile(comp);
|
||||||
if thunk && !self.rec {
|
if thunk {
|
||||||
comp.push(OpCode::CaptureEnv);
|
comp.push(OpCode::CaptureEnv);
|
||||||
}
|
}
|
||||||
comp.push(OpCode::PushStaticAttr { name: stc.0 });
|
comp.push(OpCode::PushStaticAttr { name: stc.0 });
|
||||||
@@ -122,20 +134,17 @@ impl Compile for ir::Attrs {
|
|||||||
let thunk = dynamic.1.is_thunk();
|
let thunk = dynamic.1.is_thunk();
|
||||||
dynamic.0.compile_force(comp);
|
dynamic.0.compile_force(comp);
|
||||||
dynamic.1.compile(comp);
|
dynamic.1.compile(comp);
|
||||||
if thunk && !self.rec {
|
if thunk {
|
||||||
comp.push(OpCode::CaptureEnv);
|
comp.push(OpCode::CaptureEnv);
|
||||||
}
|
}
|
||||||
comp.push(OpCode::PushDynamicAttr)
|
comp.push(OpCode::PushDynamicAttr)
|
||||||
}
|
}
|
||||||
if self.rec {
|
|
||||||
comp.push(OpCode::FinalizeRec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compile for ir::List {
|
impl Compile for ir::List {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
comp.push(OpCode::List);
|
comp.push(OpCode::List { cap: self.items.len() });
|
||||||
for item in self.items {
|
for item in self.items {
|
||||||
item.compile(comp);
|
item.compile(comp);
|
||||||
comp.push(OpCode::PushElem);
|
comp.push(OpCode::PushElem);
|
||||||
@@ -375,8 +384,14 @@ impl Compile for ir::If {
|
|||||||
|
|
||||||
impl Compile for ir::Let {
|
impl Compile for ir::Let {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
self.attrs.compile(comp);
|
comp.push(OpCode::List {
|
||||||
comp.push(OpCode::EnterLetEnv);
|
cap: self.bindings.len()
|
||||||
|
});
|
||||||
|
for (_, val) in self.bindings {
|
||||||
|
val.compile(comp);
|
||||||
|
comp.push(OpCode::PushElem);
|
||||||
|
}
|
||||||
|
comp.push(OpCode::FinalizeLet);
|
||||||
self.expr.compile(comp);
|
self.expr.compile(comp);
|
||||||
comp.push(OpCode::LeaveEnv);
|
comp.push(OpCode::LeaveEnv);
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/env.rs
78
src/env.rs
@@ -8,16 +8,17 @@ use crate::{ir::Ir, ty::internal::Value};
|
|||||||
#[derive(Collect)]
|
#[derive(Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub struct Env<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
pub struct Env<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
||||||
let_: Gc<'gc, LetEnv<'gc, K, V>>,
|
let_: Gc<'gc, LetEnv<'gc, V>>,
|
||||||
with: Gc<'gc, With<'gc, K, V>>,
|
with: Gc<'gc, With<'gc, K, V>>,
|
||||||
|
args: Vec<V>,
|
||||||
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
last: Option<Gc<'gc, Env<'gc, K, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Collect)]
|
#[derive(Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub struct LetEnv<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
pub struct LetEnv<'gc, V: Collect<'gc>> {
|
||||||
map: LetNode<'gc, K, V>,
|
map: Vec<V>,
|
||||||
last: Option<Gc<'gc, LetEnv<'gc, K, V>>>,
|
last: Option<Gc<'gc, LetEnv<'gc, V>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type VmEnv<'gc> = Env<'gc, usize, Value<'gc>>;
|
pub type VmEnv<'gc> = Env<'gc, usize, Value<'gc>>;
|
||||||
@@ -34,7 +35,6 @@ pub struct With<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
|||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
enum LetNode<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
enum LetNode<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> {
|
||||||
Let(Gc<'gc, HashMap<K, V>>),
|
Let(Gc<'gc, HashMap<K, V>>),
|
||||||
SingleArg(K, V),
|
|
||||||
MultiArg(Gc<'gc, HashMap<K, V>>),
|
MultiArg(Gc<'gc, HashMap<K, V>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ pub enum Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, K, V> {
|
impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, K, V> {
|
||||||
pub fn new(map: Gc<'gc, HashMap<K, V>>, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
pub fn new(map: Vec<V>, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
||||||
Gc::new(
|
Gc::new(
|
||||||
mc,
|
mc,
|
||||||
Self {
|
Self {
|
||||||
@@ -58,20 +58,18 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
last: None,
|
last: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
args: Vec::new(),
|
||||||
last: None,
|
last: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_slow(&self, symbol: &K) -> Option<&V> {
|
pub fn lookup_arg(&self, level: usize) -> V {
|
||||||
if let Some(val) = self.let_.lookup(symbol) {
|
self.args[self.args.len() - level - 1].clone()
|
||||||
return Some(val);
|
|
||||||
}
|
|
||||||
self.with.lookup(symbol)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_let(&self, symbol: &K) -> Option<&V> {
|
pub fn lookup_let(&self, level: usize, idx: usize) -> V {
|
||||||
self.let_.lookup(symbol)
|
self.let_.lookup(level, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_with(&self, symbol: &K) -> Option<&V> {
|
pub fn lookup_with(&self, symbol: &K) -> Option<&V> {
|
||||||
@@ -82,20 +80,25 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
self.with.map.is_some()
|
self.with.map.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_arg(self: Gc<'gc, Self>, ident: K, val: V, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
#[must_use]
|
||||||
|
pub fn enter_arg(self: Gc<'gc, Self>, val: V, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
||||||
|
let mut args = self.args.clone();
|
||||||
|
args.push(val);
|
||||||
Gc::new(
|
Gc::new(
|
||||||
mc,
|
mc,
|
||||||
Env {
|
Env {
|
||||||
let_: self.let_.enter_arg(ident, val, mc),
|
let_: self.let_,
|
||||||
with: self.with,
|
with: self.with,
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
|
args
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn enter_let(
|
pub fn enter_let(
|
||||||
self: Gc<'gc, Self>,
|
self: Gc<'gc, Self>,
|
||||||
map: Gc<'gc, HashMap<K, V>>,
|
map: Vec<V>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Gc<'gc, Self> {
|
) -> Gc<'gc, Self> {
|
||||||
Gc::new(
|
Gc::new(
|
||||||
@@ -103,11 +106,13 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
Self {
|
Self {
|
||||||
let_: self.let_.enter_let(map, mc),
|
let_: self.let_.enter_let(map, mc),
|
||||||
with: self.with,
|
with: self.with,
|
||||||
|
args: self.args.clone(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn enter_with(
|
pub fn enter_with(
|
||||||
self: Gc<'gc, Self>,
|
self: Gc<'gc, Self>,
|
||||||
map: Gc<'gc, HashMap<K, V>>,
|
map: Gc<'gc, HashMap<K, V>>,
|
||||||
@@ -118,6 +123,7 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
Env {
|
Env {
|
||||||
let_: self.let_,
|
let_: self.let_,
|
||||||
with: self.with.enter(map, mc),
|
with: self.with.enter(map, mc),
|
||||||
|
args: self.args.clone(),
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -128,53 +134,35 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> LetEnv<'gc, K, V> {
|
impl<'gc, V: Clone + Collect<'gc>> LetEnv<'gc, V> {
|
||||||
pub fn new(map: Gc<'gc, HashMap<K, V>>, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
pub fn new(map: Vec<V>, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
||||||
Gc::new(
|
Gc::new(
|
||||||
mc,
|
mc,
|
||||||
Self {
|
Self {
|
||||||
map: LetNode::Let(map),
|
map,
|
||||||
last: None,
|
last: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(&self, symbol: &K) -> Option<&V> {
|
pub fn lookup(&self, level: usize, idx: usize) -> V {
|
||||||
use self::LetNode::*;
|
let mut cur = self;
|
||||||
match &self.map {
|
for _ in 0..level {
|
||||||
Let(map) | MultiArg(map) => {
|
let last = cur.last.unwrap();
|
||||||
if let Some(val) = map.get(symbol) {
|
cur = last.as_ref();
|
||||||
return Some(val);
|
|
||||||
}
|
}
|
||||||
}
|
cur.map[idx].clone()
|
||||||
SingleArg(sym, val) => {
|
|
||||||
if sym == symbol {
|
|
||||||
return Some(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.last.as_ref().and_then(|env| env.lookup(symbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enter_arg(self: Gc<'gc, Self>, ident: K, val: V, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
|
||||||
Gc::new(
|
|
||||||
mc,
|
|
||||||
Self {
|
|
||||||
map: LetNode::SingleArg(ident, val),
|
|
||||||
last: Some(self),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_let(
|
pub fn enter_let(
|
||||||
self: Gc<'gc, Self>,
|
self: Gc<'gc, Self>,
|
||||||
map: Gc<'gc, HashMap<K, V>>,
|
map: Vec<V>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Gc<'gc, Self> {
|
) -> Gc<'gc, Self> {
|
||||||
Gc::new(
|
Gc::new(
|
||||||
mc,
|
mc,
|
||||||
Self {
|
Self {
|
||||||
map: LetNode::Let(map),
|
map,
|
||||||
last: Some(self),
|
last: Some(self),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ pub struct Helpers<'ctx> {
|
|||||||
pub eq: FunctionValue<'ctx>,
|
pub eq: FunctionValue<'ctx>,
|
||||||
pub or: FunctionValue<'ctx>,
|
pub or: FunctionValue<'ctx>,
|
||||||
pub call: FunctionValue<'ctx>,
|
pub call: FunctionValue<'ctx>,
|
||||||
|
pub arg: FunctionValue<'ctx>,
|
||||||
|
pub lookup_let: FunctionValue<'ctx>,
|
||||||
pub lookup: FunctionValue<'ctx>,
|
pub lookup: FunctionValue<'ctx>,
|
||||||
pub force: FunctionValue<'ctx>,
|
pub force: FunctionValue<'ctx>,
|
||||||
}
|
}
|
||||||
@@ -113,6 +115,16 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
let arg = module.add_function(
|
||||||
|
"arg",
|
||||||
|
value_type.fn_type(&[ptr_int_type.into(), ptr_type.into()], false),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let lookup_let = module.add_function(
|
||||||
|
"lookup_let",
|
||||||
|
value_type.fn_type(&[ptr_int_type.into(), ptr_int_type.into(), ptr_type.into()], false),
|
||||||
|
None,
|
||||||
|
);
|
||||||
let lookup = module.add_function(
|
let lookup = module.add_function(
|
||||||
"lookup",
|
"lookup",
|
||||||
value_type.fn_type(&[ptr_int_type.into(), ptr_type.into()], false),
|
value_type.fn_type(&[ptr_int_type.into(), ptr_type.into()], false),
|
||||||
@@ -142,6 +154,8 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
execution_engine.add_global_mapping(&eq, helper_eq as _);
|
execution_engine.add_global_mapping(&eq, helper_eq as _);
|
||||||
execution_engine.add_global_mapping(&or, helper_or as _);
|
execution_engine.add_global_mapping(&or, helper_or as _);
|
||||||
execution_engine.add_global_mapping(&call, helper_call as _);
|
execution_engine.add_global_mapping(&call, helper_call as _);
|
||||||
|
execution_engine.add_global_mapping(&arg, helper_arg as _);
|
||||||
|
execution_engine.add_global_mapping(&lookup_let, helper_lookup_let as _);
|
||||||
execution_engine.add_global_mapping(&lookup, helper_lookup as _);
|
execution_engine.add_global_mapping(&lookup, helper_lookup as _);
|
||||||
execution_engine.add_global_mapping(&force, helper_force as _);
|
execution_engine.add_global_mapping(&force, helper_force as _);
|
||||||
|
|
||||||
@@ -165,6 +179,8 @@ impl<'ctx> Helpers<'ctx> {
|
|||||||
eq,
|
eq,
|
||||||
or,
|
or,
|
||||||
call,
|
call,
|
||||||
|
arg,
|
||||||
|
lookup_let,
|
||||||
lookup,
|
lookup,
|
||||||
force,
|
force,
|
||||||
}
|
}
|
||||||
@@ -348,9 +364,21 @@ extern "C" fn helper_call<'gc>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
|
||||||
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
|
let val: JITValue = env.lookup_arg(idx).into();
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const VmEnv) -> JITValue {
|
||||||
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
|
let val: JITValue = env.lookup_let(level, idx).into();
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
|
||||||
let env = unsafe { env.as_ref() }.unwrap();
|
let env = unsafe { env.as_ref() }.unwrap();
|
||||||
let val: JITValue = env.lookup_slow(&sym).unwrap().into();
|
let val: JITValue = env.lookup_with(&sym).unwrap().into();
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +401,7 @@ extern "C" fn helper_force<'gc>(
|
|||||||
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
let (opcodes, env) = thunk.suspend(mc).unwrap();
|
||||||
let func = unsafe { jit.as_ref() }
|
let func = unsafe { jit.as_ref() }
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.compile_seq(opcodes.iter().copied(), vm)
|
.compile_seq(opcodes.iter().copied().rev(), vm)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let val = unsafe { func.call(env.as_ref() as *const _, mc as *const _) };
|
let val = unsafe { func.call(env.as_ref() as *const _, mc as *const _) };
|
||||||
thunk.insert_value(val.into(), mc);
|
thunk.insert_value(val.into(), mc);
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ impl<'gc> JITContext<'gc> {
|
|||||||
|
|
||||||
pub fn compile_seq(
|
pub fn compile_seq(
|
||||||
&self,
|
&self,
|
||||||
opcodes: impl ExactSizeIterator<Item = OpCode> + DoubleEndedIterator,
|
mut opcodes: impl ExactSizeIterator<Item = OpCode>,
|
||||||
vm: &'gc VM<'gc>,
|
vm: &'gc VM<'gc>,
|
||||||
) -> Result<JITFunc<'gc>> {
|
) -> Result<JITFunc<'gc>> {
|
||||||
let mut stack = Stack::<_, STACK_SIZE>::new();
|
let mut stack = Stack::<_, STACK_SIZE>::new();
|
||||||
@@ -211,7 +211,7 @@ impl<'gc> JITContext<'gc> {
|
|||||||
let entry = self.context.append_basic_block(func_, "entry");
|
let entry = self.context.append_basic_block(func_, "entry");
|
||||||
self.builder.position_at_end(entry);
|
self.builder.position_at_end(entry);
|
||||||
let len = opcodes.len();
|
let len = opcodes.len();
|
||||||
self.build_expr(&mut opcodes.rev(), vm, env, mc, &mut stack, func_, len)?;
|
self.build_expr(&mut opcodes, vm, env, mc, &mut stack, func_, len)?;
|
||||||
|
|
||||||
assert_eq!(stack.len(), 1);
|
assert_eq!(stack.len(), 1);
|
||||||
let value = stack.pop();
|
let value = stack.pop();
|
||||||
@@ -437,6 +437,47 @@ impl<'gc> JITContext<'gc> {
|
|||||||
_ => todo!("BinOp::{:?} not implemented in JIT", op),
|
_ => todo!("BinOp::{:?} not implemented in JIT", op),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OpCode::Arg { level } => stack.push(
|
||||||
|
self.builder
|
||||||
|
.build_direct_call(
|
||||||
|
self.helpers.arg,
|
||||||
|
&[
|
||||||
|
self.helpers
|
||||||
|
.ptr_int_type
|
||||||
|
.const_int(level as u64, false)
|
||||||
|
.into(),
|
||||||
|
env.into(),
|
||||||
|
],
|
||||||
|
"call_arg",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap(),
|
||||||
|
)?,
|
||||||
|
OpCode::LookUpLet { level, idx } => stack.push(
|
||||||
|
self.builder
|
||||||
|
.build_direct_call(
|
||||||
|
self.helpers.lookup_let,
|
||||||
|
&[
|
||||||
|
self.helpers
|
||||||
|
.ptr_int_type
|
||||||
|
.const_int(level as u64, false)
|
||||||
|
.into(),
|
||||||
|
self.helpers
|
||||||
|
.ptr_int_type
|
||||||
|
.const_int(idx as u64, false)
|
||||||
|
.into(),
|
||||||
|
env.into(),
|
||||||
|
],
|
||||||
|
"call_lookup_let",
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap(),
|
||||||
|
)?,
|
||||||
|
|
||||||
OpCode::LookUp { sym } => stack.push(
|
OpCode::LookUp { sym } => stack.push(
|
||||||
self.builder
|
self.builder
|
||||||
.build_direct_call(
|
.build_direct_call(
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use hashbrown::{HashMap, HashSet};
|
|||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use rpds::vector_sync;
|
|
||||||
|
|
||||||
use crate::builtins::vm_env;
|
use crate::builtins::vm_env;
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
@@ -77,7 +76,7 @@ macro_rules! symbol {
|
|||||||
|
|
||||||
macro_rules! list {
|
macro_rules! list {
|
||||||
($($x:tt)*) => (
|
($($x:tt)*) => (
|
||||||
Value::List(List::new(vector_sync![$($x)*]))
|
Value::List(List::new(vec![$($x)*]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,3 +112,8 @@ impl PartialEq for Const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Const {}
|
impl Eq for Const {}
|
||||||
|
|
||||||
|
pub enum MaybeThunk {
|
||||||
|
Thunk(usize),
|
||||||
|
Const(Const)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ use std::ops::Deref;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use gc_arena::{Collect, Gc, Mutation};
|
use gc_arena::Collect;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::env::VmEnv;
|
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
use super::super::public as p;
|
use super::super::public as p;
|
||||||
@@ -58,14 +57,6 @@ impl<'gc> AttrSet<'gc> {
|
|||||||
self.data.get(&sym).is_some()
|
self.data.get(&sym).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn capture(&mut self, env: Gc<'gc, VmEnv<'gc>>, mc: &Mutation<'gc>) {
|
|
||||||
self.data.iter().for_each(|(_, v)| {
|
|
||||||
if let Value::Thunk(ref thunk) = v.clone() {
|
|
||||||
thunk.capture_env(env, mc);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, other: &AttrSet<'gc>) {
|
pub fn update(&mut self, other: &AttrSet<'gc>) {
|
||||||
for (k, v) in other.data.iter() {
|
for (k, v) in other.data.iter() {
|
||||||
self.push_attr_force(*k, v.clone())
|
self.push_attr_force(*k, v.clone())
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ use std::cell::Cell;
|
|||||||
|
|
||||||
use gc_arena::lock::{GcRefLock, RefLock};
|
use gc_arena::lock::{GcRefLock, RefLock};
|
||||||
use gc_arena::{Collect, Gc, Mutation};
|
use gc_arena::{Collect, Gc, Mutation};
|
||||||
use hashbrown::HashMap;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use crate::bytecode::Func as BFunc;
|
use crate::bytecode::Func as BFunc;
|
||||||
use crate::env::VmEnv;
|
use crate::env::VmEnv;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::ir;
|
use crate::ir;
|
||||||
use crate::jit::JITFunc;
|
use crate::jit::JITFunc;
|
||||||
use crate::ty::internal::{Thunk, Value};
|
use crate::ty::internal::Value;
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Collect)]
|
#[derive(Debug, Clone, Collect)]
|
||||||
@@ -75,45 +73,7 @@ impl<'gc> Func<'gc> {
|
|||||||
vm: &'gc VM<'gc>,
|
vm: &'gc VM<'gc>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Result<Value<'gc>> {
|
) -> Result<Value<'gc>> {
|
||||||
use Param::*;
|
let env = self.env.enter_arg(arg, mc);
|
||||||
|
|
||||||
let mut env = self.env;
|
|
||||||
env = match self.func.param.clone() {
|
|
||||||
Ident(ident) => env.enter_arg(ident, arg, mc),
|
|
||||||
Formals {
|
|
||||||
formals,
|
|
||||||
ellipsis,
|
|
||||||
alias,
|
|
||||||
} => {
|
|
||||||
let arg = arg.unwrap_attr_set();
|
|
||||||
let mut new = HashMap::with_capacity(formals.len() + alias.iter().len());
|
|
||||||
if !ellipsis
|
|
||||||
&& arg
|
|
||||||
.as_inner()
|
|
||||||
.iter()
|
|
||||||
.map(|(k, _)| k)
|
|
||||||
.sorted()
|
|
||||||
.ne(formals.iter().map(|(k, _)| k).sorted())
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
for (formal, default) in formals {
|
|
||||||
let arg = arg
|
|
||||||
.select(formal)
|
|
||||||
.or_else(|| {
|
|
||||||
default
|
|
||||||
.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx), mc)))
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
new.insert(formal, arg);
|
|
||||||
}
|
|
||||||
if let Some(alias) = alias {
|
|
||||||
new.insert(alias, Value::AttrSet(arg));
|
|
||||||
}
|
|
||||||
env.enter_let(Gc::new(mc, new), mc)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let compiled = self
|
let compiled = self
|
||||||
.compiled
|
.compiled
|
||||||
.borrow_mut(mc)
|
.borrow_mut(mc)
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
use gc_arena::{Collect, Gc, Mutation};
|
||||||
use derive_more::Constructor;
|
|
||||||
use gc_arena::Collect;
|
|
||||||
use rpds::Vector;
|
|
||||||
|
|
||||||
use crate::ty::public as p;
|
use crate::ty::public as p;
|
||||||
use crate::vm::VM;
|
use crate::vm::VM;
|
||||||
|
use crate::env::VmEnv;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Constructor, Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct List<'gc> {
|
pub struct List<'gc> {
|
||||||
data: Vector<Value<'gc>>,
|
data: Vec<Value<'gc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
||||||
@@ -23,22 +21,40 @@ unsafe impl<'gc> Collect<'gc> for List<'gc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> List<'gc> {
|
impl<'gc> List<'gc> {
|
||||||
pub fn empty() -> Self {
|
pub fn new() -> Self {
|
||||||
List {
|
List {
|
||||||
data: Vector::new(),
|
data: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_capacity(cap: usize) -> Self {
|
||||||
|
List {
|
||||||
|
data: Vec::with_capacity(cap),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, elem: Value<'gc>) {
|
pub fn push(&mut self, elem: Value<'gc>) {
|
||||||
self.data.push_back_mut(elem);
|
self.data.push(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat(&mut self, other: &List<'gc>) {
|
pub fn concat(&mut self, other: &List<'gc>) {
|
||||||
for elem in other.data.iter() {
|
for elem in other.data.iter() {
|
||||||
self.data.push_back_mut(elem.clone());
|
self.data.push(elem.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn capture(&mut self, env: Gc<'gc, VmEnv<'gc>>, mc: &Mutation<'gc>) {
|
||||||
|
self.data.iter().for_each(|v| {
|
||||||
|
if let Value::Thunk(ref thunk) = v.clone() {
|
||||||
|
thunk.capture_env(env, mc);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> Vec<Value<'gc>> {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_public(&self, vm: &VM<'gc>, seen: &mut HashSet<Value<'gc>>) -> p::Value {
|
pub fn to_public(&self, vm: &VM<'gc>, seen: &mut HashSet<Value<'gc>>) -> p::Value {
|
||||||
p::Value::List(p::List::new(
|
p::Value::List(p::List::new(
|
||||||
self.data
|
self.data
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
@@ -35,66 +33,49 @@ pub struct CoW<'gc, T: Clone + Collect<'gc>> {
|
|||||||
inner: Gc<'gc, CoWInner<'gc, T>>,
|
inner: Gc<'gc, CoWInner<'gc, T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Collect)]
|
||||||
|
#[collect(no_drop)]
|
||||||
struct CoWInner<'gc, T: Clone + Collect<'gc>> {
|
struct CoWInner<'gc, T: Clone + Collect<'gc>> {
|
||||||
ref_count: Cell<usize>,
|
ref_count: Cell<usize>,
|
||||||
data: MaybeUninit<T>,
|
data: GcRefLock<'gc, T>,
|
||||||
_marker: PhantomData<Cell<&'gc ()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'gc, T: Clone + Collect<'gc>> Collect<'gc> for CoWInner<'gc, T> {
|
|
||||||
fn trace<Tr: gc_arena::collect::Trace<'gc>>(&self, cc: &mut Tr) {
|
|
||||||
unsafe { self.data.assume_init_ref() }.trace(cc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
impl<'gc, T: Clone + Collect<'gc>> CoW<'gc, T> {
|
impl<'gc, T: Clone + Collect<'gc>> CoW<'gc, T> {
|
||||||
pub fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
pub fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Gc::new(mc, CoWInner::new(data)),
|
inner: Gc::new(mc, CoWInner::new(data, mc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_cyclic(datafn: impl FnOnce(Self) -> T, mc: &Mutation<'gc>) -> Self {
|
pub unsafe fn make_cyclic(&mut self, f: impl FnOnce(&mut T, Self), mc: &Mutation<'gc>) {
|
||||||
let inner = Gc::new(
|
let inner = self.inner;
|
||||||
mc,
|
self.make_mut(|self_mut| f(self_mut, Self { inner }), mc);
|
||||||
CoWInner {
|
self.inner.ref_count.set(self.inner.ref_count.get() + 1);
|
||||||
ref_count: Cell::new(1),
|
|
||||||
data: MaybeUninit::uninit(),
|
|
||||||
_marker: PhantomData,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let data = datafn(CoW { inner });
|
|
||||||
unsafe { std::mem::transmute::<_, &mut MaybeUninit<_>>(&inner.data) }.write(data);
|
|
||||||
Self { inner }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_mut(&mut self, mc: &Mutation<'gc>) -> &mut T {
|
pub fn make_mut<U>(&mut self, f: impl FnOnce(&mut T) -> U, mc: &Mutation<'gc>) -> U {
|
||||||
if self.inner.ref_count.get() == 1 {
|
if self.inner.ref_count.get() == 1 {
|
||||||
unsafe { std::mem::transmute(self.inner.data.assume_init_ref()) }
|
f(&mut *self.inner.data.borrow_mut(mc))
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
*self = CoW::new(self.inner.data.borrow().clone(), mc);
|
||||||
*self = CoW::new(self.inner.data.assume_init_ref().clone(), mc);
|
f(&mut *self.inner.data.borrow_mut(mc))
|
||||||
std::mem::transmute(self.inner.data.assume_init_ref())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ptr(&self) -> *const T {
|
pub fn as_ptr(&self) -> *const T {
|
||||||
self.as_ref() as *const T
|
&*self.as_ref() as *const T
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> AsRef<T> for CoW<'gc, T> {
|
pub fn as_ref(&self) -> std::cell::Ref<'_, T> {
|
||||||
fn as_ref(&self) -> &T {
|
self.inner.data.borrow()
|
||||||
unsafe { self.inner.data.assume_init_ref() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> Deref for CoW<'gc, T> {
|
impl<'gc, T: Clone + Collect<'gc>> Deref for CoW<'gc, T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.as_ref()
|
unsafe { self.as_ptr().as_ref() }.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +93,10 @@ impl<'gc, T: Clone + Collect<'gc>> Drop for CoW<'gc, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc, T: Clone + Collect<'gc>> CoWInner<'gc, T> {
|
impl<'gc, T: Clone + Collect<'gc>> CoWInner<'gc, T> {
|
||||||
fn new(data: T) -> Self {
|
fn new(data: T, mc: &Mutation<'gc>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ref_count: Cell::new(1),
|
ref_count: Cell::new(1),
|
||||||
data: MaybeUninit::new(data),
|
data: Gc::new(mc, RefLock::new(data))
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +133,7 @@ impl Hash for Value<'_> {
|
|||||||
List(x) => x.as_ptr().hash(state),
|
List(x) => x.as_ptr().hash(state),
|
||||||
Catchable(x) => x.hash(state),
|
Catchable(x) => x.hash(state),
|
||||||
PrimOp(x) => (x.as_ref() as *const self::PrimOp).hash(state),
|
PrimOp(x) => (x.as_ref() as *const self::PrimOp).hash(state),
|
||||||
PartialPrimOp(x) => (x.as_ref() as *const self::PartialPrimOp).hash(state),
|
PartialPrimOp(x) => x.as_ptr().hash(state),
|
||||||
Func(x) => (x.as_ref() as *const self::Func).hash(state),
|
Func(x) => (x.as_ref() as *const self::Func).hash(state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,22 +186,6 @@ pub enum ValueAsRef<'v, 'gc> {
|
|||||||
Func(&'v Func<'gc>),
|
Func(&'v Func<'gc>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap)]
|
|
||||||
pub enum ValueAsMut<'v, 'gc> {
|
|
||||||
Int(i64),
|
|
||||||
Float(f64),
|
|
||||||
Bool(bool),
|
|
||||||
String(&'v str),
|
|
||||||
Null,
|
|
||||||
Thunk(&'v Thunk<'gc>),
|
|
||||||
AttrSet(&'v mut AttrSet<'gc>),
|
|
||||||
List(&'v mut List<'gc>),
|
|
||||||
Catchable(&'v str),
|
|
||||||
PrimOp(&'v PrimOp),
|
|
||||||
PartialPrimOp(&'v mut PartialPrimOp<'gc>),
|
|
||||||
Func(&'v Func<'gc>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc, 'v> Value<'gc> {
|
impl<'gc, 'v> Value<'gc> {
|
||||||
pub fn as_ref(&'v self) -> ValueAsRef<'v, 'gc> {
|
pub fn as_ref(&'v self) -> ValueAsRef<'v, 'gc> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
@@ -241,25 +205,6 @@ impl<'gc, 'v> Value<'gc> {
|
|||||||
Func(x) => R::Func(x),
|
Func(x) => R::Func(x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_mut(&'v mut self, mc: &Mutation<'gc>) -> ValueAsMut<'v, 'gc> {
|
|
||||||
use Value::*;
|
|
||||||
use ValueAsMut as M;
|
|
||||||
match self {
|
|
||||||
Int(x) => M::Int(*x),
|
|
||||||
Float(x) => M::Float(*x),
|
|
||||||
Bool(x) => M::Bool(*x),
|
|
||||||
String(x) => M::String(x),
|
|
||||||
Null => M::Null,
|
|
||||||
Thunk(x) => M::Thunk(x),
|
|
||||||
AttrSet(x) => M::AttrSet(x.make_mut(mc)),
|
|
||||||
List(x) => M::List(x.make_mut(mc)),
|
|
||||||
Catchable(x) => M::Catchable(x),
|
|
||||||
PrimOp(x) => M::PrimOp(x),
|
|
||||||
PartialPrimOp(x) => M::PartialPrimOp(x.make_mut(mc)),
|
|
||||||
Func(x) => M::Func(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<'gc> Value<'gc> {
|
impl<'gc> Value<'gc> {
|
||||||
pub fn ok(self) -> Result<Self> {
|
pub fn ok(self) -> Result<Self> {
|
||||||
@@ -382,7 +327,7 @@ impl<'gc> Value<'gc> {
|
|||||||
(Float(a), Float(b)) => Float(a + b),
|
(Float(a), Float(b)) => Float(a + b),
|
||||||
(String(a), String(b)) => {
|
(String(a), String(b)) => {
|
||||||
let mut a = a.clone();
|
let mut a = a.clone();
|
||||||
a.make_mut(mc).push_str(b.as_str());
|
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||||
String(a)
|
String(a)
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => return,
|
(Value::Catchable(_), _) => return,
|
||||||
@@ -426,7 +371,7 @@ impl<'gc> Value<'gc> {
|
|||||||
match (self.coerce_to_string(), other.coerce_to_string()) {
|
match (self.coerce_to_string(), other.coerce_to_string()) {
|
||||||
(Value::String(a), Value::String(b)) => {
|
(Value::String(a), Value::String(b)) => {
|
||||||
let mut a = a.clone();
|
let mut a = a.clone();
|
||||||
a.make_mut(mc).push_str(b.as_str())
|
a.make_mut(|a| a.push_str(b.as_str()), mc);
|
||||||
}
|
}
|
||||||
(_, Value::Catchable(_)) => *self = other,
|
(_, Value::Catchable(_)) => *self = other,
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
@@ -437,7 +382,7 @@ impl<'gc> Value<'gc> {
|
|||||||
|
|
||||||
pub fn push(&mut self, elem: Self, mc: &Mutation<'gc>) -> &mut Self {
|
pub fn push(&mut self, elem: Self, mc: &Mutation<'gc>) -> &mut Self {
|
||||||
if let Value::List(list) = self {
|
if let Value::List(list) = self {
|
||||||
list.make_mut(mc).push(elem);
|
list.make_mut(|list| list.push(elem), mc);
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Value::Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = elem {
|
} else if let Value::Catchable(_) = elem {
|
||||||
*self = elem;
|
*self = elem;
|
||||||
@@ -454,7 +399,7 @@ impl<'gc> Value<'gc> {
|
|||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::List(a), Value::List(b)) => {
|
(Value::List(a), Value::List(b)) => {
|
||||||
a.make_mut(mc).concat(b.as_ref());
|
a.make_mut(|a| a.concat(&b), mc);
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
@@ -463,7 +408,7 @@ impl<'gc> Value<'gc> {
|
|||||||
|
|
||||||
pub fn push_attr(&mut self, sym: usize, val: Self, mc: &Mutation<'gc>) -> &mut Self {
|
pub fn push_attr(&mut self, sym: usize, val: Self, mc: &Mutation<'gc>) -> &mut Self {
|
||||||
if let Value::AttrSet(attrs) = self {
|
if let Value::AttrSet(attrs) = self {
|
||||||
attrs.make_mut(mc).push_attr(sym, val);
|
attrs.make_mut(|attrs| attrs.push_attr(sym, val), mc)
|
||||||
} else if let Value::Catchable(_) = self {
|
} else if let Value::Catchable(_) = self {
|
||||||
} else if let Value::Catchable(_) = val {
|
} else if let Value::Catchable(_) = val {
|
||||||
*self = val
|
*self = val
|
||||||
@@ -480,7 +425,7 @@ impl<'gc> Value<'gc> {
|
|||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
(Value::AttrSet(a), Value::AttrSet(b)) => {
|
||||||
a.make_mut(mc).update(b.as_ref());
|
a.make_mut(|a| a.update(&b), mc)
|
||||||
}
|
}
|
||||||
(Value::Catchable(_), _) => (),
|
(Value::Catchable(_), _) => (),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
@@ -556,7 +501,7 @@ impl<'gc> Value<'gc> {
|
|||||||
Int(x) => Value::Const(Const::Int(*x)),
|
Int(x) => Value::Const(Const::Int(*x)),
|
||||||
Float(x) => Value::Const(Const::Float(*x)),
|
Float(x) => Value::Const(Const::Float(*x)),
|
||||||
Bool(x) => Value::Const(Const::Bool(*x)),
|
Bool(x) => Value::Const(Const::Bool(*x)),
|
||||||
String(x) => Value::Const(Const::String(x.as_ref().into())),
|
String(x) => Value::Const(Const::String(x.as_str().into())),
|
||||||
Null => Value::Const(Const::Null),
|
Null => Value::Const(Const::Null),
|
||||||
Thunk(_) => Value::Thunk,
|
Thunk(_) => Value::Thunk,
|
||||||
PrimOp(primop) => Value::PrimOp(primop.name),
|
PrimOp(primop) => Value::PrimOp(primop.name),
|
||||||
|
|||||||
@@ -73,13 +73,17 @@ impl<'gc> PartialPrimOp<'gc> {
|
|||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Result<Value<'gc>> {
|
) -> Result<Value<'gc>> {
|
||||||
let func = self.func;
|
let func = self.func;
|
||||||
let self_mut = self.make_mut(mc);
|
let Some(ret) = self.make_mut(|self_mut| {
|
||||||
self_mut.args.push(arg);
|
self_mut.args.push(arg);
|
||||||
self_mut.arity -= 1;
|
self_mut.arity -= 1;
|
||||||
if self_mut.arity > 0 {
|
if self_mut.arity == 0 {
|
||||||
Value::PartialPrimOp(self.clone()).ok()
|
Some(func(std::mem::take(&mut self_mut.args), vm, mc))
|
||||||
} else {
|
} else {
|
||||||
func(std::mem::take(&mut self_mut.args), vm, mc)
|
None
|
||||||
}
|
}
|
||||||
|
}, mc) else {
|
||||||
|
return Value::PartialPrimOp(self.clone()).ok();
|
||||||
|
};
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
// TODO: Contextful String
|
// TODO: Contextful String
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use rpds::List;
|
|
||||||
|
|
||||||
pub struct StringContext {
|
pub struct StringContext {
|
||||||
context: List<()>,
|
context: Vec<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StringContext {
|
impl StringContext {
|
||||||
pub fn new() -> StringContext {
|
pub fn new() -> StringContext {
|
||||||
StringContext {
|
StringContext {
|
||||||
context: List::new(),
|
context: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use std::sync::LazyLock;
|
|||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rpds::VectorSync;
|
|
||||||
|
|
||||||
use super::common::*;
|
use super::common::*;
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ impl Display for AttrSet {
|
|||||||
|
|
||||||
#[derive(Constructor, Clone, Debug, PartialEq)]
|
#[derive(Constructor, Clone, Debug, PartialEq)]
|
||||||
pub struct List {
|
pub struct List {
|
||||||
data: VectorSync<Value>,
|
data: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for List {
|
impl Display for List {
|
||||||
|
|||||||
106
src/vm/mod.rs
106
src/vm/mod.rs
@@ -3,7 +3,6 @@ use std::cell::RefCell;
|
|||||||
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
use gc_arena::{Arena, Collect, Gc, Mutation, Rootable};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use crate::builtins::vm_env;
|
use crate::builtins::vm_env;
|
||||||
use crate::bytecode::{BinOp, Func as F, OpCode, OpCodes, Program, UnOp};
|
use crate::bytecode::{BinOp, Func as F, OpCode, OpCodes, Program, UnOp};
|
||||||
@@ -88,49 +87,9 @@ pub fn eval<T, F: for<'gc> FnOnce(Value<'gc>, &mut GcRoot<'gc>, &Mutation<'gc>)
|
|||||||
}
|
}
|
||||||
Consq::PopEnv => _ = root.envs.pop().unwrap(),
|
Consq::PopEnv => _ = root.envs.pop().unwrap(),
|
||||||
Consq::Call => {
|
Consq::Call => {
|
||||||
use Param::*;
|
|
||||||
let arg = root.stack.pop();
|
let arg = root.stack.pop();
|
||||||
let func = root.stack.pop().unwrap_func();
|
let func = root.stack.pop().unwrap_func();
|
||||||
let env = func.env;
|
let env = func.env.enter_arg(arg, mc);
|
||||||
let env = match func.func.param.clone() {
|
|
||||||
Ident(ident) => env.enter_arg(ident, arg, mc),
|
|
||||||
Formals {
|
|
||||||
formals,
|
|
||||||
ellipsis,
|
|
||||||
alias,
|
|
||||||
} => {
|
|
||||||
let arg = arg.unwrap_attr_set();
|
|
||||||
let mut new =
|
|
||||||
HashMap::with_capacity(formals.len() + alias.iter().len());
|
|
||||||
if !ellipsis
|
|
||||||
&& arg
|
|
||||||
.iter()
|
|
||||||
.map(|(k, _)| k)
|
|
||||||
.sorted()
|
|
||||||
.ne(formals.iter().map(|(k, _)| k).sorted())
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
for (formal, default) in formals {
|
|
||||||
// TODO: rec env
|
|
||||||
let arg = arg
|
|
||||||
.select(formal)
|
|
||||||
.or_else(|| {
|
|
||||||
default.map(|idx| {
|
|
||||||
Value::Thunk(
|
|
||||||
Thunk::new(root.vm.get_thunk(idx), mc),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
new.insert(formal, arg);
|
|
||||||
}
|
|
||||||
if let Some(alias) = alias {
|
|
||||||
new.insert(alias, Value::AttrSet(arg));
|
|
||||||
}
|
|
||||||
env.enter_let(Gc::new(mc, new), mc)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let count = func.count.get();
|
let count = func.count.get();
|
||||||
func.count.set(count + 1);
|
func.count.set(count + 1);
|
||||||
if count >= 1 {
|
if count >= 1 {
|
||||||
@@ -200,13 +159,12 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else {
|
let Some(val) = stack.tos().as_ref().unwrap_thunk().get_value() else {
|
||||||
return Ok(Consq::Force);
|
return Ok(Consq::Force);
|
||||||
};
|
};
|
||||||
stack.pop();
|
*stack.tos_mut() = val;
|
||||||
stack.push(val)?;
|
|
||||||
}
|
}
|
||||||
OpCode::InsertValue => {
|
OpCode::InsertValue => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
stack.pop().unwrap_thunk().insert_value(val.clone(), mc);
|
stack.tos().as_ref().unwrap_thunk().insert_value(val.clone(), mc);
|
||||||
let _ = stack.push(val);
|
*stack.tos_mut() = val;
|
||||||
}
|
}
|
||||||
OpCode::Jmp { step } => return Ok(Consq::Jmp(step)),
|
OpCode::Jmp { step } => return Ok(Consq::Jmp(step)),
|
||||||
OpCode::JmpIfFalse { step } => {
|
OpCode::JmpIfFalse { step } => {
|
||||||
@@ -218,7 +176,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
let arg = stack.pop();
|
let arg = stack.pop();
|
||||||
let func = stack.tos_mut();
|
let func = stack.tos_mut();
|
||||||
if func.is_func() {
|
if func.is_func() {
|
||||||
stack.push(arg)?;
|
let _ = stack.push(arg);
|
||||||
return Ok(Consq::Call);
|
return Ok(Consq::Call);
|
||||||
}
|
}
|
||||||
func.call(arg, vm, mc)?;
|
func.call(arg, vm, mc)?;
|
||||||
@@ -227,6 +185,9 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
let func = vm.get_func(idx);
|
let func = vm.get_func(idx);
|
||||||
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
stack.push(Value::Func(Gc::new(mc, Func::new(func, *env, mc))))?;
|
||||||
}
|
}
|
||||||
|
OpCode::Arg { level } => {
|
||||||
|
stack.push(env.lookup_arg(level))?;
|
||||||
|
}
|
||||||
OpCode::UnOp { op } => {
|
OpCode::UnOp { op } => {
|
||||||
use UnOp::*;
|
use UnOp::*;
|
||||||
let value = stack.tos_mut();
|
let value = stack.tos_mut();
|
||||||
@@ -262,8 +223,8 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
OpCode::Path => {
|
OpCode::Path => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
OpCode::List => {
|
OpCode::List { cap } => {
|
||||||
stack.push(Value::List(CoW::new(List::empty(), mc)))?;
|
stack.push(Value::List(CoW::new(List::with_capacity(cap), mc)))?;
|
||||||
}
|
}
|
||||||
OpCode::PushElem => {
|
OpCode::PushElem => {
|
||||||
let elem = stack.pop();
|
let elem = stack.pop();
|
||||||
@@ -272,22 +233,14 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
OpCode::AttrSet { cap } => {
|
OpCode::AttrSet { cap } => {
|
||||||
stack.push(Value::AttrSet(CoW::new(AttrSet::with_capacity(cap), mc)))?;
|
stack.push(Value::AttrSet(CoW::new(AttrSet::with_capacity(cap), mc)))?;
|
||||||
}
|
}
|
||||||
OpCode::FinalizeRec => {
|
OpCode::FinalizeLet => {
|
||||||
let mut new = HashMap::new();
|
let mut list = stack.pop().unwrap_list();
|
||||||
stack
|
let map = list
|
||||||
.tos()
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_attr_set()
|
.clone()
|
||||||
.as_inner()
|
.into_inner();
|
||||||
.iter()
|
*env = env.enter_let(map, mc);
|
||||||
.map(|(&k, v)| (k, v.clone()))
|
list.make_mut(|list| list.capture(*env, mc), mc);
|
||||||
.collect_into(&mut new);
|
|
||||||
*env = env.enter_let(Gc::new(mc, new), mc);
|
|
||||||
stack
|
|
||||||
.tos_mut()
|
|
||||||
.as_mut(mc)
|
|
||||||
.unwrap_attr_set()
|
|
||||||
.capture(*env, mc);
|
|
||||||
}
|
}
|
||||||
OpCode::PushStaticAttr { name } => {
|
OpCode::PushStaticAttr { name } => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
@@ -296,7 +249,7 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
OpCode::PushDynamicAttr => {
|
OpCode::PushDynamicAttr => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
let sym = stack.pop();
|
let sym = stack.pop();
|
||||||
let sym = vm.new_sym(sym.unwrap_string().as_ref());
|
let sym = vm.new_sym::<&str>(&sym.unwrap_string());
|
||||||
stack.tos_mut().push_attr(sym, val, mc);
|
stack.tos_mut().push_attr(sym, val, mc);
|
||||||
}
|
}
|
||||||
OpCode::Select { sym } => {
|
OpCode::Select { sym } => {
|
||||||
@@ -309,14 +262,14 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
let mut val = stack.pop();
|
let mut val = stack.pop();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||||
stack.tos_mut().select(sym, vm)?;
|
stack.tos_mut().select(sym, vm)?;
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamicOrDefault => {
|
OpCode::SelectDynamicOrDefault => {
|
||||||
let default = stack.pop();
|
let default = stack.pop();
|
||||||
let mut val = stack.pop();
|
let mut val = stack.pop();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||||
stack.tos_mut().select_with_default(sym, default)?;
|
stack.tos_mut().select_with_default(sym, default)?;
|
||||||
}
|
}
|
||||||
OpCode::HasAttr { sym } => {
|
OpCode::HasAttr { sym } => {
|
||||||
@@ -325,25 +278,18 @@ fn single_op<'gc, const CAP: usize>(
|
|||||||
OpCode::HasDynamicAttr => {
|
OpCode::HasDynamicAttr => {
|
||||||
let mut val = stack.pop();
|
let mut val = stack.pop();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = vm.new_sym(val.unwrap_string().as_ref());
|
let sym = vm.new_sym::<&str>(&val.unwrap_string());
|
||||||
stack.tos_mut().has_attr(sym);
|
stack.tos_mut().has_attr(sym);
|
||||||
}
|
}
|
||||||
OpCode::LookUp { sym } => {
|
OpCode::LookUp { sym } => {
|
||||||
stack.push(
|
stack.push(
|
||||||
env.lookup_slow(&sym)
|
env.lookup_with(&sym)
|
||||||
.ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym))))?
|
.ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym))))?
|
||||||
.clone(),
|
.clone(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
OpCode::EnterLetEnv => {
|
OpCode::LookUpLet { level, idx } => {
|
||||||
let mut new = HashMap::new();
|
stack.push(env.lookup_let(level, idx))?;
|
||||||
stack
|
|
||||||
.pop()
|
|
||||||
.unwrap_attr_set()
|
|
||||||
.iter()
|
|
||||||
.map(|(&k, v)| (k, v.clone()))
|
|
||||||
.collect_into(&mut new);
|
|
||||||
*env = env.enter_let(Gc::new(mc, new), mc);
|
|
||||||
}
|
}
|
||||||
OpCode::LeaveEnv => *env = env.leave(),
|
OpCode::LeaveEnv => *env = env.leave(),
|
||||||
OpCode::EnterWithEnv => {
|
OpCode::EnterWithEnv => {
|
||||||
@@ -401,7 +347,7 @@ impl<'gc> VM<'gc> {
|
|||||||
self.symbols.borrow()[idx].clone().into()
|
self.symbols.borrow()[idx].clone().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_sym(&self, sym: impl Into<EcoString>) -> usize {
|
pub fn new_sym<T: Into<EcoString>>(&self, sym: T) -> usize {
|
||||||
let sym = sym.into();
|
let sym = sym.into();
|
||||||
if let Some(&idx) = self.symmap.borrow().get(&sym) {
|
if let Some(&idx) = self.symmap.borrow().get(&sym) {
|
||||||
idx
|
idx
|
||||||
@@ -420,7 +366,7 @@ impl<'gc> VM<'gc> {
|
|||||||
|
|
||||||
pub fn compile_func(&'gc self, func: &'gc F) -> JITFunc<'gc> {
|
pub fn compile_func(&'gc self, func: &'gc F) -> JITFunc<'gc> {
|
||||||
self.jit
|
self.jit
|
||||||
.compile_seq(func.opcodes.iter().copied(), self)
|
.compile_seq(func.opcodes.iter().copied().rev(), self)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use hashbrown::HashMap;
|
|||||||
use test::{Bencher, black_box};
|
use test::{Bencher, black_box};
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use rpds::vector_sync;
|
|
||||||
|
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
use crate::ir::downgrade;
|
use crate::ir::downgrade;
|
||||||
@@ -75,7 +74,7 @@ macro_rules! symbol {
|
|||||||
|
|
||||||
macro_rules! list {
|
macro_rules! list {
|
||||||
($($x:tt)*) => (
|
($($x:tt)*) => (
|
||||||
Value::List(List::new(vector_sync![$($x)*]))
|
Value::List(List::new(vec![$($x)*]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user