servo: Merge #13569 - Start simplifying FFI ownership sugar (from Manishearth:simpliffi); r=emilio
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 05 Oct 2016 00:59:56 -0500
changeset 339835 579eff382d8e4bbcb1e9c62215f95b71554238f4
parent 339834 ada5a662212fdf157561ebd62719bd96fcfd4f1c
child 339836 694be2a7cd68aedd4eb04d3735e1cdd58577e1d9
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
servo: Merge #13569 - Start simplifying FFI ownership sugar (from Manishearth:simpliffi); r=emilio This is step one of a series of changes planned to make the ownership sugar easier to use. This was blocked on #13038 *very* unsure about second commit. Don't like the thought of accepting types with destructors over FFI. Probably will revert it. Leaving it in for now in case you have some insight. Eventually at least for the borrowed stuff I want to use T directly (because the crates are merged now), instead of the fake void types. Perhaps for the others too. I might include those changes in this PR -- was originally planning to but I realized that these steps could be split out. Tentative plan for `Owned` (assuming it's not removed) is to have `Owned<T> <-> Box<T>` (same `T`, no "FFI type") conversions. We will only use ownership wrapper types for things with destructors, and try to keep the conversion simple. I'm envisioning a couple methods for arc/strong and a few more for box/owned. We may need to introduce new wrapper types for gecko-side managed objects (`RefPtr<T>`, `UniquePtr<T>`) but that should be all the wrapper types we have in the ownership sugar. This PR relies on the guarantee that `Option<&T>` and `Option<Box<T>>` are pointer-sized via the `NonZero` optimization. I am now less unconvinced that this is a good idea :wink:. r? @emilio cc @mystor Source-Repo: https://github.com/servo/servo Source-Revision: cbc857bb78fdc5e9221ecdec25c82be7172bab36
servo/components/style/binding_tools/regen.py
servo/components/style/gecko/wrapper.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/gecko_bindings/sugar/ownership.rs
servo/components/style/properties/gecko.mako.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/binding_tools/regen.py
+++ b/servo/components/style/binding_tools/regen.py
@@ -437,34 +437,34 @@ def build(objdir, target_name, debug, de
             flags.append("{}Strong".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;"
                          .format(ty))
             flags.append("--blacklist-type")
             flags.append("{}BorrowedOrNull".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}BorrowedOrNull<'a> = \
-::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;".format(ty))
+Option<&'a {0}>;".format(ty))
             flags.append("--blacklist-type")
             flags.append("{}Borrowed".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty))
             zero_size_type(ty, flags)
 
     if "servo_immutable_borrow_types" in current_target:
         for ty in current_target["servo_immutable_borrow_types"]:
             flags.append("--blacklist-type")
             flags.append("{}Borrowed".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty))
             flags.append("--blacklist-type")
             flags.append("{}BorrowedOrNull".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}BorrowedOrNull<'a> = \
-::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;".format(ty))
+Option<&'a {0}>;".format(ty))
             # Right now the only immutable borrow types are ones which we import
             # from the |structs| module. As such, we don't need to create an opaque
             # type with zero_size_type. If we ever introduce immutable borrow types
             # which _do_ need to be opaque, we'll need a separate mode.
 
     if "servo_mapped_generic_types" in current_target:
         for ty in current_target["servo_mapped_generic_types"]:
             flags.append("--blacklist-type")
