Skip to content

Commit 4516ab9

Browse files
author
Alan Jeffrey
committed
Moved GC traits from mozjs crate to mozjs_sys
1 parent 39d3e78 commit 4516ab9

File tree

5 files changed

+264
-6
lines changed

5 files changed

+264
-6
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ libz-sys = "1.0"
3030
[build-dependencies]
3131
bindgen = "0.36"
3232
cc = "1.0"
33+
34+
[patch.crates-io]
35+
bindgen = { git = "https://github.com/emilio/rust-bindgen", branch = "per-module-lines" }

build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ fn build_jsapi_bindings() {
158158
builder = builder.blacklist_type(ty);
159159
}
160160

161+
for &(module, raw_line) in MODULE_RAW_LINES {
162+
builder = builder.module_raw_line(module, raw_line);
163+
}
164+
161165
let bindings = builder.generate()
162166
.expect("Should generate JSAPI bindings OK");
163167

@@ -421,3 +425,8 @@ const BLACKLIST_TYPES: &'static [&'static str] = &[
421425
// the definition of the struct to make our Drop implementation correct.
422426
"JS::Heap",
423427
];
428+
429+
/// Definitions for types that were blacklisted
430+
const MODULE_RAW_LINES: &'static [(&'static str, &'static str)] = &[
431+
("root::JS", "pub type Heap<T> = ::jsgc::Heap<T>;")
432+
];

