Move DUMMY_URL_DATA to glue and use static to avoid shutdown leak. r?Manishearth draft
authorXidorn Quan <me@upsuper.org>
Fri, 31 Mar 2017 15:58:04 +1100
changeset 554630 da02743c82518ff9aaa96b88324e633c4b96c931
parent 554629 5ca5a0ad0a5e3d774d36fe774a38f8cb8bfff8f9
child 554631 9afffa11db846d0ca9e2f427cec2ee7f2ed1e56a
push id52016
push userxquan@mozilla.com
push dateSat, 01 Apr 2017 07:30:38 +0000
reviewersManishearth
milestone55.0a1
Move DUMMY_URL_DATA to glue and use static to avoid shutdown leak. r?Manishearth MozReview-Commit-ID: 3N8YnlM7EyJ
servo/components/style/gecko/wrapper.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -36,24 +36,23 @@ use gecko_bindings::bindings::Gecko_GetA
 use gecko_bindings::bindings::Gecko_GetExtraContentStyleDeclarations;
 use gecko_bindings::bindings::Gecko_GetHTMLPresentationAttrDeclarationBlock;
 use gecko_bindings::bindings::Gecko_GetStyleAttrDeclarationBlock;
 use gecko_bindings::bindings::Gecko_GetStyleContext;
 use gecko_bindings::bindings::Gecko_IsSignificantChild;
 use gecko_bindings::bindings::Gecko_MatchStringArgPseudo;
 use gecko_bindings::bindings::Gecko_UpdateAnimations;
 use gecko_bindings::structs;
-use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, URLExtraData};
+use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
 use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext};
 use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
 use gecko_bindings::structs::NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
 use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
 use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
 use gecko_bindings::sugar::ownership::HasArcFFI;
-use gecko_bindings::sugar::refptr::RefPtr;
 use parking_lot::RwLock;
 use properties::{ComputedValues, parse_style_attribute};
 use properties::PropertyDeclarationBlock;
 use properties::animated_properties::AnimationValueMap;
 use rule_tree::CascadeLevel as ServoCascadeLevel;
 use selector_parser::{ElementExt, Snapshot};
 use selectors::Element;
 use selectors::matching::{ElementSelectorFlags, StyleRelations};
@@ -382,27 +381,16 @@ impl<'le> GeckoElement<'le> {
     }
 
     /// Creates a blank snapshot for this element.
     pub fn create_snapshot(&self) -> Snapshot {
         Snapshot::new(*self)
     }
 }
 
-lazy_static! {
-    /// A dummy url data in order to get it where we don't have any available.
-    ///
-    /// We need to get rid of this sooner than later.
-    pub static ref DUMMY_URL_DATA: RefPtr<URLExtraData> = {
-        unsafe {
-            RefPtr::from_addrefed(bindings::Gecko_URLExtraData_CreateDummy())
-        }
-    };
-}
-
 /// Converts flags from the layout used by rust-selectors to the layout used
 /// by Gecko. We could align these and then do this without conditionals, but
 /// it's probably not worth the trouble.
 fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
     use gecko_bindings::structs::*;
     use selectors::matching::*;
     let mut gecko_flags = 0u32;
     if flags.contains(HAS_SLOW_SELECTOR) {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -20,17 +20,16 @@ use style::data::{ElementData, ElementSt
 use style::dom::{AnimationOnlyDirtyDescendants, DirtyDescendants};
 use style::dom::{ShowSubtreeData, TElement, TNode};
 use style::error_reporting::StdoutErrorReporter;
 use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl};
 use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
 use style::gecko::restyle_damage::GeckoRestyleDamage;
 use style::gecko::selector_parser::{SelectorImpl, PseudoElement};
 use style::gecko::traversal::RecalcStyleOnly;
-use style::gecko::wrapper::DUMMY_URL_DATA;
 use style::gecko::wrapper::GeckoElement;
 use style::gecko_bindings::bindings;
 use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
 use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
 use style::gecko_bindings::bindings::{RawServoMediaListBorrowed, RawServoMediaListStrong};
 use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoStyleRule, RawServoStyleRuleBorrowed};
@@ -92,17 +91,19 @@ use super::stylesheet_loader::Stylesheet
 /*
  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
  * depend on but good enough for our purposes.
  */
 
-
+// A dummy url data for where we don't pass url data in.
+// We need to get rid of this sooner than later.
+static mut DUMMY_URL_DATA: Option<*mut URLExtraData> = None;
 
 #[no_mangle]
 pub extern "C" fn Servo_Initialize() {
     // Initialize logging.
     let mut builder = LogBuilder::new();
     let default_level = if cfg!(debug_assertions) { "warn" } else { "error" };
     match env::var("RUST_LOG") {
       Ok(v) => builder.parse(&v).init().unwrap(),
@@ -112,22 +113,34 @@ pub extern "C" fn Servo_Initialize() {
     // Pretend that we're a Servo Layout thread, to make some assertions happy.
     thread_state::initialize(thread_state::LAYOUT);
 
     // Perform some debug-only runtime assertions.
     restyle_hints::assert_restyle_hints_match();
 
     // Initialize some static data.
     gecko_properties::initialize();
+
+    // Initialize the dummy url data
+    unsafe {
+        DUMMY_URL_DATA = Some(bindings::Gecko_URLExtraData_CreateDummy());
+    }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_Shutdown() {
     // Clear some static data to avoid shutdown leaks.
     gecko_properties::shutdown();
+
+    // Clear the dummy url data to avoid shutdown leaks.
+    unsafe { RefPtr::from_addrefed(DUMMY_URL_DATA.take().unwrap()) };
+}
+
+unsafe fn dummy_url_data() -> &'static RefPtr<URLExtraData> {
+    RefPtr::from_ptr_ref(DUMMY_URL_DATA.as_ref().unwrap())
 }
 
 fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard,
                              per_doc_data: &PerDocumentStyleDataImpl,
                              animation_only: bool) -> SharedStyleContext<'a> {
     let local_context_data =
         ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
 
@@ -312,18 +325,18 @@ pub extern "C" fn Servo_StyleSheet_Empty
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let origin = match mode {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
     };
     let shared_lock = global_style_data.shared_lock.clone();
     Arc::new(Stylesheet::from_str(
-        "", DUMMY_URL_DATA.clone(), origin, Default::default(),
-        shared_lock, None, &StdoutErrorReporter)
+        "", unsafe { dummy_url_data() }.clone(), origin,
+        Default::default(), shared_lock, None, &StdoutErrorReporter)
     ).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
                                                  stylesheet: *mut ServoStyleSheet,
                                                  data: *const nsACString,
                                                  mode: SheetParsingMode,
@@ -1318,27 +1331,27 @@ pub extern "C" fn Servo_CSSSupports2(pro
     let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };
     let id =  if let Ok(id) = PropertyId::parse(property.into()) {
         id
     } else {
         return false
     };
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
-    let url_data = &*DUMMY_URL_DATA;
+    let url_data = unsafe { dummy_url_data() };
     parse_one_declaration(id, &value, url_data, &StdoutErrorReporter).is_ok()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool {
     let condition = unsafe { cond.as_ref().unwrap().as_str_unchecked() };
     let mut input = Parser::new(&condition);
     let cond = parse_condition_or_declaration(&mut input);
     if let Ok(cond) = cond {
-        let url_data = &*DUMMY_URL_DATA;
+        let url_data = unsafe { dummy_url_data() };
         let reporter = StdoutErrorReporter;
         let context = ParserContext::new_for_cssom(url_data, &reporter);
         cond.eval(&context)
     } else {
         false
     }
 }