From e66cd52861b032fa38c86d54dbd08cbd47a3f209 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 30 Dec 2021 17:59:48 +0100 Subject: [PATCH] start with gc --- src/value.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/value.rs b/src/value.rs index f716e9a..797e3f7 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,9 +1,91 @@ +use std::collections::LinkedList; +use std::fmt::{Debug, Formatter}; +use std::ops::Deref; +use std::ptr::NonNull; + /// imagine interning or something here pub type Symbol = String; +/// here is the actual interning or something +pub type NewSym = Gc; + #[cfg(not(feature = "fxhash"))] #[allow(clippy::disallowed_type)] pub type HashMap = std::collections::HashMap; #[cfg(feature = "fxhash")] pub type HashMap = rustc_hash::FxHashMap; + +#[cfg(not(feature = "fxhash"))] +#[allow(clippy::disallowed_type)] +pub type HashSet = std::collections::HashSet; + +#[cfg(feature = "fxhash")] +pub type HashSet = rustc_hash::FxHashSet; + +/// A pointer to a garbage collected value. This pointer *must* always be valid, and a value +/// is only allowed to be freed once no Gc is pointing at it anymore. This is achieved through +/// tracing through all objects from a few known roots and marking every reachable value. All other +/// values will be swept. +pub struct Gc { + ptr: NonNull, +} + +impl Deref for Gc { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: Gc will always point to a valid T, since T will only be freed once all Gc are gone + // This requires tracing through *all* roots without forgetting any + // I would guess that there will be some errors with the garbage collector, but once they are + // all fixed this will be sound. But who knows. + unsafe { &*self.ptr.as_ptr() } + } +} + +impl Debug for Gc { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + T::fmt(self, f) + } +} + +impl Clone for Gc { + fn clone(&self) -> Self { + Self { ..*self } + } +} + +impl Copy for Gc {} + +enum Object { + String(Gc), +} + +pub struct RtAlloc { + symbols: HashSet>, + objects: LinkedList, +} + +impl RtAlloc { + pub fn alloc_str(&mut self, str: &str) -> Gc { + let ptr = Box::into_raw(str.to_owned().into_boxed_str()); + // SAFETY: Box cannot be null + let new_nonnull = unsafe { NonNull::new_unchecked(ptr) }; + let gc = Gc { ptr: new_nonnull }; + let object = Object::String(gc.clone()); + + self.objects.push_back(object); + + gc + } + + pub fn intern_string(&mut self, str: &str) -> NewSym { + let original_nonnull = NonNull::from(str); + + if let Some(interned) = self.symbols.get(&original_nonnull) { + return Gc { ptr: *interned }; + } + + self.alloc_str(str) + } +}