Skip to content
Permalink
Browse files

style: Use atom handles in favour of atom pointers in style system code.

  • Loading branch information...
heycam authored and emilio committed Jan 7, 2019
1 parent 160842b commit 63fd707bd342d614fa620415bb1062b3a40a2488
@@ -29,7 +29,6 @@ arrayvec = "0.4.6"
atomic_refcell = "0.1" atomic_refcell = "0.1"
bitflags = "1.0" bitflags = "1.0"
byteorder = "1.0" byteorder = "1.0"
cfg-if = "0.1.0"
cssparser = "0.25" cssparser = "0.25"
crossbeam-channel = { version = "0.3", optional = true } crossbeam-channel = { version = "0.3", optional = true }
new_debug_unreachable = "1.0" new_debug_unreachable = "1.0"
@@ -122,51 +122,10 @@ def __exit__(self, type, value, traceback):
// DO NOT EDIT DIRECTLY // DO NOT EDIT DIRECTLY
'''[1:] '''[1:]


IMPORTS = '''
use gecko_bindings::structs::nsStaticAtom;
use string_cache::Atom;
'''

UNSAFE_STATIC = '''
#[inline(always)]
pub unsafe fn atom_from_static(ptr: *const nsStaticAtom) -> Atom {
Atom::from_static(ptr)
}
'''

SATOMS_TEMPLATE = '''
#[link_name = \"{link_name}\"]
pub static nsGkAtoms_sAtoms: *const nsStaticAtom;
'''[1:]

CFG_IF_TEMPLATE = '''
cfg_if! {{
if #[cfg(not(target_env = "msvc"))] {{
extern {{
{gnu}\
}}
}} else if #[cfg(target_pointer_width = "64")] {{
extern {{
{msvc64}\
}}
}} else {{
extern {{
{msvc32}\
}}
}}
}}\n
'''

CONST_TEMPLATE = '''
pub const k_{name}: isize = {index};
'''[1:]

RULE_TEMPLATE = ''' RULE_TEMPLATE = '''
("{atom}") => ("{atom}") => {{{{
{{{{
use $crate::string_cache::atom_macro;
#[allow(unsafe_code)] #[allow(unused_unsafe)] #[allow(unsafe_code)] #[allow(unused_unsafe)]
unsafe {{ atom_macro::atom_from_static(atom_macro::nsGkAtoms_sAtoms.offset(atom_macro::k_{name})) }} unsafe {{ $crate::string_cache::Atom::from_index({index}) }}
}}}}; }}}};
'''[1:] '''[1:]


@@ -180,26 +139,8 @@ def __exit__(self, type, value, traceback):
def write_atom_macro(atoms, file_name): def write_atom_macro(atoms, file_name):
with FileAvoidWrite(file_name) as f: with FileAvoidWrite(file_name) as f:
f.write(PRELUDE) f.write(PRELUDE)
f.write(IMPORTS) macro_rules = [RULE_TEMPLATE.format(atom=atom.value, name=atom.ident, index=i)
f.write(UNSAFE_STATIC) for (i, atom) in enumerate(atoms)]

gnu_name='_ZN9nsGkAtoms6sAtomsE'
gnu_symbols = SATOMS_TEMPLATE.format(link_name=gnu_name)

# Prepend "\x01" to avoid LLVM prefixing the mangled name with "_".
# See https://github.com/rust-lang/rust/issues/36097
msvc32_name = '\\x01?sAtoms@nsGkAtoms@@0QBVnsStaticAtom@@B'
msvc32_symbols = SATOMS_TEMPLATE.format(link_name=msvc32_name)

msvc64_name = '?sAtoms@nsGkAtoms@@0QEBVnsStaticAtom@@EB'
msvc64_symbols = SATOMS_TEMPLATE.format(link_name=msvc64_name)

f.write(CFG_IF_TEMPLATE.format(gnu=gnu_symbols, msvc32=msvc32_symbols, msvc64=msvc64_symbols))

consts = [CONST_TEMPLATE.format(name=atom.ident, index=i) for (i, atom) in enumerate(atoms)]
f.write('{}'.format(''.join(consts)))

macro_rules = [RULE_TEMPLATE.format(atom=atom.value, name=atom.ident) for atom in atoms]
f.write(MACRO_TEMPLATE.format(body=''.join(macro_rules))) f.write(MACRO_TEMPLATE.format(body=''.join(macro_rules)))




