Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Merge API-only branch into main #4

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f088286
Moved actual collection to a configuration option.
mcoblenz Mar 10, 2021
921e937
Added Turtles prototype.
mcoblenz Mar 15, 2021
cf9e59b
Added breeding.
mcoblenz Mar 15, 2021
ceb2bc0
Attempt #1 to have children. I can't add any children because I can't…
mcoblenz Mar 15, 2021
606e655
Switched to Rc<Turtle> to allow aliasing, but still need to allow mut…
mcoblenz Mar 15, 2021
b61e3a3
Used Rc<RefCell<Turtle>> to manage children.
mcoblenz Mar 15, 2021
f96a7fc
Made prototype more consistent with the homework problem.
Mar 19, 2021
a3d8491
Extension to Turtles.
Mar 21, 2021
51a9277
Implemented improvements suggested by Michael Rosenberg.
Mar 21, 2021
3daeecc
Added metadata for crate publication.
Mar 25, 2021
5a55bad
Switched to the MIT license.
Mar 26, 2021
686ca4a
Added MPL license for the appropriate code, as required.
Mar 26, 2021
278c275
Added usage instructions to the readme.
Mar 26, 2021
2b07f41
Renaming in preparation for publishing the crate.
Mar 26, 2021
5174e55
Removed space from keywords.
Mar 26, 2021
7f04ca3
Fixed readme file path.
Mar 26, 2021
d54f130
Added documentation to include usage examples and recommend leveragin…
Apr 11, 2021
75a88a2
Fixed warning due to deprecated use of panic().
Jan 7, 2022
815054e
Added dynamic borrowing support to GcRef, re-using part of the standa…
Jan 13, 2022
7771e1a
Updated license file to acknowledge standard library code.
Jan 19, 2022
34c1538
Made as_ref and as_mut private. Removed Deref from GcRef.
Jan 20, 2022
b685288
Merge branch 'API-only' of github.com:mcoblenz/Bronze
Swapnilr1 May 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["bronze", "prototypes/city", "prototypes/city_gc", "prototypes/list_gc", "prototypes/draw_gc", "prototypes/tiny_gc", "bronze_derive"]
members = ["bronze_gc", "prototypes/city", "prototypes/city_gc", "prototypes/list_gc", "prototypes/draw_gc", "prototypes/tiny_gc", "prototypes/malloc", "prototypes/intcontainer", "bronze_derive"]
459 changes: 430 additions & 29 deletions LICENSE

Large diffs are not rendered by default.

15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn test() {
}
````

With Bronze, types that are not `Copy` can be freely referenced through smart pointers, which *are* `Copy`:
With Bronze, types that are not `Copy` can be referenced through smart pointers, which *are* `Copy`. Temporary immutable and immutable borrows can be obtained via `borrow()` and `borrow_mut`; these implement `Deref`, allowing convenient access.

````
//
Expand All @@ -38,7 +38,7 @@ pub struct IntContainer {
}

pub fn set(mut c: GcRef<IntContainer>, n: i32) {
c.n = n;
c.borrow_mut().n = n;
}

