mirror of https://github.com/boa-dev/boa.git
Haled Odat
1 year ago
6 changed files with 403 additions and 360 deletions
@ -0,0 +1,113 @@ |
|||||||
|
use indexmap::IndexSet; |
||||||
|
|
||||||
|
use super::SnapshotError; |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub trait Deserialize: Sized { |
||||||
|
/// TODO: doc
|
||||||
|
fn deserialize(d: &mut SnapshotDeserializer<'_>) -> Result<Self, SnapshotError>; |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub struct SnapshotDeserializer<'snapshot> { |
||||||
|
pub(super) bytes: &'snapshot [u8], |
||||||
|
pub(super) index: usize, |
||||||
|
pub(super) external_references: &'snapshot IndexSet<usize>, |
||||||
|
} |
||||||
|
|
||||||
|
impl SnapshotDeserializer<'_> { |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_bool(&mut self) -> Result<bool, SnapshotError> { |
||||||
|
let byte = self.read_u8()?; |
||||||
|
assert!(byte == 0 || byte == 1); |
||||||
|
Ok(byte == 1) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_u8(&mut self) -> Result<u8, SnapshotError> { |
||||||
|
let byte = self.bytes[self.index]; |
||||||
|
self.index += 1; |
||||||
|
Ok(byte) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_i8(&mut self) -> Result<i8, SnapshotError> { |
||||||
|
let byte = self.bytes[self.index]; |
||||||
|
self.index += 1; |
||||||
|
Ok(byte as i8) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_u16(&mut self) -> Result<u16, SnapshotError> { |
||||||
|
let bytes = self.read_bytes(std::mem::size_of::<u16>())?; |
||||||
|
let value = u16::from_le_bytes([bytes[0], bytes[1]]); |
||||||
|
Ok(value) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_i16(&mut self) -> Result<i16, SnapshotError> { |
||||||
|
let value = self.read_u16()?; |
||||||
|
Ok(value as i16) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_u32(&mut self) -> Result<u32, SnapshotError> { |
||||||
|
let bytes = self.read_bytes(4)?; |
||||||
|
let value = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]); |
||||||
|
Ok(value) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_i32(&mut self) -> Result<i32, SnapshotError> { |
||||||
|
let value = self.read_u32()?; |
||||||
|
Ok(value as i32) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_f32(&mut self) -> Result<f32, SnapshotError> { |
||||||
|
let value = self.read_u32()?; |
||||||
|
Ok(f32::from_bits(value)) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_f64(&mut self) -> Result<f64, SnapshotError> { |
||||||
|
let value = self.read_u64()?; |
||||||
|
Ok(f64::from_bits(value)) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_u64(&mut self) -> Result<u64, SnapshotError> { |
||||||
|
let bytes = self.read_bytes(std::mem::size_of::<u64>())?; |
||||||
|
let value = u64::from_le_bytes([ |
||||||
|
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], |
||||||
|
]); |
||||||
|
Ok(value) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_i64(&mut self) -> Result<i64, SnapshotError> { |
||||||
|
let value = self.read_u64()?; |
||||||
|
Ok(value as i64) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_usize(&mut self) -> Result<usize, SnapshotError> { |
||||||
|
let value = self.read_u64()?; |
||||||
|
// TODO: handle error.
|
||||||
|
Ok(usize::try_from(value).unwrap()) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_isize(&mut self) -> Result<isize, SnapshotError> { |
||||||
|
let value = self.read_usize()?; |
||||||
|
Ok(value as isize) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_string(&mut self) -> Result<&str, SnapshotError> { |
||||||
|
let len = self.read_usize()?; |
||||||
|
let bytes = self.read_bytes(len)?; |
||||||
|
// TODO: handle error
|
||||||
|
Ok(std::str::from_utf8(bytes).unwrap()) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn read_bytes(&mut self, count: usize) -> Result<&[u8], SnapshotError> { |
||||||
|
let index = self.index; |
||||||
|
self.index += count; |
||||||
|
// TODO: use .get() so we can handle the error.
|
||||||
|
let bytes = &self.bytes[index..(index + count)]; |
||||||
|
Ok(bytes) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
use std::fmt::{Debug, Display}; |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
#[derive(Debug)] |
||||||
|
pub enum SnapshotError { |
||||||
|
/// Input/output error.
|
||||||
|
///
|
||||||
|
/// See: [`std::io::Error`].
|
||||||
|
Io(std::io::Error), |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for SnapshotError { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
// FIXME: implement better formatting
|
||||||
|
<Self as Debug>::fmt(self, f) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl std::error::Error for SnapshotError {} |
||||||
|
|
||||||
|
impl From<std::io::Error> for SnapshotError { |
||||||
|
fn from(value: std::io::Error) -> Self { |
||||||
|
Self::Io(value) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,229 @@ |
|||||||
|
use indexmap::{IndexMap, IndexSet}; |
||||||
|
|
||||||
|
use crate::{Context, JsBigInt, JsObject, JsString, JsSymbol}; |
||||||
|
|
||||||
|
use super::{Header, Snapshot, SnapshotError}; |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub trait Serialize { |
||||||
|
/// Serialize type
|
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError>; |
||||||
|
} |
||||||
|
|
||||||
|
impl Serialize for Header { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
s.write_bytes(&self.signature)?; |
||||||
|
s.write_u32(self.version)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub struct SnapshotSerializer { |
||||||
|
bytes: Vec<u8>, |
||||||
|
objects: IndexSet<JsObject>, |
||||||
|
strings: IndexMap<usize, JsString>, |
||||||
|
symbols: IndexMap<u64, JsSymbol>, |
||||||
|
bigints: IndexSet<JsBigInt>, |
||||||
|
external_references: IndexSet<usize>, |
||||||
|
} |
||||||
|
|
||||||
|
impl SnapshotSerializer { |
||||||
|
/// TODO: doc
|
||||||
|
pub fn new() -> Self { |
||||||
|
Self { |
||||||
|
bytes: Vec::new(), |
||||||
|
objects: IndexSet::default(), |
||||||
|
strings: IndexMap::default(), |
||||||
|
symbols: IndexMap::default(), |
||||||
|
bigints: IndexSet::default(), |
||||||
|
external_references: IndexSet::default(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Serialize the given [`Context`].
|
||||||
|
pub fn serialize(mut self, context: &mut Context<'_>) -> Result<Snapshot, SnapshotError> { |
||||||
|
// Remove any garbage objects before serialization.
|
||||||
|
boa_gc::force_collect(); |
||||||
|
|
||||||
|
// boa_gc::walk_gc_alloc_pointers(|address| {
|
||||||
|
// });
|
||||||
|
|
||||||
|
let header = Header { |
||||||
|
signature: *b".boa", |
||||||
|
version: 42, |
||||||
|
}; |
||||||
|
|
||||||
|
header.serialize(&mut self)?; |
||||||
|
context.serialize(&mut self)?; |
||||||
|
|
||||||
|
for i in 0..self.objects.len() { |
||||||
|
let object = self |
||||||
|
.objects |
||||||
|
.get_index(i) |
||||||
|
.expect("There should be an object") |
||||||
|
.clone(); |
||||||
|
object.inner().serialize(&mut self)?; |
||||||
|
} |
||||||
|
|
||||||
|
for i in 0..self.symbols.len() { |
||||||
|
let (hash, symbol) = self |
||||||
|
.symbols |
||||||
|
.get_index(i) |
||||||
|
.map(|(hash, symbol)| (*hash, symbol.clone())) |
||||||
|
.expect("There should be an object"); |
||||||
|
|
||||||
|
self.write_u64(hash)?; |
||||||
|
if let Some(desc) = symbol.description() { |
||||||
|
self.write_bool(true)?; |
||||||
|
desc.serialize(&mut self)?; |
||||||
|
} else { |
||||||
|
self.write_bool(false)?; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for i in 0..self.strings.len() { |
||||||
|
let string = self |
||||||
|
.strings |
||||||
|
.get_index(i) |
||||||
|
.expect("There should be an string") |
||||||
|
.1 |
||||||
|
.clone(); |
||||||
|
// string.
|
||||||
|
string.serialize(&mut self)?; |
||||||
|
|
||||||
|
self.write_bool(string.is_static())?; |
||||||
|
self.write_usize(string.len())?; |
||||||
|
for elem in string.as_slice() { |
||||||
|
self.write_u16(*elem)?; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Ok(Snapshot { |
||||||
|
bytes: self.bytes, |
||||||
|
external_references: self.external_references, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_bool(&mut self, v: bool) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_u8(if v { 1 } else { 0 })?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_u8(&mut self, v: u8) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&[v])?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_i8(&mut self, v: i8) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_u16(&mut self, v: u16) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_i16(&mut self, v: i16) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_u32(&mut self, v: u32) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_i32(&mut self, v: i32) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_f32(&mut self, v: f32) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_f64(&mut self, v: f64) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
|
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_u64(&mut self, v: u64) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_i64(&mut self, v: i64) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_u128(&mut self, v: u128) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_i128(&mut self, v: i128) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&v.to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_usize(&mut self, v: usize) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&(v as u64).to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_isize(&mut self, v: isize) -> Result<(), SnapshotError> { |
||||||
|
Ok(self.write_bytes(&(v as i64).to_le_bytes())?) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_string(&mut self, v: &str) -> Result<(), SnapshotError> { |
||||||
|
let asb = v.as_bytes(); |
||||||
|
self.write_usize(asb.len())?; |
||||||
|
self.bytes.extend_from_slice(asb); |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
/// TODO: doc
|
||||||
|
pub fn write_bytes(&mut self, v: &[u8]) -> Result<(), SnapshotError> { |
||||||
|
self.bytes.extend_from_slice(v); |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T: Serialize> Serialize for Vec<T> { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
s.write_usize(self.len())?; |
||||||
|
for element in self { |
||||||
|
element.serialize(s)?; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Serialize for JsString { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
let index = s.strings.insert_full(self.ptr.addr(), self.clone()).0; |
||||||
|
|
||||||
|
s.write_u32(index as u32)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Serialize for JsSymbol { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
let index = s.symbols.insert_full(self.hash(), self.clone()).0; |
||||||
|
|
||||||
|
s.write_u32(index as u32)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Serialize for JsBigInt { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
let index = s.bigints.insert_full(self.clone()).0; |
||||||
|
s.write_u32(index as u32)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Serialize for JsObject { |
||||||
|
fn serialize(&self, s: &mut SnapshotSerializer) -> Result<(), SnapshotError> { |
||||||
|
let value = s.objects.insert_full(self.clone()).0; |
||||||
|
|
||||||
|
s.write_u32(value as u32)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue