Skip to content

Commit

Permalink
Implement snapshot Serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Jun 21, 2023
1 parent 7f50108 commit 287c289
Show file tree
Hide file tree
Showing 17 changed files with 619 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ chrome_profiler.json
# e2e test
playwright-report
test-results

# Binary snapshot file
snapshot.bin
7 changes: 7 additions & 0 deletions boa_cli/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod object;
mod optimizer;
mod realm;
mod shape;
mod snapshot;

fn create_boa_object(context: &mut Context<'_>) -> JsObject {
let function_module = function::create_object(context);
Expand All @@ -19,6 +20,7 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject {
let gc_module = gc::create_object(context);
let realm_module = realm::create_object(context);
let limits_module = limits::create_object(context);
let snapshot_module = snapshot::create_object(context);

ObjectInitializer::new(context)
.property(
Expand Down Expand Up @@ -56,6 +58,11 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject {
limits_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.property(
"snapshot",
snapshot_module,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build()
}

Expand Down
29 changes: 29 additions & 0 deletions boa_cli/src/debug/snapshot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::{fs::OpenOptions, io::Write};

use boa_engine::{
object::ObjectInitializer, snapshot::SnapshotSerializer, Context, JsNativeError, JsObject,
JsResult, JsValue, NativeFunction,
};

const SNAPSHOT_PATH: &str = "./snapshot.bin";

fn create(_: &JsValue, _: &[JsValue], context: &mut Context<'_>) -> JsResult<JsValue> {
let Ok(mut file) = OpenOptions::new().write(true).create(true).open(SNAPSHOT_PATH) else {
return Err(JsNativeError::error().with_message("could not create snapshot.bin file").into());
};

let mut serializer = SnapshotSerializer::new();

serializer.serialize(context).unwrap();

file.write_all(serializer.bytes()).unwrap();
file.flush().unwrap();

Ok(JsValue::undefined())
}

pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
ObjectInitializer::new(context)
.function(NativeFunction::from_fn_ptr(create), "create", 0)
.build()
}
82 changes: 82 additions & 0 deletions boa_engine/src/context/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ pub struct Intrinsics {
pub(super) templates: ObjectTemplates,
}

impl crate::snapshot::Serialize for Intrinsics {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.constructors.serialize(s)?;
Ok(())
}
}

impl Intrinsics {
pub(crate) fn new(root_shape: &RootShape) -> Self {
let constructors = StandardConstructors::default();
Expand Down Expand Up @@ -62,6 +72,17 @@ pub struct StandardConstructor {
prototype: JsObject,
}

impl crate::snapshot::Serialize for StandardConstructor {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.constructor.serialize(s)?;
self.prototype.serialize(s)?;
Ok(())
}
}

impl Default for StandardConstructor {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -153,6 +174,67 @@ pub struct StandardConstructors {
segmenter: StandardConstructor,
}

impl crate::snapshot::Serialize for StandardConstructors {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.object.serialize(s)?;
self.proxy.serialize(s)?;
self.date.serialize(s)?;
self.function.serialize(s)?;
self.async_function.serialize(s)?;
self.generator_function.serialize(s)?;
self.async_generator_function.serialize(s)?;
self.array.serialize(s)?;
self.bigint.serialize(s)?;
self.number.serialize(s)?;
self.boolean.serialize(s)?;
self.string.serialize(s)?;
self.regexp.serialize(s)?;
self.symbol.serialize(s)?;
self.error.serialize(s)?;
self.type_error.serialize(s)?;
self.reference_error.serialize(s)?;
self.range_error.serialize(s)?;
self.syntax_error.serialize(s)?;
self.eval_error.serialize(s)?;
self.uri_error.serialize(s)?;
self.aggregate_error.serialize(s)?;
self.map.serialize(s)?;
self.set.serialize(s)?;
self.typed_array.serialize(s)?;
self.typed_int8_array.serialize(s)?;
self.typed_uint8_array.serialize(s)?;
self.typed_uint8clamped_array.serialize(s)?;
self.typed_int16_array.serialize(s)?;
self.typed_uint16_array.serialize(s)?;
self.typed_int32_array.serialize(s)?;
self.typed_uint32_array.serialize(s)?;
self.typed_bigint64_array.serialize(s)?;
self.typed_biguint64_array.serialize(s)?;
self.typed_float32_array.serialize(s)?;
self.typed_float64_array.serialize(s)?;
self.array_buffer.serialize(s)?;
self.data_view.serialize(s)?;
self.date_time_format.serialize(s)?;
self.promise.serialize(s)?;
self.weak_ref.serialize(s)?;
self.weak_map.serialize(s)?;
self.weak_set.serialize(s)?;
#[cfg(feature = "intl")]
self.collator.serialize(s)?;
#[cfg(feature = "intl")]
self.list_format.serialize(s)?;
#[cfg(feature = "intl")]
self.locale.serialize(s)?;
#[cfg(feature = "intl")]
self.segmenter.serialize(s)?;

Ok(())
}
}

impl Default for StandardConstructors {
fn default() -> Self {
Self {
Expand Down
11 changes: 11 additions & 0 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,3 +985,14 @@ where
}
}
}

impl crate::snapshot::Serialize for Context<'_> {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
s.write_bool(self.strict)?;
self.realm.serialize(s)?;
Ok(())
}
}
2 changes: 2 additions & 0 deletions boa_engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ mod tests;
pub mod value;
pub mod vm;

pub mod snapshot;

/// A convenience module that re-exports the most commonly-used Boa APIs
pub mod prelude {
pub use crate::{
Expand Down
10 changes: 10 additions & 0 deletions boa_engine/src/object/builtins/jsfunction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ pub struct JsFunction {
inner: JsObject,
}

impl crate::snapshot::Serialize for JsFunction {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.inner.serialize(s)?;
Ok(())
}
}

impl JsFunction {
/// Creates a new `JsFunction` from an object, without checking if the object is callable.
pub(crate) fn from_object_unchecked(object: JsObject) -> Self {
Expand Down
12 changes: 12 additions & 0 deletions boa_engine/src/object/jsobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ pub struct VTableObject {
vtable: &'static InternalObjectMethods,
}

impl crate::snapshot::Serialize for VTableObject {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> StdResult<(), crate::snapshot::SnapshotError> {
// TODO: add internal methods to references

self.object.borrow().serialize(s)?;
Ok(())
}
}

impl Default for JsObject {
fn default() -> Self {
let data = ObjectData::ordinary();
Expand Down
11 changes: 11 additions & 0 deletions boa_engine/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ pub struct Object {
private_elements: ThinVec<(PrivateName, PrivateElement)>,
}

impl crate::snapshot::Serialize for Object {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
s.write_bool(self.extensible)?;
self.properties.serialize(s)?;
Ok(())
}
}

impl Default for Object {
fn default() -> Self {
Self {
Expand Down
10 changes: 10 additions & 0 deletions boa_engine/src/object/property_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,16 @@ pub struct PropertyMap {
pub(crate) storage: ObjectStorage,
}

impl crate::snapshot::Serialize for PropertyMap {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.storage.serialize(s)?;
Ok(())
}
}

impl PropertyMap {
/// Create a new [`PropertyMap`].
#[must_use]
Expand Down
20 changes: 20 additions & 0 deletions boa_engine/src/realm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ pub struct Realm {
inner: Gc<Inner>,
}

impl crate::snapshot::Serialize for Realm {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.inner.serialize(s)?;
Ok(())
}
}

impl Eq for Realm {}

impl PartialEq for Realm {
Expand Down Expand Up @@ -54,6 +64,16 @@ struct Inner {
loaded_modules: GcRefCell<FxHashMap<JsString, Module>>,
}

impl crate::snapshot::Serialize for Inner {
fn serialize(
&self,
s: &mut crate::snapshot::SnapshotSerializer,
) -> Result<(), crate::snapshot::SnapshotError> {
self.intrinsics.serialize(s)?;
Ok(())
}
}

impl Realm {
/// Create a new Realm.
#[inline]
Expand Down
Loading

0 comments on commit 287c289

Please sign in to comment.