Bug 1382190 - servo: Move FontComputationData to the end of ServoComputedValues to make size check easier, make it NonZero ; r?emilio draft
authorManish Goregaokar <manishearth@gmail.com>
Wed, 19 Jul 2017 18:28:25 -0700
changeset 612359 ee4639fc7813b830ea4d25e3ae4949d87a3335c4
parent 611714 eb1d92b2b6a4161492561250f51bae5bafeda68a
child 638391 e55e9496f116c50b0b3da4d954944e61409f9dd2
push id69478
push userbmo:manishearth@gmail.com
push dateThu, 20 Jul 2017 17:01:35 +0000
reviewersemilio
bugs1382190
milestone56.0a1
Bug 1382190 - servo: Move FontComputationData to the end of ServoComputedValues to make size check easier, make it NonZero ; r?emilio We fail bindgen layout tests on 32 bit because FontComputationData does not accurately reflect the size/alignment of the rust-side replacement. We move it to the end so that alignment is more straightforward, and use a NonZero enum so that the representation can be more accurately handled on the C++ side. MozReview-Commit-ID: 8GlSma3Wl9W
layout/style/ServoTypes.h
servo/components/style/gecko/generated/bindings.rs
servo/components/style/gecko/generated/structs_debug.rs
servo/components/style/gecko/generated/structs_release.rs
servo/components/style/properties/longhand/font.mako.rs
--- a/layout/style/ServoTypes.h
+++ b/layout/style/ServoTypes.h
@@ -131,20 +131,42 @@ enum class InheritTarget {
   // We're requesting a style for a placeholder frame.
   PlaceholderFrame,
 };
 
 struct ServoWritingMode {
   uint8_t mBits;
 };
 
