From 1b50778271f4537514fcb02c0a12e36262d71070 Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Sun, 1 Mar 2020 21:15:16 +0100 Subject: [PATCH] Implement variable capture We just copy the variables into the closure environment after it gets allocated. This involves a decent chunk of stack traffic because we have to increment their reference counts. In the process, I figured out that the "ivy_app_mut" optimization for later functions isn't sound in the presence of nested functions, because one of the earlier applications can return a shared function which isn't acceptable to mutate. (There are ways to make it sound if you know for sure what functions are being called). --- ivy-examples/break.vy | 5 +++++ ivy-examples/minimal-captures.vy | 1 + program.vy => ivy-examples/program.vy | 0 sixty-four.vy => ivy-examples/sixty-four.vy | 6 +++--- src/trans/x64.rs | 23 +++++++++++++-------- 5 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 ivy-examples/break.vy create mode 100644 ivy-examples/minimal-captures.vy rename program.vy => ivy-examples/program.vy (100%) rename sixty-four.vy => ivy-examples/sixty-four.vy (50%) diff --git a/ivy-examples/break.vy b/ivy-examples/break.vy new file mode 100644 index 0000000..0353a36 --- /dev/null +++ b/ivy-examples/break.vy @@ -0,0 +1,5 @@ +(let ( + [base (lam (y) (debug y))] + [f (lam (x) base)] + [use (f 0 0)] +) (f use use)) diff --git a/ivy-examples/minimal-captures.vy b/ivy-examples/minimal-captures.vy new file mode 100644 index 0000000..f34202b --- /dev/null +++ b/ivy-examples/minimal-captures.vy @@ -0,0 +1 @@ +((lam (x) (lam (y) (x y))) debug 0) diff --git a/program.vy b/ivy-examples/program.vy similarity index 100% rename from program.vy rename to ivy-examples/program.vy diff --git a/sixty-four.vy b/ivy-examples/sixty-four.vy similarity index 50% rename from sixty-four.vy rename to ivy-examples/sixty-four.vy index d17d061..78e88eb 100644 --- a/sixty-four.vy +++ b/ivy-examples/sixty-four.vy @@ -1,8 +1,8 @@ (let ( [zero (lam (f x) x)] - [succ (lam (n f x) (f (n f x)))] - [add (lam (m n f x) (m f (n f x)))] - [mul (lam (m n f x) (m (n f) x))] + [succ (lam (n) (lam (f x) (f (n f x))))] + [add (lam (m n) (lam (f x) (m f (n f x))))] + [mul (lam (m n) (lam (f x) (m (n f) x)))] [two (succ (succ zero))] [four (add two two)] [_64 (mul (mul four four) four)] diff --git a/src/trans/x64.rs b/src/trans/x64.rs index 6d3c921..3a07c77 100644 --- a/src/trans/x64.rs +++ b/src/trans/x64.rs @@ -207,11 +207,9 @@ fn compile_func(func: &Func) -> Definition { Var::Upvar(x) => upvar(x), Var::Ssa(s) => stack(&s), }; - let load = |s| { - match func.block[s] { - Code::Load(v) => address(v), - _ => stack(s), - } + let load = |s| match func.block[s] { + Code::Load(v) => address(v), + _ => stack(s), }; for ssa in &func.order { match &func.block[ssa] { @@ -230,9 +228,16 @@ fn compile_func(func: &Func) -> Definition { body.push(Inst::Imm(Reg::Rsi, *params as i64)); body.push(Inst::Imm(Reg::Rdx, upvars.len() as i64)); body.push(Inst::Call(extern_label!("ivy_make_lam"))); - // @TODO: Implement copying in closure captures - assert!(upvars.is_empty()); body.push(Inst::Store(stack(ssa), Reg::Rax)); + for (i, s) in upvars.iter().enumerate() { + body.push(Inst::Load(Reg::Rdi, load(s))); + body.push(Inst::Store( + Addr::Off(Reg::Rax, HEADER_SIZE + (*params as i32) * 8 + i as i32 * 8), + Reg::Rdi, + )); + body.push(Inst::Call(extern_label!("ivy_incref"))); + body.push(Inst::Load(Reg::Rax, stack(ssa))); + } } Code::App(terms) => { let mut terms = terms.iter(); @@ -248,7 +253,7 @@ fn compile_func(func: &Func) -> Definition { while let Some(term) = terms.next() { body.push(Inst::Mov(Reg::Rdi, Reg::Rax)); body.push(Inst::Load(Reg::Rsi, load(term))); - body.push(Inst::Call(extern_label!("ivy_app_mut"))); + body.push(Inst::Call(extern_label!("ivy_app"))); } body.push(Inst::Store(stack(ssa), Reg::Rax)); } @@ -330,7 +335,7 @@ impl fmt::Display for Addr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Addr::Rip(l) => write!(fmt, "[rip + {}]", l), - Addr::Off(r, o) => write!(fmt, "[{} + {}]", r, o), + Addr::Off(r, o) => write!(fmt, "[{} + 0x{:02x}]", r, o), } } } -- 2.47.0