Skip to content
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

feat(swc/common): wrap serialized struct with versioned (#5060: Part 3) #5128

Merged
merged 8 commits into from
Jul 7, 2022
44 changes: 34 additions & 10 deletions crates/swc/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ impl RustPlugins {
use std::{path::PathBuf, sync::Arc};

use anyhow::Context;
use swc_common::{plugin::PluginSerializedBytes, FileName};
use swc_common::{
plugin::{PluginSerializedBytes, VersionedSerializable},
FileName,
};
use swc_ecma_loader::resolve::Resolve;

// swc_plugin_macro will not inject proxy to the comments if comments is empty
Expand All @@ -92,7 +95,8 @@ impl RustPlugins {
inner: self.comments.clone(),
},
|| {
let mut serialized = PluginSerializedBytes::try_serialize(&n)?;
let program = VersionedSerializable::new(n);
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;

// Run plugin transformation against current program.
// We do not serialize / deserialize between each plugin execution but
Expand All @@ -111,11 +115,19 @@ impl RustPlugins {

let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| PluginSerializedBytes::try_serialize(&value))?;
.and_then(|value| {
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
value,
))
})?;

let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| PluginSerializedBytes::try_serialize(&value))?;
.and_then(|value| {
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
value,
))
})?;

let resolved_path = self
.resolver
Expand Down Expand Up @@ -152,7 +164,7 @@ impl RustPlugins {

// Plugin transformation is done. Deserialize transformed bytes back
// into Program
serialized.deserialize()
serialized.deserialize().map(|v| v.into_inner())
},
)
}
Expand All @@ -162,7 +174,10 @@ impl RustPlugins {
use std::{path::PathBuf, sync::Arc};

use anyhow::Context;
use swc_common::{plugin::PluginSerializedBytes, FileName};
use swc_common::{
plugin::{PluginSerializedBytes, VersionedSerializable},
FileName,
};
use swc_ecma_loader::resolve::Resolve;

let should_enable_comments_proxy = self.comments.is_some();
Expand All @@ -172,17 +187,26 @@ impl RustPlugins {
inner: self.comments.clone(),
},
|| {
let mut serialized = PluginSerializedBytes::try_serialize(&n)?;
let program = VersionedSerializable::new(n);
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;

if let Some(plugins) = &self.plugins {
for p in plugins {
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| PluginSerializedBytes::try_serialize(&value))?;
.and_then(|value| {
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
value,
))
})?;

let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| PluginSerializedBytes::try_serialize(&value))?;
.and_then(|value| {
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
value,
))
})?;

serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
Expand All @@ -197,7 +221,7 @@ impl RustPlugins {
}
}

serialized.deserialize()
serialized.deserialize().map(|v| v.into_inner())
},
)
}
Expand Down
19 changes: 8 additions & 11 deletions crates/swc_common/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ impl PluginSerializedBytes {
}