src/jsgc.rs

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
use jsapi::JS;
6+
use jsapi::jsid;
7+
use jsapi::JSFlatString;
8+
use jsapi::JSFunction;
9+
use jsapi::JSID_VOID;
10+
use jsapi::JSObject;
11+
use jsapi::JSScript;
12+
use jsapi::JSString;
13+
14+
use std::cell::UnsafeCell;
15+
use std::mem;
16+
use std::ptr;
17+
18+
// Trait for rooting
19+
20+
pub trait RootKind {
21+
#[allow(non_snake_case)]
22+
#[inline(always)]
23+
fn rootKind() -> JS::RootKind;
24+
}
25+
26+
impl RootKind for *mut JSObject {
27+
#[inline(always)]
28+
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
29+
}
30+
31+
impl RootKind for *mut JSFlatString {
32+
#[inline(always)]
33+
fn rootKind() -> JS::RootKind { JS::RootKind::String }
34+
}
35+
36+
impl RootKind for *mut JSFunction {
37+
#[inline(always)]
38+
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
39+
}
40+
41+
impl RootKind for *mut JSString {
42+
#[inline(always)]
43+
fn rootKind() -> JS::RootKind { JS::RootKind::String }
44+
}
45+
46+
impl RootKind for *mut JS::Symbol {
47+
#[inline(always)]
48+
fn rootKind() -> JS::RootKind { JS::RootKind::Symbol }
49+
}
50+
51+
impl RootKind for *mut JSScript {
52+
#[inline(always)]
53+
fn rootKind() -> JS::RootKind { JS::RootKind::Script }
54+
}
55+
56+
impl RootKind for jsid {
57+
#[inline(always)]
58+
fn rootKind() -> JS::RootKind { JS::RootKind::Id }
59+
}
60+
61+
impl RootKind for JS::Value {
62+
#[inline(always)]
63+
fn rootKind() -> JS::RootKind { JS::RootKind::Value }
64+
}
65+
66+
impl RootKind for JS::PropertyDescriptor {
67+
#[inline(always)]
68+
fn rootKind() -> JS::RootKind { JS::RootKind::Traceable }
69+
}
70+
71+
// Trait for GC
72+
73+
pub trait GCMethods {
74+
unsafe fn initial() -> Self;
75+
unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self);
76+
}
77+
78+
impl GCMethods for jsid {
79+
unsafe fn initial() -> jsid { JSID_VOID }
80+
unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {}
81+
}
82+
83+
impl GCMethods for *mut JSObject {
84+
unsafe fn initial() -> *mut JSObject { ptr::null_mut() }
85+
unsafe fn post_barrier(v: *mut *mut JSObject,
86+
prev: *mut JSObject, next: *mut JSObject) {
87+
JS::HeapObjectPostBarrier(v, prev, next);
88+
}
89+
}
90+
91+
impl GCMethods for *mut JSString {
92+
unsafe fn initial() -> *mut JSString { ptr::null_mut() }
93+
unsafe fn post_barrier(_: *mut *mut JSString, _: *mut JSString, _: *mut JSString) {}
94+
}
95+
96+
impl GCMethods for *mut JSScript {
97+
unsafe fn initial() -> *mut JSScript { ptr::null_mut() }
98+
unsafe fn post_barrier(_: *mut *mut JSScript, _: *mut JSScript, _: *mut JSScript) { }
99+
}
100+
101+
impl GCMethods for *mut JSFunction {
102+
unsafe fn initial() -> *mut JSFunction { ptr::null_mut() }
103+
unsafe fn post_barrier(v: *mut *mut JSFunction,
104+
prev: *mut JSFunction, next: *mut JSFunction) {
105+
JS::HeapObjectPostBarrier(mem::transmute(v),
106+
mem::transmute(prev), mem::transmute(next));
107+
}
108+
}
109+
110+
impl GCMethods for JS::Value {
111+
unsafe fn initial() -> JS::Value { JS::Value::default() }
112+
unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
113+
JS::HeapValuePostBarrier(v, &prev, &next);
114+
}
115+
}
116+
117+
impl GCMethods for JS::PropertyDescriptor {
118+
unsafe fn initial() -> JS::PropertyDescriptor { JS::PropertyDescriptor::default() }
119+
unsafe fn post_barrier(_ : *mut JS::PropertyDescriptor, _ : JS::PropertyDescriptor, _ : JS::PropertyDescriptor) {}
120+
}
121+
122+
/// Heap values encapsulate GC concerns of an on-heap reference to a JS
123+
/// object. This means that every reference to a JS object on heap must
124+
/// be realized through this structure.
125+
///
126+
/// # Safety
127+
/// For garbage collection to work correctly in SpiderMonkey, modifying the
128+
/// wrapped value triggers a GC barrier, pointing to the underlying object.
129+
///
130+
/// This means that after calling the `set()` function with a non-null or
131+
/// non-undefined value, the `Heap` wrapper *must not* be moved, since doing
132+
/// so will invalidate the local reference to wrapped value, still held by
133+
/// SpiderMonkey.
134+
///
135+
/// For safe `Heap` construction with value see `Heap::boxed` function.
136+
#[repr(C)]
137+
#[derive(Debug)]
138+
pub struct Heap<T: GCMethods + Copy> {
139+
pub ptr: UnsafeCell<T>,
140+
}
141+
142+
impl<T: GCMethods + Copy> Heap<T> {
143+
/// This creates a `Box`-wrapped Heap value. Setting a value inside Heap
144+
/// object triggers a barrier, referring to the Heap object location,
145+
/// hence why it is not safe to construct a temporary Heap value, assign
146+
/// a non-null value and move it (e.g. typical object construction).
147+
///
148+
/// Using boxed Heap value guarantees that the underlying Heap value will
149+
/// not be moved when constructed.
150+
pub fn boxed(v: T) -> Box<Heap<T>>
151+
where Heap<T>: Default
152+
{
153+
let boxed = Box::new(Heap::default());
154+
boxed.set(v);
155+
boxed
156+
}
157+
158+
pub fn set(&self, v: T) {
159+
unsafe {
160+
let ptr = self.ptr.get();
161+
let prev = *ptr;
162+
*ptr = v;
163+
T::post_barrier(ptr, prev, v);
164+
}
165+
}
166+
167+
pub fn get(&self) -> T {
168+
unsafe { *self.ptr.get() }
169+
}
170+
171+
pub fn get_unsafe(&self) -> *mut T {
172+
self.ptr.get()
173+
}
174+
175+
pub fn handle_mut(&self) -> JS::MutableHandle<T> {
176+
unsafe {
177+
JS::MutableHandle::from_marked_location(self.ptr.get())
178+
}
179+
}
180+
/// Retrieves a Handle to the underlying value.
181+
///
182+
/// # Safety
183+
///
184+
/// This is only safe to do on a rooted object (which Heap is not, it needs
185+
/// to be additionally rooted), like RootedGuard, so use this only if you
186+
/// know what you're doing.
187+
///
188+
/// # Notes
189+
///
190+
/// Since Heap values need to be informed when a change to underlying
191+
/// value is made (e.g. via `get()`), this does not allow to create
192+
/// MutableHandle objects, which can bypass this and lead to crashes.
193+
pub unsafe fn handle(&self) -> JS::Handle<T> {
194+
JS::Handle::from_marked_location(self.ptr.get() as *const _)
195+
}
196+
}
197+
198+
impl<T> Default for Heap<*mut T>
199+
where *mut T: GCMethods + Copy
200+
{
201+
fn default() -> Heap<*mut T> {
202+
Heap {
203+
ptr: UnsafeCell::new(ptr::null_mut())
204+
}
205+
}
206+
}
207+
208+
impl Default for Heap<JS::Value> {
209+
fn default() -> Heap<JS::Value> {
210+
Heap {
211+
ptr: UnsafeCell::new(JS::Value::default())
212+
}
213+
}
214+
}
215+
216+
impl<T: GCMethods + Copy> Drop for Heap<T> {
217+
fn drop(&mut self) {
218+
unsafe {
219+
let ptr = self.ptr.get();
220+
T::post_barrier(ptr, *ptr, T::initial());
221+
}
222+
}
223+
}
224+
225+
impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> {
226+
fn eq(&self, other: &Self) -> bool {
227+
self.get() == other.get()
228+
}
229+
}

