Skip to content

Use an unsafe serializer. #1799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 77 additions & 11 deletions webrender_api/src/display_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use YuvImageDisplayItem;
use bincode;
use serde::{Deserialize, Serialize, Serializer};
use serde::ser::{SerializeMap, SerializeSeq};
use std::io::Write;
use std::{io, ptr};
use std::marker::PhantomData;
use time::precise_time_ns;

Expand Down Expand Up @@ -483,6 +485,72 @@ impl<'a, 'b> Serialize for DisplayItemRef<'a, 'b> {
}
}

// This is a replacement for bincode::serialize_into(&vec)
// The default implementation Write for Vec will basically
// call extend_from_slice(). Serde ends up calling that for every
// field of a struct that we're serializing. extend_from_slice()
// does not get inlined and thus we end up calling a generic memcpy()
// implementation. If we instead reserve enough room for the serialized
// struct in the Vec ahead of time we can rely on that and use
// the following UnsafeVecWriter to write into the vec without
// any checks. This writer assumes that size returned by the
// serialize function will not change between calls to serialize_into:
//
// For example, the following struct will cause memory unsafety when
// used with UnsafeVecWriter.
//
// struct S {
// first: Cell<bool>,
// }
//
// impl Serialize for S {
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
// where S: Serializer
// {
// if self.first.get() {
// self.first.set(false);
// ().serialize(serializer)
// } else {
// 0.serialize(serializer)
// }
// }
// }
//

struct UnsafeVecWriter<'a>(&'a mut Vec<u8>);

impl<'a> Write for UnsafeVecWriter<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let old_len = self.0.len();
self.0.set_len(old_len + buf.len());
debug_assert!(self.0.len() <= self.0.capacity());
ptr::copy_nonoverlapping(buf.as_ptr(), self.0.as_mut_ptr().offset(old_len as isize), buf.len());
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

struct SizeCounter(usize);

impl<'a> Write for SizeCounter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0 += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) {
// manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
let mut size = SizeCounter(0);
bincode::serialize_into(&mut size,e , bincode::Infinite).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space before e

vec.reserve(size.0);

bincode::serialize_into(&mut UnsafeVecWriter(vec), e, bincode::Infinite).unwrap();
}

#[derive(Clone)]
pub struct DisplayListBuilder {
pub data: Vec<u8>,
Expand Down Expand Up @@ -541,28 +609,26 @@ impl DisplayListBuilder {
}

fn push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo) {
bincode::serialize_into(
serialize_fast(
&mut self.data,
&DisplayItem {
item,
clip_and_scroll: *self.clip_stack.last().unwrap(),
info: *info,
},
bincode::Infinite,
).unwrap();
)
}

fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
let info = LayoutPrimitiveInfo::new(LayoutRect::zero());
bincode::serialize_into(
serialize_fast(
&mut self.data,
&DisplayItem {
item,
clip_and_scroll: *self.clip_stack.last().unwrap(),
info,
},
bincode::Infinite,
).unwrap();
}
)
}

fn push_iter<I>(&mut self, iter: I)
Expand All @@ -575,10 +641,10 @@ impl DisplayListBuilder {
let len = iter.len();
let mut count = 0;

bincode::serialize_into(&mut self.data, &len, bincode::Infinite).unwrap();
serialize_fast(&mut self.data, &len);
for elem in iter {
count += 1;
bincode::serialize_into(&mut self.data, &elem, bincode::Infinite).unwrap();
serialize_fast(&mut self.data, &elem);
}

debug_assert_eq!(len, count);
Expand Down Expand Up @@ -1103,8 +1169,8 @@ impl DisplayListBuilder {

// Append glyph data to the end
for ((font_key, color), sub_glyphs) in glyphs {
bincode::serialize_into(&mut self.data, &font_key, bincode::Infinite).unwrap();
bincode::serialize_into(&mut self.data, &color, bincode::Infinite).unwrap();
serialize_fast(&mut self.data, &font_key);
serialize_fast(&mut self.data, &color);
self.push_iter(sub_glyphs);
}

Expand Down