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

Commit 9ddac71

Browse files
author
bors-servo
authored
Auto merge of #272 - eddyb:back-to-roots, r=Manishearth
Replace return_address usage in Rooted with a stack guard and a rooted! macro. Part of a potential solution for rust-lang/rust#34227. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-mozjs/272) <!-- Reviewable:end -->
2 parents 707bfb4 + ae62516 commit 9ddac71

File tree

3 files changed

+120
-80
lines changed

3 files changed

+120
-80
lines changed

Diff for: src/conversions.rs

+34-5
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
}

Diff for: src/lib.rs

+4-2
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)]
@@ -77,12 +76,15 @@ pub mod jsapi {
7776
include!("jsapi_linux_32_debug.rs");
7877
}
7978

79+
#[macro_use]
80+
pub mod rust;
81+
8082
mod consts;
8183
pub mod conversions;
8284
pub mod error;
8385
pub mod glue;
8486
pub mod jsval;
85-
pub mod rust;
87+
8688

8789
pub use consts::*;
8890

Diff for: src/rust.rs

+82-73
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
//! Rust wrappers around the raw JS apis
66
7-
use libc::{size_t, c_uint, c_char, ptrdiff_t};
7+
use libc::{size_t, c_uint, c_char};
88
use heapsize::HeapSizeOf;
99
use std::char;
1010
use std::ffi;
@@ -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;
@@ -26,7 +25,6 @@ use jsapi::{JS_SetErrorReporter, Evaluate2, JSErrorReport};
2625
use jsapi::{JS_SetGCParameter, JSGCParamKey};
2726
use jsapi::{Heap, HeapObjectPostBarrier, HeapValuePostBarrier};
2827
use jsapi::{ContextFriendFields};
29-
use jsapi::{CustomAutoRooter, AutoGCRooter, _vftable_CustomAutoRooter, AutoGCRooter_jspubtd_h_unnamed_1};
3028
use jsapi::{Rooted, Handle, MutableHandle, MutableHandleBase, RootedBase};
3129
use jsapi::{MutableHandleValue, HandleValue, HandleObject, HandleBase};
3230
use jsapi::AutoObjectVector;
@@ -270,41 +268,103 @@ impl RootKind for Value {
270268
fn rootKind() -> jsapi::RootKind { jsapi::RootKind::Value }
271269
}
272270

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

287-
ctxfriend.roots.stackRoots_[kind] = unsafe { mem::transmute(addr) };
288-
root
288+
ctxfriend.roots.stackRoots_[kind] = self as *mut _ as usize as _;
289289
}
290290

291-
pub fn new(cx: *mut JSContext, initial: T) -> Rooted<T> {
292-
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;
293294
}
295+
}
294296

295-
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 {
296306
unsafe {
297-
Handle::from_marked_location(&self.ptr)
307+
root.add_to_root_stack(cx);
298308
}
309+
RootedGuard {
310+
root: root
311+
}
312+
}
313+
314+
pub fn handle(&self) -> Handle<T> where T: Copy {
315+
unsafe {
316+
Handle::from_marked_location(&self.root.ptr)
317+
}
318+
}
319+
320+
pub fn handle_mut(&mut self) -> MutableHandle<T> where T: Copy {
321+
unsafe {
322+
MutableHandle::from_marked_location(&mut self.root.ptr)
323+
}
324+
}
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
299345
}
346+
}
300347

301-
pub fn handle_mut(&mut self) -> MutableHandle<T> {
348+
impl<'a, T> Drop for RootedGuard<'a, T> {
349+
fn drop(&mut self) {
302350
unsafe {
303-
MutableHandle::from_marked_location(&mut self.ptr)
351+
self.root.remove_from_root_stack();
304352
}
305353
}
306354
}
307355

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+
}
366+
}
367+
308368
impl<T: Copy> Handle<T> {
309369
pub fn get(&self) -> T {
310370
unsafe { *self.ptr }
@@ -391,57 +451,6 @@ impl<T: Copy> MutableHandle<T> {
391451
}
392452
}
393453

394-
impl<T> Drop for Rooted<T> {
395-
fn drop(&mut self) {
396-
unsafe {
397-
if self.stack as usize == mem::POST_DROP_USIZE {
398-
return;
399-
}
400-
assert!(*self.stack == mem::transmute(&*self));
401-
*self.stack = self.prev;
402-
}
403-
}
404-
}
405-
406-
impl CustomAutoRooter {
407-
pub fn new(cx: *mut JSContext, vftable: &'static _vftable_CustomAutoRooter)
408-
-> CustomAutoRooter {
409-
CustomAutoRooter::new_with_addr(cx, vftable, unsafe { return_address() })
410-
}
411-
412-
pub fn new_with_addr(cx: *mut JSContext, vftable: &'static _vftable_CustomAutoRooter, addr: *const u8) -> CustomAutoRooter {
413-
let ctxfriend: &mut ContextFriendFields = unsafe {
414-
&mut *(cx as *mut ContextFriendFields)
415-
};
416-
417-
let rooter = CustomAutoRooter {
418-
_vftable: vftable as *const _,
419-
_base: AutoGCRooter {
420-
down: ctxfriend.roots.autoGCRooters_,
421-
tag_: AutoGCRooter_jspubtd_h_unnamed_1::CUSTOM as ptrdiff_t,
422-
stackTop: &mut ctxfriend.roots.autoGCRooters_ as *mut _,
423-
}
424-
};
425-
426-
ctxfriend.roots.autoGCRooters_ = unsafe {
427-
(addr as *const *const u8).offset(1) as *const AutoGCRooter as *mut _
428-
};
429-
rooter
430-
}
431-
}
432-
433-
impl Drop for CustomAutoRooter {
434-
fn drop(&mut self) {
435-
if self._base.stackTop as usize == mem::POST_DROP_USIZE {
436-
return;
437-
}
438-
unsafe {
439-
assert!(*self._base.stackTop == mem::transmute(&self._base));
440-
*self._base.stackTop = self._base.down;
441-
}
442-
}
443-
}
444-
445454
impl Default for jsid {
446455
fn default() -> jsid { JSID_VOID }
447456
}

0 commit comments

Comments
 (0)