@@ -15,6 +15,7 @@ use crate::gecko_bindings::bindings::Gecko_Atomize;
use crate::gecko_bindings::bindings::Gecko_Atomize16; use crate::gecko_bindings::bindings::Gecko_Atomize16;
use crate::gecko_bindings::bindings::Gecko_ReleaseAtom; use crate::gecko_bindings::bindings::Gecko_ReleaseAtom;
use crate::gecko_bindings::structs::{nsAtom, nsDynamicAtom, nsStaticAtom}; use crate::gecko_bindings::structs::{nsAtom, nsDynamicAtom, nsStaticAtom};
use crate::gecko_bindings::structs::root::mozilla::detail::gGkAtoms;
use nsstring::{nsAString, nsStr}; use nsstring::{nsAString, nsStr};
use precomputed_hash::PrecomputedHash; use precomputed_hash::PrecomputedHash;
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
@@ -43,22 +44,44 @@ macro_rules! local_name {
}; };
} }


/// A strong reference to a Gecko atom. /// A handle to a Gecko atom.
///
/// This is either a strong reference to a dynamic atom (an nsAtom pointer),
/// or an offset from gGkAtoms to the nsStaticAtom object.
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
pub struct Atom(*mut WeakAtom); pub struct Atom(usize);


/// An atom *without* a strong reference. /// An atom *without* a strong reference.
/// ///
/// Only usable as `&'a WeakAtom`, /// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom. /// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsAtom); pub struct WeakAtom(nsAtom);


#[inline]
fn valid_static_atom_addr(addr: usize) -> bool {
unsafe {
let start = gGkAtoms.mAtoms.get_unchecked(0) as *const _;
let end = gGkAtoms.mAtoms.get_unchecked(gGkAtoms.mAtoms.len()) as *const _;
let in_range = addr >= start as usize && addr < end as usize;
let aligned = addr % mem::align_of::<nsStaticAtom>() == 0;
in_range && aligned
}
}

impl Deref for Atom { impl Deref for Atom {
type Target = WeakAtom; type Target = WeakAtom;


#[inline] #[inline]
fn deref(&self) -> &WeakAtom { fn deref(&self) -> &WeakAtom {
unsafe { &*self.0 } unsafe {
let addr = if self.is_static() {
(&gGkAtoms as *const _ as usize) + (self.0 >> 1)
} else {
self.0
};
debug_assert!(!self.is_static() || valid_static_atom_addr(addr));
WeakAtom::new(addr as *const nsAtom)
}
} }
} }


@@ -277,50 +300,73 @@ impl fmt::Display for WeakAtom {
} }
} }


#[inline]
unsafe fn make_handle(ptr: *const nsAtom) -> usize {
debug_assert!(!ptr.is_null());
if !WeakAtom::new(ptr).is_static() {
ptr as usize
} else {
make_static_handle(ptr as *mut nsStaticAtom)
}
}

#[inline]
unsafe fn make_static_handle(ptr: *const nsStaticAtom) -> usize {
// FIXME(heycam): Use offset_from once it's stabilized.
// https://github.com/rust-lang/rust/issues/41079
debug_assert!(valid_static_atom_addr(ptr as usize));
let base = &gGkAtoms as *const _;
let offset = ptr as usize - base as usize;
(offset << 1) | 1
}

