diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-07-04 11:03:35 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-04 11:03:35 -0700 |
commit | 80cb0cf8214fd52d2884724614c40cb278ee7575 (patch) | |
tree | d5d98004a84375aea65a74d594dead5a27fc2392 /components/script/dom/bindings/trace.rs | |
parent | 36974f0746261b971c93ed7dfb9bd726675ccf69 (diff) | |
parent | b79a7d468e99f335dce49cc48342f0cd447eb855 (diff) | |
download | servo-80cb0cf8214fd52d2884724614c40cb278ee7575.tar.gz servo-80cb0cf8214fd52d2884724614c40cb278ee7575.zip |
Auto merge of #11872 - eddyb:back-to-roots, r=Ms2ger
Replace return_address usage for rooting with stack guards and convenience macros.
The existing `Rooted` and `RootedVec` users were migrated the the following two macros:
```rust
let x = Rooted::new(cx, value);
// Was changed to:
rooted!(in(cx) let x = value);
// Which expands to:
let mut __root = Rooted::new_unrooted(value);
let x = RootedGuard::new(cx, &mut __root);
```
```rust
let mut v = RootedVec::new();
v.extend(iterator);
// Was changed to:
rooted_vec!(let v <- iterator);
// Which expands to:
let mut __root = RootableVec::new();
let v = RootedVec::new(&mut __root, iterator);
```
The `rooted!` macro depends on servo/rust-mozjs#272.
These APIs based on two types, a container to be rooted and a rooting guard, allow implementing both `Rooted`-style rooting and `Traceable`-based rooting in stable Rust, without abusing `return_address`.
Such macros may have been tried before, but in 1.9 their hygiene is broken, they work only since 1.10.
Sadly, `Rooted` is a FFI type and completely exposed, so I cannot prevent anyone from creating their own, although all fields but the value get overwritten by `RootedGuard::new` anyway.
`RootableVec` OTOH is *guaranteed* to be empty when not rooted, which makes it harmless AFAICT.
By fixing rust-lang/rust#34227, this PR enables Servo to build with `-Zorbit`.
---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix rust-lang/rust#34227
- [x] These changes do not require tests because they are not functional changes
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11872)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom/bindings/trace.rs')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 80 |
1 files changed, 39 insertions, 41 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a0813a047df..d066db9dfcb 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -77,8 +77,6 @@ use std::boxed::FnBox; use std::cell::{Cell, UnsafeCell}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::{BuildHasher, Hash}; -use std::intrinsics::return_address; -use std::iter::{FromIterator, IntoIterator}; use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; @@ -466,8 +464,8 @@ impl RootedTraceableSet { /// Roots any JSTraceable thing /// /// If you have a valid Reflectable, use Root. -/// If you have GC things like *mut JSObject or JSVal, use jsapi::Rooted. -/// If you have an arbitrary number of Reflectables to root, use RootedVec<JS<T>> +/// If you have GC things like *mut JSObject or JSVal, use rooted!. +/// If you have an arbitrary number of Reflectables to root, use rooted_vec!. /// If you know what you're doing, use this. #[derive(JSTraceable)] pub struct RootedTraceable<'a, T: 'a + JSTraceable> { @@ -494,73 +492,73 @@ impl<'a, T: JSTraceable> Drop for RootedTraceable<'a, T> { } } -/// A vector of items that are rooted for the lifetime of this struct. +/// A vector of items to be rooted with `RootedVec`. +/// Guaranteed to be empty when not rooted. +/// Usage: `rooted_vec!(let mut v);` or if you have an +/// iterator of `Root`s, `rooted_vec!(let v <- iterator);`. #[allow(unrooted_must_root)] -#[no_move] #[derive(JSTraceable)] #[allow_unrooted_interior] -pub struct RootedVec<T: JSTraceable> { +pub struct RootableVec<T: JSTraceable> { v: Vec<T>, } +impl<T: JSTraceable> RootableVec<T> { + /// Create a vector of items of type T that can be rooted later. + pub fn new_unrooted() -> RootableVec<T> { + RootableVec { + v: vec![], + } + } +} + +/// A vector of items that are rooted for the lifetime 'a. +#[allow_unrooted_interior] +pub struct RootedVec<'a, T: 'a + JSTraceable> { + root: &'a mut RootableVec<T>, +} -impl<T: JSTraceable> RootedVec<T> { +impl<'a, T: JSTraceable + Reflectable> RootedVec<'a, JS<T>> { /// Create a vector of items of type T that is rooted for /// the lifetime of this struct - pub fn new() -> RootedVec<T> { - let addr = unsafe { return_address() as *const libc::c_void }; - - unsafe { RootedVec::new_with_destination_address(addr) } - } - - /// Create a vector of items of type T. This constructor is specific - /// for RootTraceableSet. - pub unsafe fn new_with_destination_address(addr: *const libc::c_void) -> RootedVec<T> { - RootedTraceableSet::add::<RootedVec<T>>(&*(addr as *const _)); - RootedVec::<T> { - v: vec![], + pub fn new<I: Iterator<Item = Root<T>>>(root: &'a mut RootableVec<JS<T>>, iter: I) + -> RootedVec<'a, JS<T>> { + unsafe { + RootedTraceableSet::add(root); + } + root.v.extend(iter.map(|item| JS::from_ref(&*item))); + RootedVec { + root: root, } } } -impl<T: JSTraceable + Reflectable> RootedVec<JS<T>> { +impl<'a, T: JSTraceable + Reflectable> RootedVec<'a, JS<T>> { /// Obtain a safe slice of references that can't outlive that RootedVec. pub fn r(&self) -> &[&T] { - unsafe { mem::transmute(&self.v[..]) } + unsafe { mem::transmute(&self[..]) } } } -impl<T: JSTraceable> Drop for RootedVec<T> { +impl<'a, T: JSTraceable> Drop for RootedVec<'a, T> { fn drop(&mut self) { + self.clear(); unsafe { - RootedTraceableSet::remove(self); + RootedTraceableSet::remove(self.root); } } } -impl<T: JSTraceable> Deref for RootedVec<T> { +impl<'a, T: JSTraceable> Deref for RootedVec<'a, T> { type Target = Vec<T>; fn deref(&self) -> &Vec<T> { - &self.v + &self.root.v } } -impl<T: JSTraceable> DerefMut for RootedVec<T> { +impl<'a, T: JSTraceable> DerefMut for RootedVec<'a, T> { fn deref_mut(&mut self) -> &mut Vec<T> { - &mut self.v - } -} - -impl<A: JSTraceable + Reflectable> FromIterator<Root<A>> for RootedVec<JS<A>> { - #[allow(moved_no_move)] - fn from_iter<T>(iterable: T) -> RootedVec<JS<A>> - where T: IntoIterator<Item = Root<A>> - { - let mut vec = unsafe { - RootedVec::new_with_destination_address(return_address() as *const libc::c_void) - }; - vec.extend(iterable.into_iter().map(|item| JS::from_ref(&*item))); - vec + &mut self.root.v } } |