mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
590 lines
18 KiB
Rust
590 lines
18 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
||
//! Utilities for tracing JS-managed values.
|
||
//!
|
||
//! The lifetime of DOM objects is managed by the SpiderMonkey Garbage
|
||
//! Collector. A rooted DOM object implementing the interface `Foo` is traced
|
||
//! as follows:
|
||
//!
|
||
//! 1. The GC calls `_trace` defined in `FooBinding` during the marking
|
||
//! phase. (This happens through `JSClass.trace` for non-proxy bindings, and
|
||
//! through `ProxyTraps.trace` otherwise.)
|
||
//! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`).
|
||
//! This is typically derived via a `#[dom_struct]`
|
||
//! (implies `#[derive(JSTraceable)]`) annotation.
|
||
//! Non-JS-managed types have an empty inline `trace()` method,
|
||
//! achieved via `no_jsmanaged_fields!` or similar.
|
||
//! 3. For all fields, `Foo::trace()`
|
||
//! calls `trace()` on the field.
|
||
//! For example, for fields of type `JS<T>`, `JS<T>::trace()` calls
|
||
//! `trace_reflector()`.
|
||
//! 4. `trace_reflector()` calls `JS_CallUnbarrieredObjectTracer()` with a
|
||
//! pointer to the `JSObject` for the reflector. This notifies the GC, which
|
||
//! will add the object to the graph, and will trace that object as well.
|
||
//! 5. When the GC finishes tracing, it [`finalizes`](../index.html#destruction)
|
||
//! any reflectors that were not reachable.
|
||
//!
|
||
//! The `no_jsmanaged_fields!()` macro adds an empty implementation of `JSTraceable` to
|
||
//! a datatype.
|
||
|
||
use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle};
|
||
use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle};
|
||
use cssparser::RGBA;
|
||
use devtools_traits::CSSError;
|
||
use devtools_traits::WorkerId;
|
||
use dom::abstractworker::SharedRt;
|
||
use dom::bindings::js::{JS, Root};
|
||
use dom::bindings::refcounted::Trusted;
|
||
use dom::bindings::reflector::{Reflectable, Reflector};
|
||
use dom::bindings::str::{DOMString, USVString};
|
||
use dom::bindings::utils::WindowProxyHandler;
|
||
use encoding::types::EncodingRef;
|
||
use euclid::length::Length as EuclidLength;
|
||
use euclid::matrix2d::Matrix2D;
|
||
use euclid::point::Point2D;
|
||
use euclid::rect::Rect;
|
||
use euclid::size::Size2D;
|
||
use html5ever::tree_builder::QuirksMode;
|
||
use hyper::header::Headers;
|
||
use hyper::method::Method;
|
||
use hyper::mime::Mime;
|
||
use hyper::status::StatusCode;
|
||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||
use js::glue::{CallObjectTracer, CallUnbarrieredObjectTracer, CallValueTracer};
|
||
use js::jsapi::{GCTraceKindToAscii, Heap, TraceKind, JSObject, JSTracer};
|
||
use js::jsval::JSVal;
|
||
use js::rust::Runtime;
|
||
use libc;
|
||
use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeType, ReferrerPolicy};
|
||
use net_traits::filemanager_thread::RelativePos;
|
||
use net_traits::image::base::{Image, ImageMetadata};
|
||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
|
||
use net_traits::request::Request;
|
||
use net_traits::response::HttpsState;
|
||
use net_traits::response::{Response, ResponseBody};
|
||
use net_traits::storage_thread::StorageType;
|
||
use net_traits::{Metadata, NetworkError, ResourceThreads};
|
||
use offscreen_gl_context::GLLimits;
|
||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||
use script_layout_interface::OpaqueStyleAndLayoutData;
|
||
use script_layout_interface::reporter::CSSErrorReporter;
|
||
use script_layout_interface::rpc::LayoutRPC;
|
||
use script_runtime::ScriptChan;
|
||
use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress, WindowSizeData};
|
||
use serde::{Deserialize, Serialize};
|
||
use smallvec::SmallVec;
|
||
use std::boxed::FnBox;
|
||
use std::cell::{Cell, UnsafeCell};
|
||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||
use std::hash::{BuildHasher, Hash};
|
||
use std::mem;
|
||
use std::ops::{Deref, DerefMut};
|
||
use std::path::PathBuf;
|
||
use std::rc::Rc;
|
||
use std::sync::Arc;
|
||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||
use std::sync::mpsc::{Receiver, Sender};
|
||
use std::time::SystemTime;
|
||
use string_cache::{Atom, Namespace, QualName};
|
||
use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
|
||
use style::domrefcell::DOMRefCell;
|
||
use style::element_state::*;
|
||
use style::properties::PropertyDeclarationBlock;
|
||
use style::selector_impl::{PseudoElement, ElementSnapshot};
|
||
use style::values::specified::Length;
|
||
use time::Duration;
|
||
use url::Origin as UrlOrigin;
|
||
use url::Url;
|
||
use uuid::Uuid;
|
||
use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
|
||
use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId};
|
||
|
||
/// A trait to allow tracing (only) DOM objects.
|
||
pub trait JSTraceable {
|
||
/// Trace `self`.
|
||
fn trace(&self, trc: *mut JSTracer);
|
||
}
|
||
|
||
no_jsmanaged_fields!(CSSError);
|
||
|
||
no_jsmanaged_fields!(EncodingRef);
|
||
|
||
no_jsmanaged_fields!(Reflector);
|
||
|
||
no_jsmanaged_fields!(Duration);
|
||
|
||
/// Trace a `JSVal`.
|
||
pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) {
|
||
unsafe {
|
||
if !val.get().is_markable() {
|
||
return;
|
||
}
|
||
|
||
debug!("tracing value {}", description);
|
||
CallValueTracer(tracer,
|
||
val.ptr.get() as *mut _,
|
||
GCTraceKindToAscii(val.get().trace_kind()));
|
||
}
|
||
}
|
||
|
||
/// Trace the `JSObject` held by `reflector`.
|
||
#[allow(unrooted_must_root)]
|
||
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
||
unsafe {
|
||
debug!("tracing reflector {}", description);
|
||
CallUnbarrieredObjectTracer(tracer,
|
||
reflector.rootable(),
|
||
GCTraceKindToAscii(TraceKind::Object));
|
||
}
|
||
}
|
||
|
||
/// Trace a `JSObject`.
|
||
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
|
||
unsafe {
|
||
debug!("tracing {}", description);
|
||
CallObjectTracer(tracer,
|
||
obj.ptr.get() as *mut _,
|
||
GCTraceKindToAscii(TraceKind::Object));
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for Rc<T> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
(**self).trace(trc)
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for Box<T> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
(**self).trace(trc)
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable + Copy> JSTraceable for Cell<T> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
self.get().trace(trc)
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for UnsafeCell<T> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
unsafe { (*self.get()).trace(trc) }
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
unsafe {
|
||
(*self).borrow_for_gc_trace().trace(trc)
|
||
}
|
||
}
|
||
}
|
||
|
||
impl JSTraceable for Heap<*mut JSObject> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
if self.get().is_null() {
|
||
return;
|
||
}
|
||
trace_object(trc, "heap object", self);
|
||
}
|
||
}
|
||
|
||
|
||
impl JSTraceable for Heap<JSVal> {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
trace_jsval(trc, "heap value", self);
|
||
}
|
||
}
|
||
|
||
// XXXManishearth Check if the following three are optimized to no-ops
|
||
// if e.trace() is a no-op (e.g it is an no_jsmanaged_fields type)
|
||
impl<T: JSTraceable> JSTraceable for Vec<T> {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
for e in &*self {
|
||
e.trace(trc);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for (T, T, T, T) {
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
self.0.trace(trc);
|
||
self.1.trace(trc);
|
||
self.2.trace(trc);
|
||
self.3.trace(trc);
|
||
}
|
||
}
|
||
|
||
// XXXManishearth Check if the following three are optimized to no-ops
|
||
// if e.trace() is a no-op (e.g it is an no_jsmanaged_fields type)
|
||
impl<T: JSTraceable + 'static> JSTraceable for SmallVec<[T; 1]> {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
for e in self.iter() {
|
||
e.trace(trc);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable> JSTraceable for Option<T> {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
self.as_ref().map(|e| e.trace(trc));
|
||
}
|
||
}
|
||
|
||
impl<T: JSTraceable, U: JSTraceable> JSTraceable for Result<T, U> {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
match *self {
|
||
Ok(ref inner) => inner.trace(trc),
|
||
Err(ref inner) => inner.trace(trc),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<K, V, S> JSTraceable for HashMap<K, V, S>
|
||
where K: Hash + Eq + JSTraceable,
|
||
V: JSTraceable,
|
||
S: BuildHasher
|
||
{
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
for (k, v) in &*self {
|
||
k.trace(trc);
|
||
v.trace(trc);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<K: Ord + JSTraceable, V: JSTraceable> JSTraceable for BTreeMap<K, V> {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
for (k, v) in self {
|
||
k.trace(trc);
|
||
v.trace(trc);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
let (ref a, ref b) = *self;
|
||
a.trace(trc);
|
||
b.trace(trc);
|
||
}
|
||
}
|
||
|
||
impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) {
|
||
#[inline]
|
||
fn trace(&self, trc: *mut JSTracer) {
|
||
let (ref a, ref b, ref c) = *self;
|
||
a.trace(trc);
|
||
b.trace(trc);
|
||
c.trace(trc);
|
||
}
|
||
}
|
||
|
||
no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char);
|
||
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
|
||
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
|
||
no_jsmanaged_fields!(Sender<T>);
|
||
no_jsmanaged_fields!(Receiver<T>);
|
||
no_jsmanaged_fields!(Point2D<T>);
|
||
no_jsmanaged_fields!(Rect<T>);
|
||
no_jsmanaged_fields!(Size2D<T>);
|
||
no_jsmanaged_fields!(Arc<T>);
|
||
no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread);
|
||
no_jsmanaged_fields!(Metadata);
|
||
no_jsmanaged_fields!(NetworkError);
|
||
no_jsmanaged_fields!(Atom, Namespace, QualName);
|
||
no_jsmanaged_fields!(Trusted<T: Reflectable>);
|
||
no_jsmanaged_fields!(PropertyDeclarationBlock);
|
||
no_jsmanaged_fields!(HashSet<T>);
|
||
// These three are interdependent, if you plan to put jsmanaged data
|
||
// in one of these make sure it is propagated properly to containing structs
|
||
no_jsmanaged_fields!(FrameType, SubpageId, WindowSizeData, WindowSizeType, PipelineId);
|
||
no_jsmanaged_fields!(TimerEventId, TimerSource);
|
||
no_jsmanaged_fields!(WorkerId);
|
||
no_jsmanaged_fields!(QuirksMode);
|
||
no_jsmanaged_fields!(Runtime);
|
||
no_jsmanaged_fields!(Headers, Method);
|
||
no_jsmanaged_fields!(WindowProxyHandler);
|
||
no_jsmanaged_fields!(UntrustedNodeAddress);
|
||
no_jsmanaged_fields!(LengthOrPercentageOrAuto);
|
||
no_jsmanaged_fields!(RGBA);
|
||
no_jsmanaged_fields!(EuclidLength<Unit, T>);
|
||
no_jsmanaged_fields!(Matrix2D<T>);
|
||
no_jsmanaged_fields!(StorageType);
|
||
no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle);
|
||
no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending);
|
||
no_jsmanaged_fields!(RepetitionStyle);
|
||
no_jsmanaged_fields!(WebGLError, GLLimits);
|
||
no_jsmanaged_fields!(TimeProfilerChan);
|
||
no_jsmanaged_fields!(MemProfilerChan);
|
||
no_jsmanaged_fields!(PseudoElement);
|
||
no_jsmanaged_fields!(Length);
|
||
no_jsmanaged_fields!(ElementState);
|
||
no_jsmanaged_fields!(DOMString);
|
||
no_jsmanaged_fields!(Mime);
|
||
no_jsmanaged_fields!(AttrIdentifier);
|
||
no_jsmanaged_fields!(AttrValue);
|
||
no_jsmanaged_fields!(ElementSnapshot);
|
||
no_jsmanaged_fields!(HttpsState);
|
||
no_jsmanaged_fields!(Request);
|
||
no_jsmanaged_fields!(SharedRt);
|
||
no_jsmanaged_fields!(TouchpadPressurePhase);
|
||
no_jsmanaged_fields!(USVString);
|
||
no_jsmanaged_fields!(ReferrerPolicy);
|
||
no_jsmanaged_fields!(Response);
|
||
no_jsmanaged_fields!(ResponseBody);
|
||
no_jsmanaged_fields!(ResourceThreads);
|
||
no_jsmanaged_fields!(StatusCode);
|
||
no_jsmanaged_fields!(SystemTime);
|
||
no_jsmanaged_fields!(RelativePos);
|
||
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
|
||
no_jsmanaged_fields!(PathBuf);
|
||
no_jsmanaged_fields!(CSSErrorReporter);
|
||
no_jsmanaged_fields!(WebGLBufferId);
|
||
no_jsmanaged_fields!(WebGLFramebufferId);
|
||
no_jsmanaged_fields!(WebGLProgramId);
|
||
no_jsmanaged_fields!(WebGLRenderbufferId);
|
||
no_jsmanaged_fields!(WebGLShaderId);
|
||
no_jsmanaged_fields!(WebGLTextureId);
|
||
|
||
|
||
impl JSTraceable for Box<ScriptChan + Send> {
|
||
#[inline]
|
||
fn trace(&self, _trc: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl JSTraceable for Box<FnBox(f64, )> {
|
||
#[inline]
|
||
fn trace(&self, _trc: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl<'a> JSTraceable for &'a str {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl<A, B> JSTraceable for fn(A) -> B {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl<T> JSTraceable for IpcSender<T> where T: Deserialize + Serialize {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl JSTraceable for Box<LayoutRPC + 'static> {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl JSTraceable for () {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
impl<T> JSTraceable for IpcReceiver<T> where T: Deserialize + Serialize {
|
||
#[inline]
|
||
fn trace(&self, _: *mut JSTracer) {
|
||
// Do nothing
|
||
}
|
||
}
|
||
|
||
/// Homemade trait object for JSTraceable things
|
||
struct TraceableInfo {
|
||
pub ptr: *const libc::c_void,
|
||
pub trace: fn(obj: *const libc::c_void, tracer: *mut JSTracer),
|
||
}
|
||
|
||
/// Holds a set of JSTraceables that need to be rooted
|
||
pub struct RootedTraceableSet {
|
||
set: Vec<TraceableInfo>,
|
||
}
|
||
|
||
#[allow(missing_docs)] // FIXME
|
||
mod dummy { // Attributes don’t apply through the macro.
|
||
use std::cell::RefCell;
|
||
use std::rc::Rc;
|
||
use super::RootedTraceableSet;
|
||
/// TLV Holds a set of JSTraceables that need to be rooted
|
||
thread_local!(pub static ROOTED_TRACEABLES: Rc<RefCell<RootedTraceableSet>> =
|
||
Rc::new(RefCell::new(RootedTraceableSet::new())));
|
||
}
|
||
pub use self::dummy::ROOTED_TRACEABLES;
|
||
|
||
impl RootedTraceableSet {
|
||
fn new() -> RootedTraceableSet {
|
||
RootedTraceableSet {
|
||
set: vec![],
|
||
}
|
||
}
|
||
|
||
unsafe fn remove<T: JSTraceable>(traceable: &T) {
|
||
ROOTED_TRACEABLES.with(|ref traceables| {
|
||
let mut traceables = traceables.borrow_mut();
|
||
let idx =
|
||
match traceables.set.iter()
|
||
.rposition(|x| x.ptr == traceable as *const T as *const _) {
|
||
Some(idx) => idx,
|
||
None => unreachable!(),
|
||
};
|
||
traceables.set.remove(idx);
|
||
});
|
||
}
|
||
|
||
unsafe fn add<T: JSTraceable>(traceable: &T) {
|
||
ROOTED_TRACEABLES.with(|ref traceables| {
|
||
fn trace<T: JSTraceable>(obj: *const libc::c_void, tracer: *mut JSTracer) {
|
||
let obj: &T = unsafe { &*(obj as *const T) };
|
||
obj.trace(tracer);
|
||
}
|
||
|
||
let mut traceables = traceables.borrow_mut();
|
||
let info = TraceableInfo {
|
||
ptr: traceable as *const T as *const libc::c_void,
|
||
trace: trace::<T>,
|
||
};
|
||
traceables.set.push(info);
|
||
})
|
||
}
|
||
|
||
unsafe fn trace(&self, tracer: *mut JSTracer) {
|
||
for info in &self.set {
|
||
(info.trace)(info.ptr, tracer);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Roots any JSTraceable thing
|
||
///
|
||
/// If you have a valid Reflectable, use Root.
|
||
/// 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> {
|
||
ptr: &'a T,
|
||
}
|
||
|
||
impl<'a, T: JSTraceable> RootedTraceable<'a, T> {
|
||
/// Root a JSTraceable thing for the life of this RootedTraceable
|
||
pub fn new(traceable: &'a T) -> RootedTraceable<'a, T> {
|
||
unsafe {
|
||
RootedTraceableSet::add(traceable);
|
||
}
|
||
RootedTraceable {
|
||
ptr: traceable,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<'a, T: JSTraceable> Drop for RootedTraceable<'a, T> {
|
||
fn drop(&mut self) {
|
||
unsafe {
|
||
RootedTraceableSet::remove(self.ptr);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 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)]
|
||
#[derive(JSTraceable)]
|
||
#[allow_unrooted_interior]
|
||
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<'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<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<'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[..]) }
|
||
}
|
||
}
|
||
|
||
impl<'a, T: JSTraceable> Drop for RootedVec<'a, T> {
|
||
fn drop(&mut self) {
|
||
self.clear();
|
||
unsafe {
|
||
RootedTraceableSet::remove(self.root);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<'a, T: JSTraceable> Deref for RootedVec<'a, T> {
|
||
type Target = Vec<T>;
|
||
fn deref(&self) -> &Vec<T> {
|
||
&self.root.v
|
||
}
|
||
}
|
||
|
||
impl<'a, T: JSTraceable> DerefMut for RootedVec<'a, T> {
|
||
fn deref_mut(&mut self) -> &mut Vec<T> {
|
||
&mut self.root.v
|
||
}
|
||
}
|
||
|
||
/// SM Callback that traces the rooted traceables
|
||
pub unsafe fn trace_traceables(tracer: *mut JSTracer) {
|
||
debug!("tracing stack-rooted traceables");
|
||
ROOTED_TRACEABLES.with(|ref traceables| {
|
||
let traceables = traceables.borrow();
|
||
traceables.trace(tracer);
|
||
});
|
||
}
|