+// Don't attempt to read from this
+// (see comment on ServoFontComputationData
+enum ServoKeywordSize {
+  Empty, // when the Option is None
+  XXSmall,
+  XSmall,
+  Small,
+  Medium,
+  Large,
+  XLarge,
+  XXLarge,
+  XXXLarge,
+};
+
+// Don't attempt to read from this. We can't
+// always guarantee that the interior representation
+// of this is correct (the mKeyword field may have a different padding),
+// but the entire struct should
+// have the same size and alignment as the Rust version.
+// Ensure layout tests get run if touching either side.
 struct ServoFontComputationData {
-  // 8 bytes, but is done as 4+4 for alignment
-  uint32_t mFour;
-  uint32_t mFour2;
+private:
+  ServoKeywordSize mKeyword;
+  float/*32_t*/ mRatio;
+
+  static_assert(sizeof(float) == 4, "float should be 32 bit");
 };
 
 struct ServoCustomPropertiesMap {
   uintptr_t mPtr;
 };
 
 struct ServoRuleNode {
   uintptr_t mPtr;
@@ -201,26 +223,33 @@ struct ServoComputedValues {
   inline const nsStyle##name_* GetStyle##name_() const;
   #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
   const nsStyleVariables* GetStyleVariables() const;
   mozilla::ServoCustomPropertiesMap custom_properties;
   mozilla::ServoWritingMode writing_mode;
-  mozilla::ServoFontComputationData font_computation_data;
+  mozilla::ServoComputedValueFlags flags;
   /// The rule node representing the ordered list of rules matched for this
   /// node.  Can be None for default values and text nodes.  This is
   /// essentially an optimization to avoid referencing the root rule node.
   mozilla::ServoRuleNode rules;
   /// The element's computed values if visited, only computed if there's a
   /// relevant link for this element. A element's "relevant link" is the
   /// element being matched if it is a link or the nearest ancestor link.
   mozilla::ServoVisitedStyle visited_style;
-  mozilla::ServoComputedValueFlags flags;
+
+  // this is the last member because most of the other members
+  // are pointer sized. This makes it easier to deal with the
+  // alignment of the fields when replacing things via bindgen
+  //
+  // This is opaque, please don't read from it from C++
+  // (see comment on ServoFontComputationData)
+  mozilla::ServoFontComputationData font_computation_data;
 
   // C++ just sees this struct as a bucket of bits, and will
   // do the wrong thing if we let it use the default copy ctor/assignment
   // operator. Remove them so that there is no footgun.
   //
   // We remove the move ctor/assignment operator as well, because
   // moves in C++ don't prevent destructors from being called,
   // which will lead to double frees.
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1967,20 +1967,20 @@ extern "C" {
                                                      RawServoStyleSetBorrowed,
                                                  parent_style:
                                                      ServoStyleContextBorrowedOrNull,
                                                  declarations:
                                                      RawServoDeclarationBlockBorrowed)
      -> ServoStyleContextStrong;
 }
 extern "C" {
-    pub fn Servo_StyleContext_AddRef(ctx: ServoStyleContextBorrowed);
-}
-extern "C" {
-    pub fn Servo_StyleContext_Release(ctx: ServoStyleContextBorrowed);
+    pub fn Servo_StyleContext_AddRef(ctx: &ServoStyleContext);
+}
+extern "C" {
+    pub fn Servo_StyleContext_Release(ctx: &ServoStyleContext);
 }
 extern "C" {
     pub fn Servo_StyleSet_MightHaveAttributeDependency(set:
                                                            RawServoStyleSetBorrowed,
                                                        element:
                                                            RawGeckoElementBorrowed,
                                                        local_name:
                                                            *mut nsIAtom)
--- a/servo/components/style/gecko/generated/structs_debug.rs
+++ b/servo/components/style/gecko/generated/structs_debug.rs
@@ -7587,26 +7587,39 @@ pub mod root {
         pub type ParsingMode = u8;
         #[repr(i32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum InheritTarget {
             Text = 0,
             FirstLetterContinuation = 1,
             PlaceholderFrame = 2,
         }
+        #[repr(u32)]
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+        pub enum ServoKeywordSize {
+            Empty = 0,
+            XXSmall = 1,
+            XSmall = 2,
+            Small = 3,
+            Medium = 4,
+            Large = 5,
+            XLarge = 6,
+            XXLarge = 7,
+            XXXLarge = 8,
+        }
         #[repr(C)]
         #[derive(Debug)]
         pub struct ServoStyleContext {
             pub _base: root::nsStyleContext,
             pub mPresContext: *mut root::nsPresContext,
             pub mSource: root::ServoComputedValues,
         }
         #[test]
         fn bindgen_test_layout_ServoStyleContext() {
-            assert_eq!(::std::mem::size_of::<ServoStyleContext>() , 272usize ,
+            assert_eq!(::std::mem::size_of::<ServoStyleContext>() , 264usize ,
                        concat ! (
                        "Size of: " , stringify ! ( ServoStyleContext ) ));
             assert_eq! (::std::mem::align_of::<ServoStyleContext>() , 8usize ,
                         concat ! (
                         "Alignment of " , stringify ! ( ServoStyleContext )
                         ));
             assert_eq! (unsafe {
                         & ( * ( 0 as * const ServoStyleContext ) ) .
@@ -21163,30 +21176,30 @@ pub mod root {
         pub Border: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoBorder>,
         pub Outline: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoOutline>,
         pub XUL: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoXUL>,
         pub SVGReset: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoSVGReset>,
         pub Column: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoColumn>,
         pub Effects: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoEffects>,
         pub custom_properties: ::gecko_bindings::structs::ServoCustomPropertiesMap,
         pub writing_mode: ::gecko_bindings::structs::ServoWritingMode,
-        pub font_computation_data: ::gecko_bindings::structs::ServoFontComputationData,
+        pub flags: ::gecko_bindings::structs::ServoComputedValueFlags,
         /// The rule node representing the ordered list of rules matched for this
   /// node.  Can be None for default values and text nodes.  This is
   /// essentially an optimization to avoid referencing the root rule node.
         pub rules: ::gecko_bindings::structs::ServoRuleNode,
         /// The element's computed values if visited, only computed if there's a
   /// relevant link for this element. A element's "relevant link" is the
   /// element being matched if it is a link or the nearest ancestor link.
         pub visited_style: ::gecko_bindings::structs::ServoVisitedStyle,
-        pub flags: ::gecko_bindings::structs::ServoComputedValueFlags,
+        pub font_computation_data: ::gecko_bindings::structs::ServoFontComputationData,
     }
     #[test]
     fn bindgen_test_layout_ServoComputedValues() {
-        assert_eq!(::std::mem::size_of::<ServoComputedValues>() , 232usize ,
+        assert_eq!(::std::mem::size_of::<ServoComputedValues>() , 224usize ,
                    concat ! (
                    "Size of: " , stringify ! ( ServoComputedValues ) ));
         assert_eq! (::std::mem::align_of::<ServoComputedValues>() , 8usize ,
                     concat ! (
                     "Alignment of " , stringify ! ( ServoComputedValues ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) . Font as *
                     const _ as usize } , 0usize , concat ! (
@@ -21311,37 +21324,37 @@ pub mod root {
                     ) , "::" , stringify ! ( custom_properties ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) .
                     writing_mode as * const _ as usize } , 192usize , concat !
                     (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( writing_mode ) ));
         assert_eq! (unsafe {
-                    & ( * ( 0 as * const ServoComputedValues ) ) .
-                    font_computation_data as * const _ as usize } , 196usize ,
-                    concat ! (
+                    & ( * ( 0 as * const ServoComputedValues ) ) . flags as *
+                    const _ as usize } , 193usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
-                    ) , "::" , stringify ! ( font_computation_data ) ));
+                    ) , "::" , stringify ! ( flags ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) . rules as *
-                    const _ as usize } , 208usize , concat ! (
+                    const _ as usize } , 200usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( rules ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) .
-                    visited_style as * const _ as usize } , 216usize , concat
+                    visited_style as * const _ as usize } , 208usize , concat
                     ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( visited_style ) ));
         assert_eq! (unsafe {
-                    & ( * ( 0 as * const ServoComputedValues ) ) . flags as *
-                    const _ as usize } , 224usize , concat ! (
+                    & ( * ( 0 as * const ServoComputedValues ) ) .
+                    font_computation_data as * const _ as usize } , 216usize ,
+                    concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
-                    ) , "::" , stringify ! ( flags ) ));
+                    ) , "::" , stringify ! ( font_computation_data ) ));
     }
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct ServoComputedValuesForgotten {
         pub mPtr: *const root::ServoComputedValues,
     }
     #[test]
     fn bindgen_test_layout_ServoComputedValuesForgotten() {
@@ -40292,26 +40305,17 @@ pub mod root {
                    "Size of template specialization: " , stringify ! (
                    root::nsCharTraits ) ));
         assert_eq!(::std::mem::align_of::<root::nsCharTraits>() , 1usize ,
                    concat ! (
                    "Alignment of template specialization: " , stringify ! (
                    root::nsCharTraits ) ));
     }
     #[test]