src/jsglue.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,30 @@ use jsapi::JS_LeaveCompartment;
1515
use jsapi::glue::JS_NewCompartmentOptions;
1616
use jsapi::JSID_VOID;
1717
use jsapi::jsid;
18-
use rooting;
18+
use jsgc::RootKind;
19+
use jsval::UndefinedValue;
1920

20-
impl<T> ::std::ops::Deref for JS::Handle<T> {
21+
use std::ops::Deref;
22+
use std::ops::DerefMut;
23+
use std::ptr;
24+
25+
impl<T> Deref for JS::Handle<T> {
2126
type Target = T;
2227

2328
fn deref<'a>(&'a self) -> &'a T {
2429
unsafe { &*self.ptr }
2530
}
2631
}
2732

28-
impl<T> ::std::ops::Deref for JS::MutableHandle<T> {
33+
impl<T> Deref for JS::MutableHandle<T> {
2934
type Target = T;
3035

3136
fn deref<'a>(&'a self) -> &'a T {
3237
unsafe { &*self.ptr }
3338
}
3439
}
3540

36-
impl<T> ::std::ops::DerefMut for JS::MutableHandle<T> {
41+
impl<T> DerefMut for JS::MutableHandle<T> {
3742
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
3843
unsafe { &mut *self.ptr }
3944
}
@@ -49,6 +54,18 @@ impl Default for JS::CompartmentOptions {
4954
}
5055
}
5156

57+
impl Default for JS::PropertyDescriptor {
58+
fn default() -> Self {
59+
JS::PropertyDescriptor {
60+
obj: ptr::null_mut(),
61+
attrs: 0,
62+
getter: None,
63+
setter: None,
64+
value: UndefinedValue()
65+
}
66+
}
67+
}
68+
5269
impl Drop for JSAutoCompartment {
5370
fn drop(&mut self) {
5471
unsafe { JS_LeaveCompartment(self.cx_, self.oldCompartment_); }
@@ -258,7 +275,7 @@ impl<T> JS::Rooted<T> {
258275
}
259276
}
260277

261-
pub unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) where T: rooting::RootKind {
278+
pub unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) where T: RootKind {
262279
let ctxfriend = cx as *mut js::ContextFriendFields;
263280
let zone = (*ctxfriend).zone_;
264281
let roots: *mut _ = if !zone.is_null() {

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod generated { include!(concat!(env!("OUT_DIR"), "/jsapi.rs")); }
88
mod jsglue;
99

1010
// Modules with public definitions
11-
pub mod rooting;
11+
pub mod jsgc;
1212
pub mod jsval;
1313

1414
// Reexport the bindings in the jsapi module

0 commit comments

Comments
 (0)