New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace return_address usage in Rooted with a stack guard and a rooted! macro. #272
Changes from 1 commit
File filter...
Jump to…
Move from using return_address to a macro-mediated rooting solution.
- Loading branch information
| @@ -13,7 +13,6 @@ use std::slice; | ||
| use std::mem; | ||
| use std::u32; | ||
| use std::default::Default; | ||
| use std::intrinsics::return_address; | ||
| use std::ops::{Deref, DerefMut}; | ||
| use std::cell::UnsafeCell; | ||
| use std::marker::PhantomData; | ||
| @@ -269,39 +268,101 @@ impl RootKind for Value { | ||
| fn rootKind() -> jsapi::RootKind { jsapi::RootKind::Value } | ||
| } | ||
|
|
||
| impl<T: RootKind + Copy> Rooted<T> { | ||
| pub fn new_with_addr(cx: *mut JSContext, initial: T, addr: *const u8) -> Rooted<T> { | ||
| let ctxfriend: &mut ContextFriendFields = unsafe { | ||
| mem::transmute(cx) | ||
| }; | ||
|
|
||
| let kind = T::rootKind() as usize; | ||
| let root = Rooted::<T> { | ||
| impl<T> Rooted<T> { | ||
| pub fn new_unrooted(initial: T) -> Rooted<T> { | ||
fitzgen
Member
|
||
| Rooted { | ||
| _base: RootedBase { _phantom0: PhantomData }, | ||
| stack: &mut ctxfriend.roots.stackRoots_[kind] as *mut _ as *mut _, | ||
| prev: ctxfriend.roots.stackRoots_[kind] as *mut _, | ||
| stack: ptr::null_mut(), | ||
| prev: ptr::null_mut(), | ||
| ptr: initial, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| ctxfriend.roots.stackRoots_[kind] = unsafe { mem::transmute(addr) }; | ||
| root | ||
| pub unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) where T: RootKind { | ||
| let ctxfriend: &mut ContextFriendFields = mem::transmute(cx); | ||
|
|
||
| let kind = T::rootKind() as usize; | ||
| self.stack = &mut ctxfriend.roots.stackRoots_[kind] as *mut _ as *mut _; | ||
| self.prev = ctxfriend.roots.stackRoots_[kind] as *mut _; | ||
|
|
||
| ctxfriend.roots.stackRoots_[kind] = self as *mut _ as usize as _; | ||
| } | ||
|
|
||
| pub fn new(cx: *mut JSContext, initial: T) -> Rooted<T> { | ||
| Rooted::new_with_addr(cx, initial, unsafe { return_address() }) | ||
| pub unsafe fn remove_from_root_stack(&mut self) { | ||
| assert!(*self.stack == mem::transmute(&*self)); | ||
| *self.stack = self.prev; | ||
| } | ||
| } | ||
|
|
||
| pub fn handle(&self) -> Handle<T> { | ||
| /// Rust API for keeping a Rooted value in the context's root stack. | ||
| /// Example usage: `rooted!(in(cx) let x = UndefinedValue());`. | ||
| /// `RootedGuard::new` also works, but the macro is preferred. | ||
| pub struct RootedGuard<'a, T: 'a> { | ||
| root: &'a mut Rooted<T> | ||
fitzgen
Member
|
||
| } | ||
|
|
||
| impl<'a, T> RootedGuard<'a, T> { | ||
| pub fn new(cx: *mut JSContext, root: &'a mut Rooted<T>) -> Self where T: RootKind { | ||
| unsafe { | ||
| root.add_to_root_stack(cx); | ||
| } | ||
| RootedGuard { | ||
| root: root | ||
| } | ||
| } | ||
|
|
||
| pub fn handle(&self) -> Handle<T> where T: Copy { | ||
|
||
| unsafe { | ||
| Handle::from_marked_location(&self.ptr) | ||
| Handle::from_marked_location(&self.root.ptr) | ||
| } | ||
| } | ||
|
|
||
| pub fn handle_mut(&mut self) -> MutableHandle<T> { | ||
| pub fn handle_mut(&mut self) -> MutableHandle<T> where T: Copy { | ||
| unsafe { | ||
| MutableHandle::from_marked_location(&mut self.ptr) | ||
| MutableHandle::from_marked_location(&mut self.root.ptr) | ||
| } | ||
| } | ||
|
|
||
| pub fn get(&self) -> T where T: Copy { | ||
| self.root.ptr | ||
| } | ||
|
|
||
| pub fn set(&mut self, v: T) { | ||
| self.root.ptr = v; | ||
| } | ||
| } | ||
|
|
||
| impl<'a, T> Deref for RootedGuard<'a, T> { | ||
| type Target = T; | ||
| fn deref(&self) -> &T { | ||
| &self.root.ptr | ||
| } | ||
| } | ||
|
|
||
| impl<'a, T> DerefMut for RootedGuard<'a, T> { | ||
| fn deref_mut(&mut self) -> &mut T { | ||
| &mut self.root.ptr | ||
| } | ||
| } | ||
|
|
||
| impl<'a, T> Drop for RootedGuard<'a, T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| self.root.remove_from_root_stack(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[macro_export] | ||
| macro_rules! rooted { | ||
| (in($cx:expr) let $name:ident = $init:expr) => { | ||
| let mut __root = $crate::jsapi::Rooted::new_unrooted($init); | ||
| let $name = $crate::rust::RootedGuard::new($cx, &mut __root); | ||
| }; | ||
| (in($cx:expr) let mut $name:ident = $init:expr) => { | ||
| let mut __root = $crate::jsapi::Rooted::new_unrooted($init); | ||
| let mut $name = $crate::rust::RootedGuard::new($cx, &mut __root); | ||
| } | ||
| } | ||
|
|
||
| impl<T: Copy> Handle<T> { | ||
| @@ -390,18 +451,6 @@ impl<T: Copy> MutableHandle<T> { | ||
| } | ||
| } | ||
|
|
||
| impl<T> Drop for Rooted<T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| if self.stack as usize == mem::POST_DROP_USIZE { | ||
| return; | ||
| } | ||
| assert!(*self.stack == mem::transmute(&*self)); | ||
| *self.stack = self.prev; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Default for jsid { | ||
| fn default() -> jsid { JSID_VOID } | ||
| } | ||
documentation on this? (explaining why it is necessary perhaps)