/**
* Constructs an instance from given struct by serializing it.
* Constructs an instance from versioned struct by serializing it.
*
* This is sort of mimic TryFrom behavior, since we can't use generic
* to implement TryFrom trait
*/
pub fn try_serialize<W>(t: &W) -> Result<Self, Error>
pub fn try_serialize<W>(t: &VersionedSerializable<W>) -> Result<Self, Error>
where
W: rkyv::Serialize<rkyv::ser::serializers::AllocSerializer<512>>,
{
Expand Down Expand Up @@ -105,15 +105,15 @@ impl PluginSerializedBytes {
(self.field.as_ptr(), self.field.len())
}

pub fn deserialize<W>(&self) -> Result<W, Error>
pub fn deserialize<W>(&self) -> Result<VersionedSerializable<W>, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
{
use anyhow::Context;
use rkyv::Deserialize;

let archived = unsafe { rkyv::archived_root::<W>(&self.field[..]) };
let archived = unsafe { rkyv::archived_root::<VersionedSerializable<W>>(&self.field[..]) };

archived
.deserialize(&mut rkyv::de::deserializers::SharedDeserializeMap::new())
Expand All @@ -130,7 +130,7 @@ impl PluginSerializedBytes {
pub unsafe fn deserialize_from_ptr<W>(
raw_allocated_ptr: *const u8,
raw_allocated_ptr_len: i32,
) -> Result<W, Error>
) -> Result<VersionedSerializable<W>, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
Expand All @@ -153,7 +153,7 @@ where
pub unsafe fn deserialize_from_ptr_into_fallible<W>(
raw_allocated_ptr: *const u8,
raw_allocated_ptr_len: i32,
) -> Result<W, Error>
) -> Result<VersionedSerializable<W>, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
Expand Down Expand Up @@ -194,10 +194,7 @@ impl<T> VersionedSerializable<T> {
&self.0 .1
}

pub fn take(&mut self) -> T
where
T: Default,
{
mem::take(&mut self.0 .1)
pub fn into_inner(self) -> T {
self.0 .1
}
}
19 changes: 12 additions & 7 deletions crates/swc_common/src/syntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,10 @@ impl Mark {
pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
// This code path executed inside of the guest memory context.
// In here, preallocate memory for the context.
let serialized =
crate::plugin::PluginSerializedBytes::try_serialize(&MutableMarkContext(0, 0, 0))
.expect("Should be serializable");
let serialized = crate::plugin::PluginSerializedBytes::try_serialize(
&crate::plugin::VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();

// Calling host proxy fn. Inside of host proxy, host will
Expand All @@ -197,6 +198,7 @@ impl Mark {
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
.into_inner()
};
self = Mark::from_u32(context.0);

Expand All @@ -219,9 +221,10 @@ impl Mark {
#[allow(unused_mut, unused_assignments)]
#[cfg(all(feature = "plugin-mode", target_arch = "wasm32"))]
pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
let serialized =
crate::plugin::PluginSerializedBytes::try_serialize(&MutableMarkContext(0, 0, 0))
.expect("Should be serializable");
let serialized = crate::plugin::PluginSerializedBytes::try_serialize(
&crate::plugin::VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();

unsafe {
Expand All @@ -234,6 +237,7 @@ impl Mark {
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
.into_inner()
};
a = Mark::from_u32(context.0);
b = Mark::from_u32(context.1);
Expand Down Expand Up @@ -383,7 +387,7 @@ impl SyntaxContext {

#[cfg(all(feature = "plugin-mode", target_arch = "wasm32"))]
pub fn remove_mark(&mut self) -> Mark {
let context = MutableMarkContext(0, 0, 0);
let context = crate::plugin::VersionedSerializable::new(MutableMarkContext(0, 0, 0));
let serialized = crate::plugin::PluginSerializedBytes::try_serialize(&context)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();
Expand All @@ -398,6 +402,7 @@ impl SyntaxContext {
len.try_into().expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize")
.into_inner()
};

*self = SyntaxContext(context.0);
Expand Down
6 changes: 0 additions & 6 deletions crates/swc_ecma_ast/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ pub enum Program {
Script(Script),
}

impl Default for Program {
fn default() -> Self {
Program::Module(Module::dummy())
}
}

#[ast_node("Module")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Module {
Expand Down
8 changes: 6 additions & 2 deletions crates/swc_plugin/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use swc_common::{plugin::PluginSerializedBytes, sync::OnceCell};
use swc_common::{
plugin::{PluginSerializedBytes, VersionedSerializable},
sync::OnceCell,
};

use crate::pseudo_scoped_key::PseudoScopedKey;

Expand All @@ -18,7 +21,8 @@ pub struct PluginDiagnosticsEmitter;
impl swc_common::errors::Emitter for PluginDiagnosticsEmitter {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn emit(&mut self, db: &swc_common::errors::DiagnosticBuilder<'_>) {
let diag = PluginSerializedBytes::try_serialize(&*db.diagnostic)
let diagnostic = VersionedSerializable::new((*db.diagnostic).clone());
let diag = PluginSerializedBytes::try_serialize(&diagnostic)
.expect("Should able to serialize Diagnostic");
let (ptr, len) = diag.as_ptr();

Expand Down
2 changes: 1 addition & 1 deletion crates/swc_plugin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Reexports
pub use swc_common::{
chain,
plugin::{deserialize_from_ptr, PluginError, PluginSerializedBytes},
plugin::{deserialize_from_ptr, PluginError, PluginSerializedBytes, VersionedSerializable},
};

pub mod comments {
Expand Down
9 changes: 5 additions & 4 deletions crates/swc_plugin_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ fn handle_func(func: ItemFn) -> TokenStream {

/// Internal function plugin_macro uses to create ptr to PluginError.
fn construct_error_ptr(plugin_error: swc_plugin::PluginError) -> i32 {
let plugin_error = swc_plugin::VersionedSerializable::new(plugin_error);
let ret = swc_plugin::PluginSerializedBytes::try_serialize(&plugin_error).expect("Should able to serialize PluginError");
let (ptr, len) = ret.as_ptr();

Expand All @@ -61,14 +62,14 @@ fn handle_func(func: ItemFn) -> TokenStream {
pub fn #process_impl_ident(ast_ptr: *const u8, ast_ptr_len: i32, config_str_ptr: *const u8, config_str_ptr_len: i32, context_str_ptr: *const u8, context_str_ptr_len: i32, should_enable_comments_proxy: i32) -> i32 {
// Reconstruct `Program` & config string from serialized program
// Host (SWC) should allocate memory, copy bytes and pass ptr to plugin.
let program = unsafe { swc_plugin::deserialize_from_ptr(ast_ptr, ast_ptr_len) };
let program = unsafe { swc_plugin::deserialize_from_ptr(ast_ptr, ast_ptr_len).map(|v| v.into_inner()) };
if program.is_err() {
let err = swc_plugin::PluginError::Deserialize("Failed to deserialize program received from host".to_string());
return construct_error_ptr(err);
}
let program: Program = program.expect("Should be a program");

let config = unsafe { swc_plugin::deserialize_from_ptr(config_str_ptr, config_str_ptr_len) };
let config = unsafe { swc_plugin::deserialize_from_ptr(config_str_ptr, config_str_ptr_len).map(|v| v.into_inner()) };
if config.is_err() {
let err = swc_plugin::PluginError::Deserialize(
"Failed to deserialize config string received from host".to_string()
Expand All @@ -77,7 +78,7 @@ fn handle_func(func: ItemFn) -> TokenStream {
}
let config: String = config.expect("Should be a string");

let context = unsafe { swc_plugin::deserialize_from_ptr(context_str_ptr, context_str_ptr_len) };
let context = unsafe { swc_plugin::deserialize_from_ptr(context_str_ptr, context_str_ptr_len).map(|v| v.into_inner()) };
if context.is_err() {
let err = swc_plugin::PluginError::Deserialize("Failed to deserialize context string received from host".to_string());
return construct_error_ptr(err);
Expand Down Expand Up @@ -112,7 +113,7 @@ fn handle_func(func: ItemFn) -> TokenStream {
let transformed_program = #ident(program, metadata);

// Serialize transformed result, return back to the host.
let serialized_result = swc_plugin::PluginSerializedBytes::try_serialize(&transformed_program);
let serialized_result = swc_plugin::PluginSerializedBytes::try_serialize(&swc_plugin::VersionedSerializable::new(transformed_program));

if serialized_result.is_err() {
let err = swc_plugin::PluginError::Serialize("Failed to serialize transformed program".to_string());
Expand Down
13 changes: 7 additions & 6 deletions crates/swc_plugin_proxy/src/comments/plugin_comments_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ impl PluginCommentsProxy {
/// comment_buffer as serialized to pass param from guest to the host for
/// the fn like add_leading*.
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn allocate_comments_buffer_to_host<T>(&self, value: &T)
fn allocate_comments_buffer_to_host<T>(&self, value: T)
where
T: rkyv::Serialize<rkyv::ser::serializers::AllocSerializer<512>>,
{
#[cfg(target_arch = "wasm32")]
{
let serialized = swc_common::plugin::PluginSerializedBytes::try_serialize(value)
let value = swc_common::plugin::VersionedSerializable::new(value);
let serialized = swc_common::plugin::PluginSerializedBytes::try_serialize(&value)
.expect("Should able to serialize value");
let (serialized_comment_ptr, serialized_comment_ptr_len) = serialized.as_ptr();
unsafe {
Expand All @@ -73,15 +74,15 @@ impl PluginCommentsProxy {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
impl Comments for PluginCommentsProxy {
fn add_leading(&self, pos: BytePos, cmt: Comment) {
self.allocate_comments_buffer_to_host(&cmt);
self.allocate_comments_buffer_to_host(cmt);
#[cfg(target_arch = "wasm32")]
unsafe {
__add_leading_comment_proxy(pos.0);
}
}

fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
self.allocate_comments_buffer_to_host(&comments);
self.allocate_comments_buffer_to_host(comments);
#[cfg(target_arch = "wasm32")]
unsafe {
__add_leading_comments_proxy(pos.0);
Expand Down Expand Up @@ -129,15 +130,15 @@ impl Comments for PluginCommentsProxy {
}

fn add_trailing(&self, pos: BytePos, cmt: Comment) {
self.allocate_comments_buffer_to_host(&cmt);
self.allocate_comments_buffer_to_host(cmt);
#[cfg(target_arch = "wasm32")]
unsafe {
__add_trailing_comment_proxy(pos.0);
}
}

fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
self.allocate_comments_buffer_to_host(&comments);
self.allocate_comments_buffer_to_host(comments);
#[cfg(target_arch = "wasm32")]
unsafe {
__add_trailing_comments_proxy(pos.0);
Expand Down
Loading