diff options
Diffstat (limited to 'js/rust/src/heap.rs')
-rw-r--r-- | js/rust/src/heap.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/js/rust/src/heap.rs b/js/rust/src/heap.rs new file mode 100644 index 0000000000..7c39feaf27 --- /dev/null +++ b/js/rust/src/heap.rs @@ -0,0 +1,179 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use glue; +use jsapi::root::*; +use rust::GCMethods; +use std::cell::UnsafeCell; +use std::ptr; + +/// Types that can be traced. +/// +/// This trait is unsafe; if it is implemented incorrectly, the GC may end up +/// collecting objects that are still reachable. +pub unsafe trait Trace { + unsafe fn trace(&self, trc: *mut JSTracer); +} + +/** + * The Heap<T> class is a heap-stored reference to a JS GC thing. All members of + * heap classes that refer to GC things should use Heap<T> (or possibly + * TenuredHeap<T>, described below). + * + * Heap<T> is an abstraction that hides some of the complexity required to + * maintain GC invariants for the contained reference. It uses operator + * overloading to provide a normal pointer interface, but notifies the GC every + * time the value it contains is updated. This is necessary for generational GC, + * which keeps track of all pointers into the nursery. + * + * Heap<T> instances must be traced when their containing object is traced to + * keep the pointed-to GC thing alive. + * + * Heap<T> objects should only be used on the heap. GC references stored on the + * C/C++ stack must use Rooted/Handle/MutableHandle instead. + * + * Type T must be a public GC pointer type. + * + * Note that the rust version of Heap<T> implements different barriers to the + * C++ version, which also provides features to help integration with + * cycle-collected C++ objects. That version has a read barrier which performs + * gray unmarking and also marks the contents during an incremental GC. This + * version has a pre-write barrier instead, and this enforces the + * snapshot-at-the-beginning invariant which is necessary for incremental GC in + * the absence of the read barrier. + */ +#[repr(C)] +#[derive(Debug)] +pub struct Heap<T: GCMethods + Copy> { + ptr: UnsafeCell<T>, +} + +impl<T: GCMethods + Copy> Heap<T> { + pub fn new(v: T) -> Heap<T> + where + Heap<T>: Default, + { + let ptr = Heap::default(); + ptr.set(v); + ptr + } + + pub fn set(&self, v: T) { + unsafe { + let ptr = self.ptr.get(); + let prev = *ptr; + *ptr = v; + T::write_barriers(ptr, prev, v); + } + } + + pub fn get(&self) -> T { + unsafe { *self.ptr.get() } + } + + pub unsafe fn get_unsafe(&self) -> *mut T { + self.ptr.get() + } + + pub fn handle(&self) -> JS::Handle<T> { + unsafe { JS::Handle::from_marked_location(self.ptr.get() as *const _) } + } + + pub fn handle_mut(&self) -> JS::MutableHandle<T> { + unsafe { JS::MutableHandle::from_marked_location(self.ptr.get()) } + } +} + +impl<T: GCMethods + Copy> Clone for Heap<T> +where + Heap<T>: Default, +{ + fn clone(&self) -> Self { + Heap::new(self.get()) + } +} + +impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + +impl<T> Default for Heap<*mut T> +where + *mut T: GCMethods + Copy, +{ + fn default() -> Heap<*mut T> { + Heap { + ptr: UnsafeCell::new(ptr::null_mut()), + } + } +} + +impl Default for Heap<JS::Value> { + fn default() -> Heap<JS::Value> { + Heap { + ptr: UnsafeCell::new(JS::Value::default()), + } + } +} + +impl<T: GCMethods + Copy> Drop for Heap<T> { + fn drop(&mut self) { + unsafe { + let prev = self.ptr.get(); + T::write_barriers(prev, *prev, T::initial()); + } + } +} + +// Creates a C string literal `$str`. +macro_rules! c_str { + ($str:expr) => { + concat!($str, "\0").as_ptr() as *const ::std::os::raw::c_char + }; +} + +unsafe impl Trace for Heap<*mut JSFunction> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallFunctionTracer(trc, self as *const _ as *mut Self, c_str!("function")); + } +} + +unsafe impl Trace for Heap<*mut JSObject> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallObjectTracer(trc, self as *const _ as *mut Self, c_str!("object")); + } +} + +unsafe impl Trace for Heap<*mut JSScript> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallScriptTracer(trc, self as *const _ as *mut Self, c_str!("script")); + } +} + +unsafe impl Trace for Heap<*mut JSString> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallStringTracer(trc, self as *const _ as *mut Self, c_str!("string")); + } +} + +#[cfg(feature = "bigint")] +unsafe impl Trace for Heap<*mut JS::BigInt> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallBigIntTracer(trc, self as *const _ as *mut Self, c_str!("bigint")); + } +} + +unsafe impl Trace for Heap<JS::Value> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallValueTracer(trc, self as *const _ as *mut Self, c_str!("value")); + } +} + +unsafe impl Trace for Heap<jsid> { + unsafe fn trace(&self, trc: *mut JSTracer) { + glue::CallIdTracer(trc, self as *const _ as *mut Self, c_str!("id")); + } +} |