Update GetAttr: use Arc<String> instead of String

This lets us share strings more easily. It needs to be Arc (as opposed
to Rc) because these are stored inside of UserFun objects, which need to
be Send (for some reason).

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2023-04-07 01:17:22 -07:00
parent fcef6c053d
commit c450e07e08
3 changed files with 28 additions and 22 deletions

View File

@@ -1,4 +1,5 @@
use std::collections::VecDeque; use std::collections::{HashMap, VecDeque};
use std::sync::Arc;
use crate::compile::{scope::GlobalScope, thunk::Thunk}; use crate::compile::{scope::GlobalScope, thunk::Thunk};
use crate::obj::prelude::*; use crate::obj::prelude::*;
@@ -8,12 +9,24 @@ use crate::vm::inst::*;
pub struct Compiler { pub struct Compiler {
scope: GlobalScope, scope: GlobalScope,
attr_names: HashMap<String, Arc<String>>,
} }
impl Compiler { impl Compiler {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
scope: Default::default(), scope: Default::default(),
attr_names: Default::default(),
}
}
fn intern_attr(&mut self, name: &str) -> Arc<String> {
if let Some(name) = self.attr_names.get(name) {
Arc::clone(name)
} else {
let name = Arc::new(name.to_string());
self.attr_names.insert(name.to_string(), Arc::clone(&name));
name
} }
} }
@@ -151,7 +164,7 @@ impl Compiler {
} }
Expr::Get(expr, name) => { Expr::Get(expr, name) => {
let mut thunk = self.emit_expr(expr); let mut thunk = self.emit_expr(expr);
thunk.push_back(Inst::GetAttr(name.clone())); thunk.push_back(Inst::GetAttr(self.intern_attr(name)));
thunk thunk
} }
Expr::Atom(atom) => self.emit_atom(atom), Expr::Atom(atom) => self.emit_atom(atom),

View File

@@ -1,6 +1,8 @@
use crate::obj::ObjPtr; use crate::obj::ObjPtr;
use crate::vm::name::Name; use crate::vm::name::Name;
use std::sync::Arc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum JumpCondition { pub enum JumpCondition {
False, False,
@@ -20,7 +22,7 @@ pub enum Inst {
Store(Name), Store(Name),
/// Get an attribute from the top item of the stack. /// Get an attribute from the top item of the stack.
GetAttr(String), GetAttr(Arc<String>),
/// Pops the top item off of the stack, discarding it. /// Pops the top item off of the stack, discarding it.
Pop, Pop,
@@ -58,7 +60,7 @@ impl Inst {
Inst::Push(ptr) => format!("push <{:#x}>", (ptr as *const _ as usize)), Inst::Push(ptr) => format!("push <{:#x}>", (ptr as *const _ as usize)),
Inst::Load(name) => format!("load {name:?}"), Inst::Load(name) => format!("load {name:?}"),
Inst::Store(name) => format!("store {name:?}"), Inst::Store(name) => format!("store {name:?}"),
Inst::GetAttr(attr) => format!("getattr {attr}"), Inst::GetAttr(name) => format!("getattr {name}"),
Inst::Pop => format!("pop"), Inst::Pop => format!("pop"),
Inst::Call(argc) => format!("call {argc}"), Inst::Call(argc) => format!("call {argc}"),
Inst::Return => format!("return"), Inst::Return => format!("return"),

View File

@@ -163,29 +163,20 @@ impl Vm {
let value = self.pop_stack().expect("Stack underflow"); let value = self.pop_stack().expect("Stack underflow");
self.store(name, Some(value)); self.store(name, Some(value));
} }
Inst::GetAttr(attr) => { Inst::GetAttr(name) => {
// XXX let name = std::sync::Arc::clone(name);
// there's an annoying thing with this. We can't use
// self.pop_stack() and then use "attr" afterwards because they
// belong to the same owner (self).
// ALSO:
// We can't just do peek_stack() either, because since `attr`
// above was borrowed while `self` is mutable. If you want to
// borrow `self` immutably, you have to drop the reference above
// as well.
// So either we have to do some unsafe stuff (not a bad option
// here, since nothing is going to move) or clone(). Maybe a
// `get_attr()` function is in order, I don't know.
// For now we're cloning.
let attr = attr.clone();
let obj = self let obj = self
.pop_stack() .pop_stack()
.expect("Inst::GetAttr executed, but there was no value on top of the stack."); .expect("Inst::GetAttr, but there was no value on top of the stack.");
let value = obj.get(&attr); let value = obj.get(&name);
if let Some(value) = value { if let Some(value) = value {
self.push_stack(value); self.push_stack(value);
} else { } else {
todo!("Throw exception: Could not get attr {attr:?} on object {obj:?}"); todo!(
"Throw exception: GetAttr object {:?} did not have attribute {}",
obj,
name,
);
} }
} }
Inst::Pop => { Inst::Pop => {