Skip to content

Commit db0c916

Browse files
committed
Implement snapshot Serializer
1 parent a9a2e1b commit db0c916

File tree

17 files changed

+619
-4
lines changed

17 files changed

+619
-4
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ chrome_profiler.json
3636
# e2e test
3737
playwright-report
3838
test-results
39+
40+
# Binary snapshot file
41+
snapshot.bin

boa_cli/src/debug/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod object;
1010
mod optimizer;
1111
mod realm;
1212
mod shape;
13+
mod snapshot;
1314

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

2325
ObjectInitializer::new(context)
2426
.property(
@@ -56,6 +58,11 @@ fn create_boa_object(context: &mut Context<'_>) -> JsObject {
5658
limits_module,
5759
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
5860
)
61+
.property(
62+
"snapshot",
63+
snapshot_module,
64+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
65+
)
5966
.build()
6067
}
6168

boa_cli/src/debug/snapshot.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::{fs::OpenOptions, io::Write};
2+
3+
use boa_engine::{
4+
object::ObjectInitializer, snapshot::SnapshotSerializer, Context, JsNativeError, JsObject,
5+
JsResult, JsValue, NativeFunction,
6+
};
7+
8+
const SNAPSHOT_PATH: &str = "./snapshot.bin";
9+
10+
fn create(_: &JsValue, _: &[JsValue], context: &mut Context<'_>) -> JsResult<JsValue> {
11+
let Ok(mut file) = OpenOptions::new().write(true).create(true).open(SNAPSHOT_PATH) else {
12+
return Err(JsNativeError::error().with_message("could not create snapshot.bin file").into());
13+
};
14+
15+
let mut serializer = SnapshotSerializer::new();
16+
17+
serializer.serialize(context).unwrap();
18+
19+
file.write_all(serializer.bytes()).unwrap();
20+
file.flush().unwrap();
21+
22+
Ok(JsValue::undefined())
23+
}
24+
25+
pub(super) fn create_object(context: &mut Context<'_>) -> JsObject {
26+
ObjectInitializer::new(context)
27+
.function(NativeFunction::from_fn_ptr(create), "create", 0)
28+
.build()
29+
}

boa_engine/src/context/intrinsics.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ pub struct Intrinsics {
2626
pub(super) templates: ObjectTemplates,
2727
}
2828