@@ -484,22 +484,22 @@ def build(objdir, target_name, debug, de
             flags.append("pub type {0}BorrowedMut<'a> = &'a mut {0};".format(ty))
             flags.append("--blacklist-type")
             flags.append("{}Owned".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;".format(ty))
             flags.append("--blacklist-type")
             flags.append("{}BorrowedOrNull".format(ty))
             flags.append("--raw-line")
-            flags.append("pub type {0}BorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;"
+            flags.append("pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;"
                          .format(ty))
             flags.append("--blacklist-type")
             flags.append("{}BorrowedMutOrNull".format(ty))
             flags.append("--raw-line")
-            flags.append("pub type {0}BorrowedMutOrNull<'a> = ::gecko_bindings::sugar::ownership::BorrowedMut<'a, {0}>;"
+            flags.append("pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;"
                          .format(ty))
             flags.append("--blacklist-type")
             flags.append("{}OwnedOrNull".format(ty))
             flags.append("--raw-line")
             flags.append("pub type {0}OwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;".format(ty))
             zero_size_type(ty, flags)
 
     if "structs_types" in current_target:
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -151,17 +151,17 @@ impl TRestyleDamage for GeckoRestyleDama
     fn empty() -> Self {
         use std::mem;
         GeckoRestyleDamage(unsafe { mem::transmute(0u32) })
     }
 
     fn compute(source: &nsStyleContext,
                new_style: &Arc<ComputedValues>) -> Self {
         let context = source as *const nsStyleContext as *mut nsStyleContext;
-        let hint = unsafe { Gecko_CalcStyleDifference(context, new_style.as_borrowed()) };
+        let hint = unsafe { Gecko_CalcStyleDifference(context, new_style.as_borrowed_opt().unwrap()) };
         GeckoRestyleDamage(hint)
     }
 
     fn rebuild_and_reflow() -> Self {
         GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame)
     }
 }
 
@@ -325,17 +325,17 @@ impl<'ln> TNode for GeckoNode<'ln> {
         unsafe { self.0.mParent.as_ref().map(GeckoNode) }
     }
 
     fn first_child(&self) -> Option<GeckoNode<'ln>> {
         unsafe { self.0.mFirstChild.as_ref().map(GeckoNode::from_content) }
     }
 
     fn last_child(&self) -> Option<GeckoNode<'ln>> {
-        unsafe { Gecko_GetLastChild(self.0).borrow_opt().map(GeckoNode) }
+        unsafe { Gecko_GetLastChild(self.0).map(GeckoNode) }
     }
 
     fn prev_sibling(&self) -> Option<GeckoNode<'ln>> {
         unsafe { self.0.mPreviousSibling.as_ref().map(GeckoNode::from_content) }
     }
 
     fn next_sibling(&self) -> Option<GeckoNode<'ln>> {
         unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) }
@@ -393,17 +393,17 @@ impl<'a> Iterator for GeckoChildrenItera
     fn next(&mut self) -> Option<GeckoNode<'a>> {
         match *self {
             GeckoChildrenIterator::Current(curr) => {
                 let next = curr.and_then(|node| node.next_sibling());
                 *self = GeckoChildrenIterator::Current(next);
                 curr
             },
             GeckoChildrenIterator::GeckoIterator(ref it) => unsafe {
-                Gecko_GetNextStyleChild(&it).borrow_opt().map(GeckoNode)
+                Gecko_GetNextStyleChild(&it).map(GeckoNode)
             }
         }
     }
 }
 
 #[derive(Clone, Copy)]
 pub struct GeckoDocument<'ld>(pub &'ld RawGeckoDocument);
 