impl Atom { impl Atom {
#[inline]
fn is_static(&self) -> bool {
self.0 & 1 == 1
}

/// Execute a callback with the atom represented by `ptr`. /// Execute a callback with the atom represented by `ptr`.
pub unsafe fn with<F, R>(ptr: *const nsAtom, callback: F) -> R pub unsafe fn with<F, R>(ptr: *const nsAtom, callback: F) -> R
where where
F: FnOnce(&Atom) -> R, F: FnOnce(&Atom) -> R,
{ {
let atom = Atom(WeakAtom::new(ptr)); let atom = Atom(make_handle(ptr as *mut nsAtom));
let ret = callback(&atom); let ret = callback(&atom);
mem::forget(atom); mem::forget(atom);
ret ret
} }


/// Creates an atom from an static atom pointer without checking in release /// Creates a static atom from its index in the static atom table, without
/// builds. /// checking in release builds.
///
/// Right now it's only used by the atom macro, and ideally it should keep
/// that way, now we have sugar for is_static, creating atoms using
/// Atom::from_raw should involve almost no overhead.
#[inline] #[inline]
pub unsafe fn from_static(ptr: *const nsStaticAtom) -> Self { pub unsafe fn from_index(index: u16) -> Self {
let atom = Atom(ptr as *mut WeakAtom); let ptr = gGkAtoms.mAtoms.get_unchecked(index as usize) as *const _;
debug_assert!( let handle = make_static_handle(ptr);
atom.is_static(), let atom = Atom(handle);
"Called from_static for a non-static atom!" debug_assert!(valid_static_atom_addr(ptr as usize));
); debug_assert!(atom.is_static());
debug_assert!((*atom).is_static());
debug_assert!(handle == make_handle(atom.as_ptr()));
atom atom
} }


/// Creates an atom from an atom pointer. /// Creates an atom from an atom pointer.
#[inline(always)] #[inline(always)]
pub unsafe fn from_raw(ptr: *mut nsAtom) -> Self { pub unsafe fn from_raw(ptr: *mut nsAtom) -> Self {
let atom = Atom(ptr as *mut WeakAtom); let atom = Atom(make_handle(ptr));
if !atom.is_static() { if !atom.is_static() {
Gecko_AddRefAtom(ptr); Gecko_AddRefAtom(ptr);
} }
atom atom
} }


/// Creates an atom from a dynamic atom pointer that has already had AddRef /// Creates an atom from an atom pointer that has already had AddRef
/// called on it. /// called on it. This may be a static or dynamic atom.
#[inline] #[inline]
pub unsafe fn from_addrefed(ptr: *mut nsAtom) -> Self { pub unsafe fn from_addrefed(ptr: *mut nsAtom) -> Self {
assert!(!ptr.is_null()); assert!(!ptr.is_null());
Atom(WeakAtom::new(ptr)) Atom(make_handle(ptr))
} }


/// Convert this atom into an addrefed nsAtom pointer. /// Convert this atom into an addrefed nsAtom pointer.
@@ -353,7 +399,13 @@ impl Hash for WeakAtom {
impl Clone for Atom { impl Clone for Atom {
#[inline(always)] #[inline(always)]
fn clone(&self) -> Atom { fn clone(&self) -> Atom {
unsafe { Atom::from_raw(self.as_ptr()) } unsafe {
let atom = Atom(self.0);
if !atom.is_static() {
Gecko_AddRefAtom(atom.as_ptr());
}
atom
}
} }
} }


@@ -377,13 +429,13 @@ impl Default for Atom {


impl fmt::Debug for Atom { impl fmt::Debug for Atom {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
write!(w, "Gecko Atom({:p}, {})", self.0, self) write!(w, "Atom(0x{:08x}, {})", self.0, self)
} }
} }


impl fmt::Display for Atom { impl fmt::Display for Atom {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
unsafe { (&*self.0).fmt(w) } self.deref().fmt(w)
} }
} }


@@ -392,10 +444,10 @@ impl<'a> From<&'a str> for Atom {
fn from(string: &str) -> Atom { fn from(string: &str) -> Atom {
debug_assert!(string.len() <= u32::max_value() as usize); debug_assert!(string.len() <= u32::max_value() as usize);
unsafe { unsafe {
Atom(WeakAtom::new(Gecko_Atomize( Atom::from_addrefed(Gecko_Atomize(
string.as_ptr() as *const _, string.as_ptr() as *const _,
string.len() as u32, string.len() as u32,
))) ))
} }
} }
} }
@@ -410,7 +462,7 @@ impl<'a> From<&'a [u16]> for Atom {
impl<'a> From<&'a nsAString> for Atom { impl<'a> From<&'a nsAString> for Atom {
#[inline] #[inline]
fn from(string: &nsAString) -> Atom { fn from(string: &nsAString) -> Atom {
unsafe { Atom(WeakAtom::new(Gecko_Atomize16(string))) } unsafe { Atom::from_addrefed(Gecko_Atomize16(string)) }
} }
} }


@@ -32,10 +32,6 @@ extern crate atomic_refcell;
extern crate bitflags; extern crate bitflags;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate byteorder; extern crate byteorder;
#[cfg(feature = "gecko")]
#[macro_use]
#[no_link]
extern crate cfg_if;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
extern crate crossbeam_channel; extern crate crossbeam_channel;
#[macro_use] #[macro_use]

0 comments on commit 63fd707

Please sign in to comment.
You can’t perform that action at this time.