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(plugin): Add versioned wrapper struct #7382

Merged
merged 5 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
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
136 changes: 68 additions & 68 deletions bindings/Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bindings/binding_core_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ tracing-chrome = "0.5.0"
tracing-futures = "0.2.5"
tracing-subscriber = { version = "0.3.9", features = ["env-filter"] }

swc_core = { version = "0.75.46", features = [
swc_core = { version = "0.76.2", features = [
"allocator_node",
"ecma_ast",
"ecma_ast_serde",
Expand Down
2 changes: 1 addition & 1 deletion bindings/binding_core_wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ plugin = []
anyhow = "1.0.66"
serde = { version = "1", features = ["derive"] }
serde-wasm-bindgen = "0.4.5"
swc_core = { version = "0.75.46", features = [
swc_core = { version = "0.76.2", features = [
"ecma_ast_serde",
"common_perf",
"binding_macro_wasm",
Expand Down
2 changes: 1 addition & 1 deletion bindings/swc_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ relative-path = "1.6.1"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["unbounded_depth"] }
sourcemap = "6.2.2"
swc_core = { version = "0.75.46", features = [
swc_core = { version = "0.76.2", features = [
"trace_macro",
"common_concurrent",
"base_concurrent",
Expand Down
18 changes: 10 additions & 8 deletions crates/swc/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ impl RustPlugins {
},
|| {
let span = tracing::span!(tracing::Level::INFO, "serialize_program").entered();
let mut serialized_program = PluginSerializedBytes::try_serialize(&n)?;
let program = swc_common::plugin::serialized::VersionedSerializable::new(n);
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;
drop(span);

// Run plugin transformation against current program.
Expand Down Expand Up @@ -137,9 +138,9 @@ impl RustPlugins {
)
.entered();

serialized_program = transform_plugin_executor
serialized = transform_plugin_executor
.transform(
&serialized_program,
&serialized,
self.unresolved_mark,
should_enable_comments_proxy,
)
Expand All @@ -156,7 +157,7 @@ impl RustPlugins {

// Plugin transformation is done. Deserialize transformed bytes back
// into Program
serialized_program.deserialize()
serialized.deserialize().map(|v| v.into_inner())
},
)
}
Expand All @@ -179,7 +180,8 @@ impl RustPlugins {
inner: self.comments.clone(),
},
|| {
let mut serialized_program = PluginSerializedBytes::try_serialize(&n)?;
let program = swc_common::plugin::serialized::VersionedSerializable::new(n);
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;

if let Some(plugins) = &mut self.plugins {
for p in plugins.drain(..) {
Expand All @@ -192,9 +194,9 @@ impl RustPlugins {
Some(p.1),
)?;

serialized_program = transform_plugin_executor
serialized = transform_plugin_executor
.transform(
&serialized_program,
&serialized,
self.unresolved_mark,
should_enable_comments_proxy,
)
Expand All @@ -204,7 +206,7 @@ impl RustPlugins {
}
}

serialized_program.deserialize()
serialized_program.deserialize().map(|v| v.into_inner())
},
)
}
Expand Down
50 changes: 21 additions & 29 deletions crates/swc_common/src/plugin/serialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl PluginSerializedBytes {
* to implement TryFrom trait
*/
#[tracing::instrument(level = "info", skip_all)]
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 @@ -99,14 +99,14 @@ impl PluginSerializedBytes {
}

#[tracing::instrument(level = "info", skip_all)]
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;

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 @@ -124,7 +124,7 @@ impl PluginSerializedBytes {
pub unsafe fn deserialize_from_ptr<W>(
raw_allocated_ptr: *const u8,
raw_allocated_ptr_len: u32,
) -> Result<W, Error>
) -> Result<VersionedSerializable<W>, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
Expand All @@ -135,37 +135,30 @@ where
serialized.deserialize()
}

/// Deserialize `Fallible` struct from raw ptr. This is similar to
/// `deserialize_from_ptr` but for the struct requires bounds to the
/// SharedSerializeRegistry which cannot be Infallible. Internally this does
/// not call deserialize with Infallible deserializer, use
/// SharedDeserializeMap instead.
#[tracing::instrument(level = "info", skip_all)]
pub fn deserialize_from_ptr_into_fallible<W>(
raw_allocated_ptr: *const u8,
raw_allocated_ptr_len: u32,
) -> Result<W, Error>
where
W: rkyv::Archive,
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
{
let serialized =
PluginSerializedBytes::from_raw_ptr(raw_allocated_ptr, raw_allocated_ptr_len as usize);

serialized.deserialize()
}

/*
/// A wrapper type for the structures to be passed into plugins
/// serializes the contained value out-of-line so that newer
/// versions can be viewed as the older version.
///
#[derive(Archive, Deserialize, Serialize)]
pub struct VersionedSerializable<T>(#[with(AsBox)] T);
/// First field indicate version of struct type (schema). Any consumers like
/// swc_plugin_macro can use this to validate compatiblility before attempt to
/// serialize.
#[cfg_attr(
feature = "__plugin",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[repr(transparent)]
#[cfg_attr(feature = "__plugin", archive(check_bytes))]
#[cfg_attr(feature = "__plugin", archive_attr(repr(transparent)))]
#[derive(Debug)]
pub struct VersionedSerializable<T>(
// [NOTE]: https://github.com/rkyv/rkyv/issues/373#issuecomment-1546360897
//#[cfg_attr(feature = "__plugin", with(rkyv::with::AsBox))]
pub T,
);

impl<T> VersionedSerializable<T> {
pub fn new(value: T) -> Self {
VersionedSerializable(value)
Self(value)
}

pub fn inner(&self) -> &T {
Expand All @@ -176,4 +169,3 @@ impl<T> VersionedSerializable<T> {
self.0
}
}
*/
15 changes: 12 additions & 3 deletions crates/swc_common/src/syntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,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.

use crate::plugin::serialized::VersionedSerializable;
let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(
&MutableMarkContext(0, 0, 0),
&VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();
Expand All @@ -200,6 +202,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 @@ -222,8 +225,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 {
use crate::plugin::serialized::VersionedSerializable;

let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(
&MutableMarkContext(0, 0, 0),
&VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();
Expand All @@ -238,6 +243,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 @@ -418,7 +424,9 @@ impl SyntaxContext {

#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
pub fn remove_mark(&mut self) -> Mark {
let context = MutableMarkContext(0, 0, 0);
use crate::plugin::serialized::VersionedSerializable;

let context = VersionedSerializable::new(MutableMarkContext(0, 0, 0));
let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(&context)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();
Expand All @@ -433,6 +441,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
10 changes: 5 additions & 5 deletions crates/swc_plugin_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn handle_func(func: ItemFn, ast_type: Ident) -> TokenStream {
impl swc_core::common::errors::Emitter for PluginDiagnosticsEmitter {
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
fn emit(&mut self, db: &swc_core::common::errors::DiagnosticBuilder<'_>) {
let diag = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(&*db.diagnostic)
let diag = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(&swc_core::common::plugin::serialized::VersionedSerializable::new(*db.diagnostic.clone()))
.expect("Should able to serialize Diagnostic");
let (ptr, len) = diag.as_ptr();

Expand All @@ -83,7 +83,7 @@ fn handle_func(func: ItemFn, ast_type: Ident) -> TokenStream {

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

send_transform_result_to_host(
Expand All @@ -107,7 +107,7 @@ fn handle_func(func: ItemFn, ast_type: Ident) -> TokenStream {
};

let serialized_result = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(
&result
&swc_core::common::plugin::serialized::VersionedSerializable::new(result)
).expect("Diagnostics should be always serializable");

let (serialized_result_ptr, serialized_result_ptr_len) = serialized_result.as_ptr();
Expand Down Expand Up @@ -135,7 +135,7 @@ fn handle_func(func: ItemFn, ast_type: Ident) -> TokenStream {
let err = swc_core::common::plugin::serialized::PluginError::Deserialize("Failed to deserialize program received from host".to_string());
return construct_error_ptr(err);
}
let program: #ast_type = program.expect("Should be a program");
let program: #ast_type = program.expect("Should be a program").into_inner();

// Create a handler wired with plugin's diagnostic emitter, set it for global context.
let handler = swc_core::common::errors::Handler::with_emitter(
Expand All @@ -161,7 +161,7 @@ fn handle_func(func: ItemFn, ast_type: Ident) -> TokenStream {
};

// Take original plugin fn ident, then call it with interop'ed args
let transformed_program = #ident(program, metadata);
let transformed_program = swc_core::common::plugin::serialized::VersionedSerializable::new(#ident(program, metadata));

// Serialize transformed result, return back to the host.
let serialized_result = swc_core::common::plugin::serialized::PluginSerializedBytes::try_serialize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ impl PluginCommentsProxy {
{
#[cfg(target_arch = "wasm32")]
{
let serialized =
swc_common::plugin::serialized::PluginSerializedBytes::try_serialize(&value)
.expect("Should able to serialize value");
let serialized = swc_common::plugin::serialized::PluginSerializedBytes::try_serialize(
&swc_common::plugin::serialized::VersionedSerializable::new(value),
)
.expect("Should able to serialize value");
let (serialized_comment_ptr, serialized_comment_ptr_len) = serialized.as_ptr();
unsafe {
// We need to copy PluginCommentProxy's param for add_leading (Comment, or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ where
F: FnOnce(u32) -> u32,
{
// Allocate AllocatedBytesPtr to get return value from the host
let allocated_bytes_ptr = AllocatedBytesPtr(0, 0);
let allocated_bytes_ptr =
swc_common::plugin::serialized::VersionedSerializable::new(AllocatedBytesPtr(0, 0));
let serialized_allocated_bytes_ptr = PluginSerializedBytes::try_serialize(&allocated_bytes_ptr)
.expect("Should able to serialize AllocatedBytesPtr");
let (serialized_allocated_bytes_raw_ptr, serialized_allocated_bytes_raw_ptr_size) =
Expand All @@ -69,6 +70,7 @@ where
.expect("Should able to convert ptr length"),
)
.expect("Should able to deserialize AllocatedBytesPtr")
.into_inner()
})
}

Expand Down Expand Up @@ -98,5 +100,6 @@ where
allocated_returned_value_ptr.1,
)
.expect("Returned value should be serializable")
.into_inner()
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl TransformPluginProgramMetadata {
#[cfg(target_arch = "wasm32")]
return read_returned_result_from_host(|serialized_ptr| unsafe {
let serialized = swc_common::plugin::serialized::PluginSerializedBytes::try_serialize(
&key.to_string(),
&swc_common::plugin::serialized::VersionedSerializable::new(key.to_string()),
)
.expect("Should be serializable");
let (key_ptr, key_ptr_len) = serialized.as_ptr();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,10 @@ impl SourceMapper for PluginSourceMapProxy {
ctxt: swc_common::SyntaxContext::empty(),
};

let serialized =
swc_common::plugin::serialized::PluginSerializedBytes::try_serialize(&span)
.expect("Should be serializable");
let serialized = swc_common::plugin::serialized::PluginSerializedBytes::try_serialize(
&swc_common::plugin::serialized::VersionedSerializable::new(span),
)
.expect("Should be serializable");
let (ptr, len) = serialized.as_ptr();

let ret = __merge_spans_proxy(
Expand Down
6 changes: 4 additions & 2 deletions crates/swc_plugin_runner/benches/ecma_invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{

use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion};
#[cfg(feature = "__rkyv")]
use swc_common::plugin::serialized::PluginSerializedBytes;
use swc_common::plugin::serialized::{PluginSerializedBytes, VersionedSerializable};
use swc_common::{
collections::AHashMap, plugin::metadata::TransformPluginMetadataContext, FileName,
FilePathMapping, Globals, Mark, SourceMap, GLOBALS,
Expand Down Expand Up @@ -62,6 +62,7 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
)
.unwrap();

let program = VersionedSerializable::new(program);
let program_ser = PluginSerializedBytes::try_serialize(&program).unwrap();

let mut transform_plugin_executor =
Expand All @@ -82,7 +83,8 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
)
.unwrap();

let experimental_metadata: AHashMap<String, String> = AHashMap::default();
let experimental_metadata: VersionedSerializable<AHashMap<String, String>> =
VersionedSerializable::new(AHashMap::default());
let _experimental_metadata =
PluginSerializedBytes::try_serialize(&experimental_metadata)
.expect("Should be a hashmap");
Expand Down
Loading