@@ -412,17 +412,17 @@ impl<'ld> TDocument for GeckoDocument<'l
     type ConcreteElement = GeckoElement<'ld>;
 
     fn as_node(&self) -> GeckoNode<'ld> {
         unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
     }
 
     fn root_node(&self) -> Option<GeckoNode<'ld>> {
         unsafe {
-            Gecko_GetDocumentElement(self.0).borrow_opt().map(|el| GeckoElement(el).as_node())
+            Gecko_GetDocumentElement(self.0).map(|el| GeckoElement(el).as_node())
         }
     }
 
     fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, GeckoElementSnapshot)> {
         unimplemented!()
         /*
         let elements =  unsafe { self.0.drain_modified_elements() };
         elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()*/
@@ -466,20 +466,20 @@ impl<'le> TElement for GeckoElement<'le>
     type ConcreteDocument = GeckoDocument<'le>;
 
     fn as_node(&self) -> Self::ConcreteNode {
         unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
     }
 
     fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
         let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
-        if declarations.is_null() {
+        if declarations.is_none() {
             None
         } else {
-            let declarations = declarations.as_arc::<GeckoDeclarationBlock>();
+            let declarations = GeckoDeclarationBlock::arc_from_borrowed(&declarations).unwrap();
             declarations.declarations.as_ref().map(|r| r as *const Arc<_>).map(|ptr| unsafe { &*ptr })
         }
     }
 
     fn get_state(&self) -> ElementState {
         unsafe {
             ElementState::from_bits_truncate(Gecko_ElementState(self.0) as u16)
         }
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -1,45 +1,45 @@
 /* automatically generated by rust-bindgen */
 
 use heapsize::HeapSizeOf;
 pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoComputedValues>;
-pub type ServoComputedValuesBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, ServoComputedValues>;
+pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;
 pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;
 enum ServoComputedValuesVoid{ }
 pub struct ServoComputedValues(ServoComputedValuesVoid);
 pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleSheet>;
-pub type RawServoStyleSheetBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, RawServoStyleSheet>;
+pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;
 pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;
 enum RawServoStyleSheetVoid{ }
 pub struct RawServoStyleSheet(RawServoStyleSheetVoid);
 pub type ServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong<ServoDeclarationBlock>;
-pub type ServoDeclarationBlockBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, ServoDeclarationBlock>;
+pub type ServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a ServoDeclarationBlock>;
 pub type ServoDeclarationBlockBorrowed<'a> = &'a ServoDeclarationBlock;
 enum ServoDeclarationBlockVoid{ }
 pub struct ServoDeclarationBlock(ServoDeclarationBlockVoid);
 pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;
-pub type RawGeckoNodeBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, RawGeckoNode>;
+pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;
 pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;
-pub type RawGeckoElementBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, RawGeckoElement>;
+pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;
 pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;
-pub type RawGeckoDocumentBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, RawGeckoDocument>;
+pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;
 pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;
 pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;
 pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
-pub type RawServoStyleSetBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, RawServoStyleSet>;
-pub type RawServoStyleSetBorrowedMutOrNull<'a> = ::gecko_bindings::sugar::ownership::BorrowedMut<'a, RawServoStyleSet>;
+pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;
+pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;
 pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
 enum RawServoStyleSetVoid{ }
 pub struct RawServoStyleSet(RawServoStyleSetVoid);
 pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;
 pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;
 pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned<StyleChildrenIterator>;
-pub type StyleChildrenIteratorBorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, StyleChildrenIterator>;
-pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = ::gecko_bindings::sugar::ownership::BorrowedMut<'a, StyleChildrenIterator>;
+pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;
+pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;
 pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<StyleChildrenIterator>;
 enum StyleChildrenIteratorVoid{ }
 pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);
 use gecko_bindings::structs::nsStyleFont;
 unsafe impl Send for nsStyleFont {}
 unsafe impl Sync for nsStyleFont {}
 use gecko_bindings::structs::nsStyleColor;
 unsafe impl Send for nsStyleColor {}
--- a/servo/components/style/gecko_bindings/sugar/ownership.rs
+++ b/servo/components/style/gecko_bindings/sugar/ownership.rs
@@ -67,26 +67,26 @@ pub unsafe trait HasBoxFFI : HasSimpleFF
 /// Should be implemented by types which are passed over FFI as Arcs
 /// via Strong and Borrowed
 ///
 /// In this case, the FFIType is the rough equivalent of ArcInner<Self>
 pub unsafe trait HasArcFFI : HasFFI {
     // these methods can't be on Borrowed because it leads to an unspecified
     // impl parameter
     /// Artificially increments the refcount of a (possibly null) borrowed Arc over FFI.
-    unsafe fn addref_opt(ptr: Borrowed<Self::FFIType>) {
-        forget(ptr.as_arc_opt::<Self>().clone())
+    unsafe fn addref_opt(ptr: Option<&Self::FFIType>) {
+        forget(Self::arc_from_borrowed(&ptr).clone())
     }
 
     /// Given a (possibly null) borrowed FFI reference, decrements the refcount.
     /// Unsafe since it doesn't consume the backing Arc. Run it only when you
     /// know that a strong reference to the backing Arc is disappearing
     /// (usually on the C++ side) without running the Arc destructor.
-    unsafe fn release_opt(ptr: Borrowed<Self::FFIType>) {
-        if let Some(arc) = ptr.as_arc_opt::<Self>() {
+    unsafe fn release_opt(ptr: Option<&Self::FFIType>) {
+        if let Some(arc) = Self::arc_from_borrowed(&ptr) {
             let _: Arc<_> = ptr::read(arc as *const Arc<_>);
         }
     }
 
     /// Artificially increments the refcount of a borrowed Arc over FFI.
     unsafe fn addref(ptr: &Self::FFIType) {
         forget(Self::as_arc(&ptr).clone())
     }
@@ -103,152 +103,29 @@ pub unsafe trait HasArcFFI : HasFFI {
     ///
     /// &GeckoType -> &Arc<ServoType>
     fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a Arc<Self> {
         debug_assert!(!(ptr as *const _).is_null());
         unsafe {
             transmute::<&&Self::FFIType, &Arc<Self>>(ptr)
         }
     }
-}
-
-#[repr(C)]
-/// Gecko-FFI-safe borrowed type
-/// This can be null.
-pub struct Borrowed<'a, T: 'a> {
-    ptr: *const T,
-    _marker: PhantomData<&'a T>,
-}
-
-#[repr(C)]
-/// Gecko-FFI-safe mutably borrowed type
-/// This can be null.
-pub struct BorrowedMut<'a, T: 'a> {
-    ptr: *mut T,
-    _marker: PhantomData<&'a mut T>,
-}
-
-// manual impls because derive doesn't realize that `T: Clone` isn't necessary
-impl<'a, T> Copy for Borrowed<'a, T> {}
-
-impl<'a, T> Clone for Borrowed<'a, T> {
-    #[inline]
-    fn clone(&self) -> Self { *self }
-}
-
-impl<'a, T> Borrowed<'a, T> {
-    #[inline]
-    pub fn is_null(self) -> bool {
-        self.ptr == ptr::null()
-    }
-
-    #[inline]
-    /// Like Deref, but gives an Option
-    pub fn borrow_opt(self) -> Option<&'a T> {
-        if self.is_null() {
-            None
-        } else {
-            Some(unsafe { &*self.ptr })
-        }
-    }
-
-    #[inline]
-    /// Borrowed<GeckoType> -> Option<&Arc<ServoType>>
-    pub fn as_arc_opt<U>(&self) -> Option<&Arc<U>> where U: HasArcFFI<FFIType = T> {
-        unsafe {
-            if self.is_null() {
-                None
-            } else {
-                Some(transmute::<&Borrowed<_>, &Arc<_>>(self))
-            }
-        }
-    }
-
-    #[inline]
-    /// Converts a borrowed FFI reference to a borrowed Arc.
-    /// Panics on null.
-    ///
-    /// &Borrowed<GeckoType> -> &Arc<ServoType>
-    pub fn as_arc<U>(&self) -> &Arc<U> where U: HasArcFFI<FFIType = T> {
-        self.as_arc_opt().unwrap()
-    }
 
     #[inline]
-    /// Borrowed<ServoType> -> Borrowed<GeckoType>
-    pub fn as_ffi(self) -> Borrowed<'a, <Self as HasFFI>::FFIType> where Self: HasSimpleFFI {
-        unsafe { transmute(self) }
-    }
-
-    #[inline]
-    /// Borrowed<GeckoType> -> Borrowed<ServoType>
-    pub fn from_ffi<U>(self) -> Borrowed<'a, U> where U: HasSimpleFFI<FFIType = T> {
-        unsafe { transmute(self) }
-    }
-
-    #[inline]
-    /// Borrowed<GeckoType> -> &ServoType
-    pub fn as_servo_ref<U>(self) -> Option<&'a U> where U: HasSimpleFFI<FFIType = T> {
-        self.borrow_opt().map(HasSimpleFFI::from_ffi)
-    }
-
-    pub fn null() -> Borrowed<'static, T> {
-        Borrowed {
-            ptr: ptr::null_mut(),
-            _marker: PhantomData
+    fn arc_from_borrowed<'a>(ptr: &'a Option<&Self::FFIType>) -> Option<&'a Arc<Self>> {
+        unsafe {
+            if let Some(ref reference) = *ptr {
+                Some(transmute::<&&Self::FFIType, &Arc<_>>(reference))
+            } else {
+                None
+            }
         }
     }
 }
 