pub fn test() {
Expand All @@ -52,17 +52,14 @@ pub fn test() {
}
````

Because `GcRef` implements `Deref`, and because Rust automatically inserts `*` when needed, you can generally treat `GcRef<T>` as if it were a `T` directly. For example, in `set()` above, the body assigns to `c.n`. This implicitly means to dereference the pointer and assign to `n` inside the referenced value. If you like, you can instead call `as_ref()` and `as_mut()` to obtain a reference or mutable reference to the data in the GC heap.


To create a new `GcRef<T>`, call `GcRef::new(e)`, where `e` is an expression whose value you want to be on the GC heap.

## Advanced Usage
If you need to remove data from the GC heap, you can use a `GcNullableRef` rather than a `GcRef`. You can create one with `Gc::new_nullable`. `GcNullableRef` is like `GcRef` but adds a method `remove`. The first call to `remove` returns an `Option` populated with the data that was previously in the GC heap. Future calls to `remove` return None.

## Experimental Implementation
This implementation is *experimental*. The 'main' branch has a collector, but it only works in limited cases and is not general enough to work with YOUR code. The 'API-only' branch has the collector disabled; be aware that you will eventually run out of memory. However, the present version is suitable for experimentation and prototyping.
## Safety
An earlier version of Bronze allowed users to obtain multiple mutable references to a GC object. This should no longer be possible; instead, Bronze dynamically tracks borrows (using a very similar mechanism to that used in RefCell). To obtain an immutable or mutable borrowed reference to a GC object, call `borrow()` or `borrow_mut()` on the `GcRef`.

Contributors are welcome! The stack map code (which, again, works only for certain cases) is in a [fork of the Rust compiler](https://github.com/mcoblenz/rust). The current implementation assumes that all allocation of GC structures happens on a single thread; this is because of the specific stack map technique used in the compiler, which we selected for implementation simplicity. In particular, it uses the LLVM [shadow stack](https://llvm.org/docs/GarbageCollection.html#using-llvm-gcwrite). A practical version of Bronze would likely use a different stack map approach.

An important aspect of the experimental nature is that, for now, it is possible with Bronze to create multiple mutable references to the same data. Obviously, this is unsafe in Rust. For now, we assume that users will encapsulate their data structures appropriately and avoid this; in the future, we should explore enforcement mechanisms to make this safe in general. One approach might be akin to how RefCell keeps track of outstanding references.
## Experimental Implementation
This implementation is *experimental*. In particular, the collector will not run; be aware that you will eventually run out of memory. However, the present version is suitable for experimentation and prototyping.
60 changes: 0 additions & 60 deletions bronze/build.rs

This file was deleted.

Empty file removed bronze/src/trace.rs
Empty file.
7 changes: 4 additions & 3 deletions bronze_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
name = "bronze_derive"
version = "0.1.0"
authors = ["Michael Coblenz <[email protected]>"]

description = "Garbage collector derive plugin for rust-gc"
description = "Plugin for bronze_gc to derive Trace and Finalize traits."
repository = "https://github.com/mcoblenz/Bronze"
homepage = "http://www.cs.umd.edu/~mcoblenz/"
readme = "../README.md"
license = "MPL-2.0"
keywords = ["garbage", "macro", "memory"]
keywords = ["garbage", "collection", "gc"]
categories = ["memory-management"]
edition = "2018"

[lib]
Expand Down
18 changes: 9 additions & 9 deletions bronze_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ fn derive_trace(mut s: Structure<'_>) -> proc_macro2::TokenStream {
let trace_body = s.each(|bi| quote!(mark(#bi)));

let trace_impl = s.unsafe_bound_impl(
quote!(::bronze::GcTrace),
quote!(::bronze_gc::GcTrace),
quote! {
#[inline] unsafe fn trace(&self) {
#[allow(dead_code)]
#[inline]
unsafe fn mark<T: ::bronze::GcTrace + ?Sized>(it: &T) {
::bronze::GcTrace::trace(it);
unsafe fn mark<T: ::bronze_gc::GcTrace + ?Sized>(it: &T) {
::bronze_gc::GcTrace::trace(it);
}
match *self { #trace_body }
}
#[inline] fn finalize_glue(&self) {
#[allow(dead_code)]
#[inline]
fn mark<T: ::bronze::GcTrace + ?Sized>(it: &T) {
::bronze::GcTrace::finalize_glue(it);
fn mark<T: ::bronze_gc::GcTrace + ?Sized>(it: &T) {
::bronze_gc::GcTrace::finalize_glue(it);
}
match *self { #trace_body }
::bronze::Finalize::finalize(self);
::bronze_gc::Finalize::finalize(self);
}
},
);
Expand All @@ -45,8 +45,8 @@ fn derive_trace(mut s: Structure<'_>) -> proc_macro2::TokenStream {
quote!(::std::ops::Drop),
quote! {
fn drop(&mut self) {
// if ::bronze::finalizer_safe() {
::bronze::Finalize::finalize(self);
// if ::bronze_gc::finalizer_safe() {
::bronze_gc::Finalize::finalize(self);
// }
}
},
Expand All @@ -61,5 +61,5 @@ fn derive_trace(mut s: Structure<'_>) -> proc_macro2::TokenStream {
decl_derive!([Finalize] => derive_finalize);

fn derive_finalize(s: Structure<'_>) -> proc_macro2::TokenStream {
s.unbound_impl(quote!(::bronze::Finalize), quote!())
s.unbound_impl(quote!(::bronze_gc::Finalize), quote!())
}
13 changes: 11 additions & 2 deletions bronze/Cargo.toml → bronze_gc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
[package]
name = "bronze"
version = "0.1.0"
name = "bronze_gc"
version = "0.2.1"
authors = ["Michael Coblenz <[email protected]>"]
edition = "2018"
links = "libbronze"
license = "MIT"
description = "The Bronze garbage collector for Rust. This version only includes the API for creating and using GC references; it does not actually collect anything. For experimental purposes only."
homepage = "http://www.cs.umd.edu/~mcoblenz/"
repository = "https://github.com/mcoblenz/Bronze/"
keywords = ["garbage", "collection", "gc"]
categories = ["memory-management"]
readme = "../README.md"


# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
derive = ["bronze_derive"]
enable_garbage_collection = []

[dependencies]
multiset = "0.0.5"
Expand Down
58 changes: 58 additions & 0 deletions bronze_gc/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// See https://doc.rust-lang.org/cargo/reference/build-scripts.html for documentation.
// The main() function here is executed by the Rust build system before building the rest of the crate.

extern crate bindgen;

fn main() {
// Tell cargo to tell rustc to link the system bzip2
// shared library.
//println!("cargo:rustc-link-lib=bz2");

// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=wrapper/wrapper.h");

#[cfg(feature="enable_garbage_collection")]
{
// Tell cargo to link with the libbronze static library
println!("cargo:rustc-link-lib=static=bronze_gc");
let mut libbronze_dir = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
libbronze_dir.pop(); // get parent dir
libbronze_dir.push("libbronze");

let mut libbronze_build_dir = libbronze_dir.clone();
libbronze_build_dir.push("build");

let lib_path_str = libbronze_build_dir.as_path().to_str().expect("libbronze path must be a valid string");

println!("cargo:rustc-link-search=native={}", lib_path_str);

// Mark dependencies on libbronze.
let mut libbronze_path = libbronze_build_dir.clone();
libbronze_path.push("libbronze.a");
let libbronze_path_str = libbronze_path.to_str().expect("libbronze.a path must be a valid string");

println!("cargo:rerun-if-changed=wrapper/wrapper.h");
println!("cargo:rerun-if-changed={}", libbronze_path_str);

// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("wrapper/wrapper.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");

// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
}
Loading