Skip to content
This repository was archived by the owner on Nov 12, 2022. It is now read-only.

Commit 71333b8

Browse files
committed
Move from using return_address to a macro-mediated rooting solution.
1 parent 4627586 commit 71333b8

File tree

7 files changed

+132
-56
lines changed

7 files changed

+132
-56
lines changed

src/conversions.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use jsapi::JSPROP_ENUMERATE;
3333
use jsapi::{JSContext, JSObject, JSString, HandleValue, MutableHandleValue};
3434
use jsapi::{JS_NewUCStringCopyN, JS_StringHasLatin1Chars, JS_WrapValue};
3535
use jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength};
36-
use jsapi::{JS_NewArrayObject1, JS_DefineElement, RootedValue, RootedObject};
36+
use jsapi::{JS_NewArrayObject1, JS_DefineElement, RootedObject};
3737
use jsapi::{ForOfIterator, ForOfIterator_NonIterableBehavior};
3838
use jsval::{BooleanValue, Int32Value, NullValue, UInt32Value, UndefinedValue};
3939
use jsval::{JSVal, ObjectValue, ObjectOrNullValue, StringValue};
@@ -473,10 +473,10 @@ impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
473473
// https://heycam.github.io/webidl/#es-sequence
474474
impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
475475
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
476-
let js_array = RootedObject::new(cx, JS_NewArrayObject1(cx, self.len() as libc::size_t));
476+
rooted!(in(cx) let js_array = JS_NewArrayObject1(cx, self.len() as libc::size_t));
477477
assert!(!js_array.handle().is_null());
478478

479-
let mut val = RootedValue::new(cx, UndefinedValue());
479+
rooted!(in(cx) let mut val = UndefinedValue());
480480
for (index, obj) in self.iter().enumerate() {
481481
obj.to_jsval(cx, val.handle_mut());
482482

@@ -488,6 +488,33 @@ impl<T: ToJSValConvertible> ToJSValConvertible for Vec<T> {
488488
}
489489
}
490490