-impl<'a, T> BorrowedMut<'a, T> {
-    #[inline]
-    /// Like DerefMut, but gives an Option
-    pub fn borrow_mut_opt(self) -> Option<&'a mut T> {
-        // We have two choices for the signature here, it can either be
-        // Self -> Option<&'a mut T> or
-        // &'b mut Self -> Option<'b mut T>
-        // The former consumes the BorrowedMut (which isn't Copy),
-        // which can be annoying. The latter only temporarily
-        // borrows it, so the return value can't exit the scope
-        // even if Self has a longer lifetime ('a)
-        //
-        // This is basically the implicit "reborrow" pattern used with &mut
-        // not cleanly translating to our custom types.
-
-        // I've chosen the former solution -- you can manually convert back
-        // if you need to reuse the BorrowedMut.
-        if self.is_null() {
-            None
-        } else {
-            Some(unsafe { &mut *self.ptr })
-        }
-    }
-
-    #[inline]
-    /// BorrowedMut<GeckoType> -> &mut ServoType
-    pub fn as_servo_mut_ref<U>(self) -> Option<&'a mut U> where U: HasSimpleFFI<FFIType = T> {
-        self.borrow_mut_opt().map(HasSimpleFFI::from_ffi_mut)
-    }
-
-    pub fn null_mut() -> BorrowedMut<'static, T> {
-        BorrowedMut {
-            ptr: ptr::null_mut(),
-            _marker: PhantomData
-        }
-    }
-}
-
-// technically not how we're supposed to use
-// Deref, but that's a minor style issue
-impl<'a, T> Deref for BorrowedMut<'a, T> {
-    type Target = Borrowed<'a, T>;
-    fn deref(&self) -> &Self::Target {
-        unsafe { transmute(self) }
-    }
-}
-
 #[repr(C)]
 /// Gecko-FFI-safe Arc (T is an ArcInner).
 /// This can be null.
 /// Leaks on drop. Please don't drop this.
 /// TODO: Add destructor bomb once drop flags are gone
 pub struct Strong<T> {
     ptr: *const T,
     _marker: PhantomData<T>,
@@ -294,38 +171,29 @@ impl<T> Strong<T> {
 pub unsafe trait FFIArcHelpers {
     type Inner: HasArcFFI;
     /// Converts an Arc into a strong FFI reference.
     ///
     /// Arc<ServoType> -> Strong<GeckoType>
     fn into_strong(self) -> Strong<<Self::Inner as HasFFI>::FFIType>;
     /// Produces a (nullable) borrowed FFI reference by borrowing an Arc.
     ///
-    /// &Arc<ServoType> -> Borrowed<GeckoType>
-    fn as_borrowed_opt(&self) -> Borrowed<<Self::Inner as HasFFI>::FFIType>;
-    /// Produces a borrowed FFI reference by borrowing an Arc.
-    ///
-    /// &Arc<ServoType> -> &GeckoType
-    fn as_borrowed(&self) -> &<Self::Inner as HasFFI>::FFIType;
+    /// &Arc<ServoType> -> Option<&GeckoType>
+    fn as_borrowed_opt(&self) -> Option<&<Self::Inner as HasFFI>::FFIType>;
 }
 
 unsafe impl<T: HasArcFFI> FFIArcHelpers for Arc<T> {
     type Inner = T;
     #[inline]
     fn into_strong(self) -> Strong<T::FFIType> {
         unsafe { transmute(self) }
     }
     #[inline]
-    fn as_borrowed_opt(&self) -> Borrowed<T::FFIType> {
-        let borrowedptr = self as *const Arc<T> as *const Borrowed<T::FFIType>;
-        unsafe { ptr::read(borrowedptr) }
-    }
-    #[inline]
-    fn as_borrowed(&self) -> &T::FFIType {
-        let borrowedptr = self as *const Arc<T> as *const & T::FFIType;
+    fn as_borrowed_opt(&self) -> Option<&T::FFIType> {
+        let borrowedptr = self as *const Arc<T> as *const Option<&T::FFIType>;
         unsafe { ptr::read(borrowedptr) }
     }
 }
 
 #[repr(C)]
 /// Gecko-FFI-safe owned pointer
 /// Cannot be null
 /// Leaks on drop. Please don't drop this.
@@ -382,16 +250,16 @@ impl<T> OwnedOrNull<T> {
     pub fn into_owned_opt(self) -> Option<Owned<T>> {
         if self.is_null() {
             None
         } else {
             Some(unsafe { transmute(self) })
         }
     }
 
-    pub fn borrow(&self) -> Borrowed<T> {
+    pub fn borrow(&self) -> Option<&T> {
         unsafe { transmute(self) }
     }
 
-    pub fn borrow_mut(&self) -> BorrowedMut<T> {
+    pub fn borrow_mut(&self) -> Option<&mut T> {
         unsafe { transmute(self) }
     }
 }
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -22,16 +22,17 @@ use gecko_bindings::bindings::{Gecko_Set
 use gecko_bindings::bindings::{Gecko_SetNullImageValue, Gecko_SetGradientImageValue};
 use gecko_bindings::bindings::{Gecko_EnsureImageLayersLength, Gecko_CreateGradient};
 use gecko_bindings::bindings::{Gecko_CopyImageValueFrom, Gecko_CopyFontFamilyFrom};
 use gecko_bindings::bindings::{Gecko_FontFamilyList_AppendGeneric, Gecko_FontFamilyList_AppendNamed};
 use gecko_bindings::bindings::{Gecko_FontFamilyList_Clear, Gecko_InitializeImageLayer};
 use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use gecko_bindings::structs;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
+use gecko_bindings::sugar::ownership::HasArcFFI;
 use gecko::values::{StyleCoordHelpers, GeckoStyleCoordConvertible, convert_nscolor_to_rgba};
 use gecko::values::convert_rgba_to_nscolor;
 use gecko::values::round_border_to_device_pixels;
 use logical_geometry::WritingMode;
 use properties::CascadePropertyFn;
 use properties::longhands;
 use std::fmt::{self, Debug};
 use std::mem::{transmute, zeroed};
@@ -1929,17 +1930,17 @@ clip-path
     }
 </%self:impl_trait>
 
 <%def name="define_ffi_struct_accessor(style_struct)">
 #[no_mangle]
 #[allow(non_snake_case, unused_variables)]
 pub extern "C" fn Servo_GetStyle${style_struct.gecko_name}(computed_values:
         ServoComputedValuesBorrowedOrNull) -> *const ${style_struct.gecko_ffi_name} {
-    computed_values.as_arc::<ComputedValues>().get_${style_struct.name_lower}().get_gecko()
+    ComputedValues::arc_from_borrowed(&computed_values).unwrap().get_${style_struct.name_lower}().get_gecko()
         as *const ${style_struct.gecko_ffi_name}
 }
 </%def>
 
 % for style_struct in data.style_structs:
 ${declare_style_struct(style_struct)}
 ${impl_style_struct(style_struct)}
 % if not style_struct.name in data.manual_style_structs:
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -248,17 +248,17 @@ pub extern "C" fn Servo_ComputedValues_G
     // The stylist consumes stylesheets lazily.
     let data = PerDocumentStyleData::from_ffi_mut(raw_data);
     data.flush_stylesheets();
 
     let atom = Atom::from(pseudo_tag);
     let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true);
 
 
-    let maybe_parent = parent_style_or_null.as_arc_opt();
+    let maybe_parent = ComputedValues::arc_from_borrowed(&parent_style_or_null);
     let new_computed = data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent);
     new_computed.map_or(Strong::null(), |c| c.into_strong())
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetForPseudoElement(parent_style: ServoComputedValuesBorrowed,
                                                            match_element: RawGeckoElementBorrowed,
                                                            pseudo_tag: *mut nsIAtom,
@@ -305,20 +305,21 @@ pub extern "C" fn Servo_ComputedValues_G
                          Servo_GetComputedValuesForPseudoElement");
         }
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_Inherit(parent_style: ServoComputedValuesBorrowedOrNull)
      -> ServoComputedValuesStrong {
-    let style = if parent_style.is_null() {
+    let maybe_arc = ComputedValues::arc_from_borrowed(&parent_style);
+    let style = if let Some(reference) = maybe_arc.as_ref() {
+        ComputedValues::inherit_from(reference)
+    } else {
         Arc::new(ComputedValues::initial_values().clone())
-    } else {
-        ComputedValues::inherit_from(parent_style.as_arc())
     };
     style.into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_AddRef(ptr: ServoComputedValuesBorrowed) -> () {
     unsafe { ComputedValues::addref(ptr) };
 }