29+
impl crate::snapshot::Serialize for Intrinsics {
30+
fn serialize(
31+
&self,
32+
s: &mut crate::snapshot::SnapshotSerializer,
33+
) -> Result<(), crate::snapshot::SnapshotError> {
34+
self.constructors.serialize(s)?;
35+
Ok(())
36+
}
37+
}
38+
2939
impl Intrinsics {
3040
pub(crate) fn new(root_shape: &RootShape) -> Self {
3141
let constructors = StandardConstructors::default();
@@ -62,6 +72,17 @@ pub struct StandardConstructor {
6272
prototype: JsObject,
6373
}
6474

75+
impl crate::snapshot::Serialize for StandardConstructor {
76+
fn serialize(
77+
&self,
78+
s: &mut crate::snapshot::SnapshotSerializer,
79+
) -> Result<(), crate::snapshot::SnapshotError> {
80+
self.constructor.serialize(s)?;
81+
self.prototype.serialize(s)?;
82+
Ok(())
83+
}
84+
}
85+
6586
impl Default for StandardConstructor {
6687
fn default() -> Self {
6788
Self {
@@ -153,6 +174,67 @@ pub struct StandardConstructors {
153174
segmenter: StandardConstructor,
154175
}
155176

177+
impl crate::snapshot::Serialize for StandardConstructors {
178+
fn serialize(
179+
&self,
180+
s: &mut crate::snapshot::SnapshotSerializer,
181+
) -> Result<(), crate::snapshot::SnapshotError> {
182+
self.object.serialize(s)?;
183+
self.proxy.serialize(s)?;
184+
self.date.serialize(s)?;
185+
self.function.serialize(s)?;
186+
self.async_function.serialize(s)?;
187+
self.generator_function.serialize(s)?;
188+
self.async_generator_function.serialize(s)?;
189+
self.array.serialize(s)?;
190+
self.bigint.serialize(s)?;
191+
self.number.serialize(s)?;
192+
self.boolean.serialize(s)?;
193+
self.string.serialize(s)?;
194+
self.regexp.serialize(s)?;
195+
self.symbol.serialize(s)?;
196+
self.error.serialize(s)?;
197+
self.type_error.serialize(s)?;
198+
self.reference_error.serialize(s)?;
199+
self.range_error.serialize(s)?;
200+
self.syntax_error.serialize(s)?;
201+
self.eval_error.serialize(s)?;
202+
self.uri_error.serialize(s)?;
203+
self.aggregate_error.serialize(s)?;
204+
self.map.serialize(s)?;
205+
self.set.serialize(s)?;
206+
self.typed_array.serialize(s)?;
207+
self.typed_int8_array.serialize(s)?;
208+
self.typed_uint8_array.serialize(s)?;
209+
self.typed_uint8clamped_array.serialize(s)?;
210+
self.typed_int16_array.serialize(s)?;
211+
self.typed_uint16_array.serialize(s)?;
212+
self.typed_int32_array.serialize(s)?;
213+
self.typed_uint32_array.serialize(s)?;
214+
self.typed_bigint64_array.serialize(s)?;
215+
self.typed_biguint64_array.serialize(s)?;
216+
self.typed_float32_array.serialize(s)?;
217+
self.typed_float64_array.serialize(s)?;
218+
self.array_buffer.serialize(s)?;
219+
self.data_view.serialize(s)?;
220+
self.date_time_format.serialize(s)?;
221+
self.promise.serialize(s)?;
222+
self.weak_ref.serialize(s)?;
223+
self.weak_map.serialize(s)?;
224+
self.weak_set.serialize(s)?;
225+
#[cfg(feature = "intl")]
226+
self.collator.serialize(s)?;
227+
#[cfg(feature = "intl")]
228+
self.list_format.serialize(s)?;
229+
#[cfg(feature = "intl")]
230+
self.locale.serialize(s)?;
231+
#[cfg(feature = "intl")]
232+
self.segmenter.serialize(s)?;
233+
234+
Ok(())
235+
}
236+
}
237+
156238
impl Default for StandardConstructors {
157239
fn default() -> Self {
158240
Self {

boa_engine/src/context/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,3 +985,14 @@ where
985985
}
986986
}
987987
}
988+
989+
impl crate::snapshot::Serialize for Context<'_> {
990+
fn serialize(
991+
&self,
992+
s: &mut crate::snapshot::SnapshotSerializer,
993+
) -> Result<(), crate::snapshot::SnapshotError> {
994+
s.write_bool(self.strict)?;
995+
self.realm.serialize(s)?;
996+
Ok(())
997+
}
998+
}

boa_engine/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ mod tests;
147147
pub mod value;
148148
pub mod vm;
149149

150+
pub mod snapshot;
151+
150152
/// A convenience module that re-exports the most commonly-used Boa APIs
151153
pub mod prelude {
152154
pub use crate::{

boa_engine/src/object/builtins/jsfunction.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ pub struct JsFunction {
1616
inner: JsObject,
1717
}
1818

19+
impl crate::snapshot::Serialize for JsFunction {
20+
fn serialize(
21+
&self,
22+
s: &mut crate::snapshot::SnapshotSerializer,
23+
) -> Result<(), crate::snapshot::SnapshotError> {
24+
self.inner.serialize(s)?;
25+
Ok(())
26+
}
27+
}
28+
1929
impl JsFunction {
2030
/// Creates a new `JsFunction` from an object, without checking if the object is callable.
2131
pub(crate) fn from_object_unchecked(object: JsObject) -> Self {

boa_engine/src/object/jsobject.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ pub struct VTableObject {
5151
vtable: &'static InternalObjectMethods,
5252
}
5353

54+
impl crate::snapshot::Serialize for VTableObject {
55+
fn serialize(
56+
&self,
57+
s: &mut crate::snapshot::SnapshotSerializer,
58+
) -> StdResult<(), crate::snapshot::SnapshotError> {
59+
// TODO: add internal methods to references
60+
61+
self.object.borrow().serialize(s)?;
62+
Ok(())
63+
}
64+
}
65+
5466
impl Default for JsObject {
5567
fn default() -> Self {
5668
let data = ObjectData::ordinary();

boa_engine/src/object/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ pub struct Object {
142142
private_elements: ThinVec<(PrivateName, PrivateElement)>,
143143
}
144144

145+
impl crate::snapshot::Serialize for Object {
146+
fn serialize(
147+
&self,
148+
s: &mut crate::snapshot::SnapshotSerializer,
149+
) -> Result<(), crate::snapshot::SnapshotError> {
150+
s.write_bool(self.extensible)?;
151+
self.properties.serialize(s)?;
152+
Ok(())
153+
}
154+
}
155+
145156
impl Default for Object {
146157
fn default() -> Self {
147158
Self {

boa_engine/src/object/property_map.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,16 @@ pub struct PropertyMap {
226226
pub(crate) storage: ObjectStorage,
227227
}
228228

229+
impl crate::snapshot::Serialize for PropertyMap {
230+
fn serialize(
231+
&self,
232+
s: &mut crate::snapshot::SnapshotSerializer,
233+
) -> Result<(), crate::snapshot::SnapshotError> {
234+
self.storage.serialize(s)?;
235+
Ok(())
236+
}
237+
}
238+
229239
impl PropertyMap {
230240
/// Create a new [`PropertyMap`].
231241
#[must_use]

0 commit comments

Comments
 (0)