491+
/// Rooting guard for the iterator field of ForOfIterator.
492+
/// Behaves like RootedGuard (roots on creation, unroots on drop),
493+
/// but borrows and allows access to the whole ForOfIterator, so
494+
/// that methods on ForOfIterator can still be used through it.
495+
struct ForOfIteratorGuard<'a> {
496+
root: &'a mut ForOfIterator
497+
}
498+
499+
impl<'a> ForOfIteratorGuard<'a> {
500+
fn new(cx: *mut JSContext, root: &'a mut ForOfIterator) -> Self {
501+
unsafe {
502+
root.iterator.add_to_root_stack(cx);
503+
}
504+
ForOfIteratorGuard {
505+
root: root
506+
}
507+
}
508+
}
509+
510+
impl<'a> Drop for ForOfIteratorGuard<'a> {
511+
fn drop(&mut self) {
512+
unsafe {
513+
self.root.iterator.remove_from_root_stack();
514+
}
515+
}
516+
}
517+
491518
impl<C: Clone, T: FromJSValConvertible<Config=C>> FromJSValConvertible for Vec<T> {
492519
type Config = C;
493520

@@ -497,9 +524,11 @@ impl<C: Clone, T: FromJSValConvertible<Config=C>> FromJSValConvertible for Vec<T
497524
-> Result<Vec<T>, ()> {
498525
let mut iterator = ForOfIterator {
499526
cx_: cx,
500-
iterator: RootedObject::new(cx, ptr::null_mut()),
527+
iterator: RootedObject::new_unrooted(ptr::null_mut()),
501528
index: ::std::u32::MAX, // NOT_ARRAY
502529
};
530+
let mut iterator = ForOfIteratorGuard::new(cx, &mut iterator);
531+
let iterator = &mut *iterator.root;
503532

504533
if !iterator.init(value, ForOfIterator_NonIterableBehavior::ThrowOnNonIterable) {
505534
return Err(())
@@ -509,7 +538,7 @@ impl<C: Clone, T: FromJSValConvertible<Config=C>> FromJSValConvertible for Vec<T
509538

510539
loop {
511540
let mut done = false;
512-
let mut val = RootedValue::new(cx, UndefinedValue());
541+
rooted!(in(cx) let mut val = UndefinedValue());
513542
if !iterator.next(val.handle_mut(), &mut done) {
514543
return Err(())
515544
}

src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#![crate_name = "js"]
66
#![crate_type = "rlib"]
77

8-
#![feature(core_intrinsics)]
98
#![feature(filling_drop)]
109
#![feature(link_args)]
1110
#![feature(unsafe_no_drop_flag)]
@@ -78,12 +77,15 @@ pub mod jsapi {
7877
include!("jsapi_linux_32_debug.rs");
7978
}
8079

80+
#[macro_use]
81+
pub mod rust;
82+
8183
mod consts;
8284
pub mod conversions;
8385
pub mod error;
8486
pub mod glue;
8587
pub mod jsval;
86-
pub mod rust;
88+
8789

8890
pub use consts::*;
8991

src/rust.rs

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use std::slice;
1313
use std::mem;
1414
use std::u32;
1515
use std::default::Default;
16-
use std::intrinsics::return_address;
1716
use std::ops::{Deref, DerefMut};
1817
use std::cell::UnsafeCell;
1918
use std::marker::PhantomData;
@@ -269,39 +268,101 @@ impl RootKind for Value {
269268
fn rootKind() -> jsapi::RootKind { jsapi::RootKind::Value }
270269
}
271270

272-
impl<T: RootKind + Copy> Rooted<T> {
273-
pub fn new_with_addr(cx: *mut JSContext, initial: T, addr: *const u8) -> Rooted<T> {
274-
let ctxfriend: &mut ContextFriendFields = unsafe {
275-
mem::transmute(cx)
276-
};
277-
278-
let kind = T::rootKind() as usize;
279-
let root = Rooted::<T> {
271+
impl<T> Rooted<T> {
272+
pub fn new_unrooted(initial: T) -> Rooted<T> {
273+
Rooted {
280274
_base: RootedBase { _phantom0: PhantomData },
281-
stack: &mut ctxfriend.roots.stackRoots_[kind] as *mut _ as *mut _,
282-
prev: ctxfriend.roots.stackRoots_[kind] as *mut _,
275+
stack: ptr::null_mut(),
276+
prev: ptr::null_mut(),
283277
ptr: initial,
284-
};
278+
}
279+
}
285280

286-
ctxfriend.roots.stackRoots_[kind] = unsafe { mem::transmute(addr) };
287-
root
281+
pub unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) where T: RootKind {
282+
let ctxfriend: &mut ContextFriendFields = mem::transmute(cx);
283+
284+
let kind = T::rootKind() as usize;
285+
self.stack = &mut ctxfriend.roots.stackRoots_[kind] as *mut _ as *mut _;
286+
self.prev = ctxfriend.roots.stackRoots_[kind] as *mut _;
287+
288+
ctxfriend.roots.stackRoots_[kind] = self as *mut _ as usize as _;
288289
}
289290

290-
pub fn new(cx: *mut JSContext, initial: T) -> Rooted<T> {
291-
Rooted::new_with_addr(cx, initial, unsafe { return_address() })
291+
pub unsafe fn remove_from_root_stack(&mut self) {
292+
assert!(*self.stack == mem::transmute(&*self));
293+
*self.stack = self.prev;
292294
}
295+
}
293296

294-
pub fn handle(&self) -> Handle<T> {
297+
/// Rust API for keeping a Rooted value in the context's root stack.
298+
/// Example usage: `rooted!(in(cx) let x = UndefinedValue());`.
299+
/// `RootedGuard::new` also works, but the macro is preferred.
300+
pub struct RootedGuard<'a, T: 'a> {
301+
root: &'a mut Rooted<T>
302+
}
303+
304+
impl<'a, T> RootedGuard<'a, T> {
305+
pub fn new(cx: *mut JSContext, root: &'a mut Rooted<T>) -> Self where T: RootKind {
306+
unsafe {
307+
root.add_to_root_stack(cx);
308+
}
309+
RootedGuard {
310+
root: root
311+
}
312+
}
313+
314+
pub fn handle(&self) -> Handle<T> where T: Copy {
295315
unsafe {
296-
Handle::from_marked_location(&self.ptr)
316+
Handle::from_marked_location(&self.root.ptr)
297317
}
298318
}
299319

300-
pub fn handle_mut(&mut self) -> MutableHandle<T> {
320+
pub fn handle_mut(&mut self) -> MutableHandle<T> where T: Copy {
301321
unsafe {
302-
MutableHandle::from_marked_location(&mut self.ptr)
322+
MutableHandle::from_marked_location(&mut self.root.ptr)
303323
}
304324
}
325+
326+
pub fn get(&self) -> T where T: Copy {
327+
self.root.ptr
328+
}
329+
330+
pub fn set(&mut self, v: T) {
331+
self.root.ptr = v;
332+
}
333+
}
334+
335+
impl<'a, T> Deref for RootedGuard<'a, T> {
336+
type Target = T;
337+
fn deref(&self) -> &T {
338+
&self.root.ptr
339+
}
340+
}
341+
342+
impl<'a, T> DerefMut for RootedGuard<'a, T> {
343+
fn deref_mut(&mut self) -> &mut T {
344+
&mut self.root.ptr
345+
}
346+
}
347+
348+
impl<'a, T> Drop for RootedGuard<'a, T> {
349+
fn drop(&mut self) {
350+
unsafe {
351+
self.root.remove_from_root_stack();
352+
}
353+
}
354+
}
355+
356+
#[macro_export]
357+
macro_rules! rooted {
358+
(in($cx:expr) let $name:ident = $init:expr) => {
359+
let mut __root = $crate::jsapi::Rooted::new_unrooted($init);
360+
let $name = $crate::rust::RootedGuard::new($cx, &mut __root);
361+
};
362+
(in($cx:expr) let mut $name:ident = $init:expr) => {
363+
let mut __root = $crate::jsapi::Rooted::new_unrooted($init);
364+
let mut $name = $crate::rust::RootedGuard::new($cx, &mut __root);
365+
}
305366
}
306367

307368
impl<T: Copy> Handle<T> {
@@ -390,18 +451,6 @@ impl<T: Copy> MutableHandle<T> {
390451
}
391452
}
392453

393-
impl<T> Drop for Rooted<T> {
394-
fn drop(&mut self) {
395-
unsafe {
396-
if self.stack as usize == mem::POST_DROP_USIZE {
397-
return;
398-
}
399-
assert!(*self.stack == mem::transmute(&*self));
400-
*self.stack = self.prev;
401-
}
402-
}
403-
}
404-
405454
impl Default for jsid {
406455
fn default() -> jsid { JSID_VOID }
407456
}

tests/callback.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
33
* You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
#[macro_use]
56
extern crate js;
67
extern crate libc;
78

@@ -14,8 +15,6 @@ use js::jsapi::JS_EncodeStringToUTF8;
1415
use js::jsapi::JS_NewGlobalObject;
1516
use js::jsapi::JS_ReportError;
1617
use js::jsapi::OnNewGlobalHookOption;
17-
use js::jsapi::Rooted;
18-
use js::jsapi::RootedValue;
1918
use js::jsapi::Value;
2019
use js::jsval::UndefinedValue;
2120
use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
@@ -33,14 +32,14 @@ fn callback() {
3332

3433
unsafe {
3534
let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(), h_option, &c_option);
36-
let global_root = Rooted::new(context, global);
35+
rooted!(in(context) let global_root = global);
3736
let global = global_root.handle();
3837
let _ac = JSAutoCompartment::new(context, global.get());
3938
let function = JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char,
4039
Some(puts), 1, 0);
4140
assert!(!function.is_null());
4241
let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');";
43-
let mut rval = RootedValue::new(runtime.cx(), UndefinedValue());
42+
rooted!(in(context) let mut rval = UndefinedValue());
4443
let _ = runtime.evaluate_script(global, javascript, "test.js", 0, rval.handle_mut());
4544
}
4645
}
@@ -55,7 +54,7 @@ unsafe extern "C" fn puts(context: *mut JSContext, argc: u32, vp: *mut Value) ->
5554

5655
let arg = args.get(0);
5756
let js = js::rust::ToString(context, arg);
58-
let message_root = Rooted::new(context, js);
57+
rooted!(in(context) let message_root = js);
5958
let message = JS_EncodeStringToUTF8(context, message_root.handle());
6059
let message = CStr::from_ptr(message);
6160
println!("{}", str::from_utf8(message.to_bytes()).unwrap());

tests/evaluate.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
#[macro_use]
56
extern crate js;
67

78
use js::jsapi::CompartmentOptions;
89
use js::jsapi::JS_NewGlobalObject;
910
use js::jsapi::OnNewGlobalHookOption;
10-
use js::jsapi::RootedObject;
11-
use js::jsapi::RootedValue;
1211
use js::jsval::UndefinedValue;
1312
use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
1413

@@ -21,12 +20,12 @@ fn evaluate() {
2120

2221
unsafe {
2322

24-
let global = RootedObject::new(cx,
23+
rooted!(in(cx) let global =
2524
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
2625
OnNewGlobalHookOption::FireOnNewGlobalHook,
2726
&CompartmentOptions::default())
2827
);
29-
let mut rval = RootedValue::new(cx, UndefinedValue());
28+
rooted!(in(cx) let mut rval = UndefinedValue());
3029
assert!(rt.evaluate_script(global.handle(), "1 + 1",
3130
"test", 1, rval.handle_mut()).is_ok());
3231
}

tests/stack_limit.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
#[macro_use]
56
extern crate js;
67

78
use js::jsapi::CompartmentOptions;
89
use js::jsapi::JS_NewGlobalObject;
910
use js::jsapi::OnNewGlobalHookOption;
10-
use js::jsapi::Rooted;
11-
use js::jsapi::RootedValue;
1211
use js::jsval::UndefinedValue;
1312
use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
1413

@@ -24,9 +23,9 @@ fn stack_limit() {
2423
let c_option = CompartmentOptions::default();
2524
let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
2625
ptr::null_mut(), h_option, &c_option);
27-
let global_root = Rooted::new(cx, global);
26+
rooted!(in(cx) let global_root = global);
2827
let global = global_root.handle();
29-
let mut rval = RootedValue::new(cx, UndefinedValue());
28+
rooted!(in(cx) let mut rval = UndefinedValue());
3029
assert!(rt.evaluate_script(global, "function f() { f.apply() } f()",
3130
"test", 1, rval.handle_mut()).is_err());
3231
}

tests/vec_conversion.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
#[macro_use]
56
extern crate js;
67

78
use js::conversions::ConversionBehavior;
@@ -12,8 +13,6 @@ use js::jsapi::JSAutoCompartment;
1213
use js::jsapi::JS_InitStandardClasses;
1314
use js::jsapi::JS_NewGlobalObject;
1415
use js::jsapi::OnNewGlobalHookOption;
15-
use js::jsapi::Rooted;
16-
use js::jsapi::RootedValue;
1716
use js::jsval::UndefinedValue;
1817
use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
1918

@@ -30,13 +29,13 @@ fn vec_conversion() {
3029
unsafe {
3130
let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
3231
ptr::null_mut(), h_option, &c_option);
33-
let global_root = Rooted::new(cx, global);
32+
rooted!(in(cx) let global_root = global);
3433
let global = global_root.handle();
3534

3635
let _ac = JSAutoCompartment::new(cx, global.get());
3736
assert!(JS_InitStandardClasses(cx, global));
3837

39-
let mut rval = RootedValue::new(cx, UndefinedValue());
38+
rooted!(in(cx) let mut rval = UndefinedValue());
4039

4140
let orig_vec: Vec<f32> = vec![1.0, 2.9, 3.0];
4241
orig_vec.to_jsval(cx, rval.handle_mut());

0 commit comments

Comments
 (0)