-    fn __bindgen_test_layout__bindgen_ty_id_197796_instantiation_98() {
-        assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
-                   "Size of template specialization: " , stringify ! ( u8 )
-                   ));
-        assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
-                   "Alignment of template specialization: " , stringify ! ( u8
-                   ) ));
-    }
-    #[test]
-    fn __bindgen_test_layout__bindgen_ty_id_197832_instantiation_99() {
+    fn __bindgen_test_layout__bindgen_ty_id_195387_instantiation_34() {
         assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
                    "Size of template specialization: " , stringify ! ( u8 )
                    ));
         assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
                    "Alignment of template specialization: " , stringify ! ( u8
                    ) ));
     }
     #[test]
--- a/servo/components/style/gecko/generated/structs_release.rs
+++ b/servo/components/style/gecko/generated/structs_release.rs
@@ -7435,26 +7435,39 @@ pub mod root {
         pub type ParsingMode = u8;
         #[repr(i32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum InheritTarget {
             Text = 0,
             FirstLetterContinuation = 1,
             PlaceholderFrame = 2,
         }
+        #[repr(u32)]
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+        pub enum ServoKeywordSize {
+            Empty = 0,
+            XXSmall = 1,
+            XSmall = 2,
+            Small = 3,
+            Medium = 4,
+            Large = 5,
+            XLarge = 6,
+            XXLarge = 7,
+            XXXLarge = 8,
+        }
         #[repr(C)]
         #[derive(Debug)]
         pub struct ServoStyleContext {
             pub _base: root::nsStyleContext,
             pub mPresContext: *mut root::nsPresContext,
             pub mSource: root::ServoComputedValues,
         }
         #[test]
         fn bindgen_test_layout_ServoStyleContext() {
-            assert_eq!(::std::mem::size_of::<ServoStyleContext>() , 272usize ,
+            assert_eq!(::std::mem::size_of::<ServoStyleContext>() , 264usize ,
                        concat ! (
                        "Size of: " , stringify ! ( ServoStyleContext ) ));
             assert_eq! (::std::mem::align_of::<ServoStyleContext>() , 8usize ,
                         concat ! (
                         "Alignment of " , stringify ! ( ServoStyleContext )
                         ));
             assert_eq! (unsafe {
                         & ( * ( 0 as * const ServoStyleContext ) ) .
@@ -20779,30 +20792,30 @@ pub mod root {
         pub Border: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoBorder>,
         pub Outline: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoOutline>,
         pub XUL: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoXUL>,
         pub SVGReset: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoSVGReset>,
         pub Column: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoColumn>,
         pub Effects: ::gecko_bindings::structs::ServoRawOffsetArc<root::mozilla::GeckoEffects>,
         pub custom_properties: ::gecko_bindings::structs::ServoCustomPropertiesMap,
         pub writing_mode: ::gecko_bindings::structs::ServoWritingMode,
-        pub font_computation_data: ::gecko_bindings::structs::ServoFontComputationData,
+        pub flags: ::gecko_bindings::structs::ServoComputedValueFlags,
         /// The rule node representing the ordered list of rules matched for this
   /// node.  Can be None for default values and text nodes.  This is
   /// essentially an optimization to avoid referencing the root rule node.
         pub rules: ::gecko_bindings::structs::ServoRuleNode,
         /// The element's computed values if visited, only computed if there's a
   /// relevant link for this element. A element's "relevant link" is the
   /// element being matched if it is a link or the nearest ancestor link.
         pub visited_style: ::gecko_bindings::structs::ServoVisitedStyle,
-        pub flags: ::gecko_bindings::structs::ServoComputedValueFlags,
+        pub font_computation_data: ::gecko_bindings::structs::ServoFontComputationData,
     }
     #[test]
     fn bindgen_test_layout_ServoComputedValues() {
-        assert_eq!(::std::mem::size_of::<ServoComputedValues>() , 232usize ,
+        assert_eq!(::std::mem::size_of::<ServoComputedValues>() , 224usize ,
                    concat ! (
                    "Size of: " , stringify ! ( ServoComputedValues ) ));
         assert_eq! (::std::mem::align_of::<ServoComputedValues>() , 8usize ,
                     concat ! (
                     "Alignment of " , stringify ! ( ServoComputedValues ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) . Font as *
                     const _ as usize } , 0usize , concat ! (
@@ -20927,37 +20940,37 @@ pub mod root {
                     ) , "::" , stringify ! ( custom_properties ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) .
                     writing_mode as * const _ as usize } , 192usize , concat !
                     (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( writing_mode ) ));
         assert_eq! (unsafe {
-                    & ( * ( 0 as * const ServoComputedValues ) ) .
-                    font_computation_data as * const _ as usize } , 196usize ,
-                    concat ! (
+                    & ( * ( 0 as * const ServoComputedValues ) ) . flags as *
+                    const _ as usize } , 193usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
-                    ) , "::" , stringify ! ( font_computation_data ) ));
+                    ) , "::" , stringify ! ( flags ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) . rules as *
-                    const _ as usize } , 208usize , concat ! (
+                    const _ as usize } , 200usize , concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( rules ) ));
         assert_eq! (unsafe {
                     & ( * ( 0 as * const ServoComputedValues ) ) .
-                    visited_style as * const _ as usize } , 216usize , concat
+                    visited_style as * const _ as usize } , 208usize , concat
                     ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
                     ) , "::" , stringify ! ( visited_style ) ));
         assert_eq! (unsafe {
-                    & ( * ( 0 as * const ServoComputedValues ) ) . flags as *
-                    const _ as usize } , 224usize , concat ! (
+                    & ( * ( 0 as * const ServoComputedValues ) ) .
+                    font_computation_data as * const _ as usize } , 216usize ,
+                    concat ! (
                     "Alignment of field: " , stringify ! ( ServoComputedValues
-                    ) , "::" , stringify ! ( flags ) ));
+                    ) , "::" , stringify ! ( font_computation_data ) ));
     }
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct ServoComputedValuesForgotten {
         pub mPtr: *const root::ServoComputedValues,
     }
     #[test]
     fn bindgen_test_layout_ServoComputedValuesForgotten() {
@@ -39601,26 +39614,26 @@ pub mod root {
                    "Size of template specialization: " , stringify ! (
                    root::nsCharTraits ) ));
         assert_eq!(::std::mem::align_of::<root::nsCharTraits>() , 1usize ,
                    concat ! (
                    "Alignment of template specialization: " , stringify ! (
                    root::nsCharTraits ) ));
     }
     #[test]
-    fn __bindgen_test_layout__bindgen_ty_id_193581_instantiation_92() {
+    fn __bindgen_test_layout__bindgen_ty_id_192873_instantiation_33() {
         assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
                    "Size of template specialization: " , stringify ! ( u8 )
                    ));
         assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
                    "Alignment of template specialization: " , stringify ! ( u8
                    ) ));
     }
     #[test]
-    fn __bindgen_test_layout__bindgen_ty_id_193617_instantiation_93() {
+    fn __bindgen_test_layout__bindgen_ty_id_192909_instantiation_34() {
         assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
                    "Size of template specialization: " , stringify ! ( u8 )
                    ));
         assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
                    "Alignment of template specialization: " , stringify ! ( u8
                    ) ));
     }
     #[test]
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -616,42 +616,57 @@ macro_rules! impl_gecko_keyword_conversi
         use app_units::Au;
         pub type T = Au;
     }
 
     /// CSS font keywords
     #[derive(Debug, Copy, Clone, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub enum KeywordSize {
-        XXSmall = 0,
-        XSmall = 1,
-        Small = 2,
-        Medium = 3,
-        Large = 4,
-        XLarge = 5,
-        XXLarge = 6,
+        XXSmall = 1, // This is to enable the NonZero optimization
+                     // which simplifies the representation of Option<KeywordSize>
+                     // in bindgen
+        XSmall,
+        Small,
+        Medium,
+        Large,
+        XLarge,
+        XXLarge,
         // This is not a real font keyword and will not parse
         // HTML font-size 7 corresponds to this value
-        XXXLarge = 7,
+        XXXLarge,
     }
 
     pub use self::KeywordSize::*;
 
     impl KeywordSize {
         pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
             try_match_ident_ignore_ascii_case! { input.expect_ident()?,
                 "xx-small" => Ok(XXSmall),
                 "x-small" => Ok(XSmall),
                 "small" => Ok(Small),
                 "medium" => Ok(Medium),
                 "large" => Ok(Large),
                 "x-large" => Ok(XLarge),
                 "xx-large" => Ok(XXLarge),
             }
         }
+
+        pub fn html_size(&self) -> u8 {
+            match *self {
+                KeywordSize::XXSmall => 0,
+                KeywordSize::XSmall => 1,
+                KeywordSize::Small => 2,
+                KeywordSize::Medium => 3,
+                KeywordSize::Large => 4,
+                KeywordSize::XLarge => 5,
+                KeywordSize::XXLarge => 6,
+                KeywordSize::XXXLarge => 7,
+            }
+        }
     }
 
     impl Default for KeywordSize {
         fn default() -> Self {
             Medium
         }
     }
 
@@ -727,17 +742,17 @@ macro_rules! impl_gecko_keyword_conversi
                 // XXXManishearth handle quirks mode
 
                 let ref gecko_font = cx.style().get_font().gecko();
                 let base_size = unsafe { Atom::with(gecko_font.mLanguage.raw::<nsIAtom>(), |atom| {
                     cx.font_metrics_provider.get_size(atom, gecko_font.mGenericID).0
                 }) };
 
                 let base_size_px = au_to_int_px(base_size as f32);
-                let html_size = *self as usize;
+                let html_size = self.html_size() as usize;
                 if base_size_px >= 9 && base_size_px <= 16 {
                     Au::from_px(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size])
                 } else {
                     Au(FONT_SIZE_FACTORS[html_size] * base_size / 100)
                 }
             }
 
             #[inline]