Skip to content

Commit b484e61

Browse files
kwonojGiveMe-A-Name
authored andcommitted
refactor(plugin): Refactor transform executor (swc-project#5147)
1 parent 51b1144 commit b484e61

File tree

10 files changed

+171
-147
lines changed

10 files changed

+171
-147
lines changed

crates/swc/src/plugin.rs

Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ impl RustPlugins {
9595
inner: self.comments.clone(),
9696
},
9797
|| {
98+
let span = tracing::span!(tracing::Level::INFO, "serialize_program").entered();
9899
let program = VersionedSerializable::new(n);
99-
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;
100+
let mut serialized_program = PluginSerializedBytes::try_serialize(&program)?;
101+
drop(span);
100102

101103
// Run plugin transformation against current program.
102104
// We do not serialize / deserialize between each plugin execution but
@@ -106,65 +108,77 @@ impl RustPlugins {
106108
// transform.
107109
if let Some(plugins) = &self.plugins {
108110
for p in plugins {
111+
let resolved_path = self
112+
.resolver
113+
.as_ref()
114+
.expect("filesystem_cache should provide resolver")
115+
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
116+
117+
let path = if let FileName::Real(value) = resolved_path {
118+
Arc::new(value)
119+
} else {
120+
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
121+
};
122+
123+
let mut transform_plugin_executor =
124+
swc_plugin_runner::create_plugin_transform_executor(
125+
&path,
126+
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
127+
&self.source_map,
128+
)?;
129+
109130
let span = tracing::span!(
110131
tracing::Level::INFO,
111132
"serialize_context",
112133
plugin_module = p.0.as_str()
113134
);
114135
let context_span_guard = span.enter();
115136

116-
let config_json = serde_json::to_string(&p.1)
137+
let serialized_config_json = serde_json::to_string(&p.1)
117138
.context("Failed to serialize plugin config as json")
118139
.and_then(|value| {
119140
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
120141
value,
121142
))
122143
})?;
123144

124-
let context_json = serde_json::to_string(&self.plugin_context)
145+
let serialized_context_json = serde_json::to_string(&self.plugin_context)
125146
.context("Failed to serialize plugin context as json")
126147
.and_then(|value| {
127148
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
128149
value,
129150
))
130151
})?;
131-
132-
let resolved_path = self
133-
.resolver
134-
.as_ref()
135-
.expect("filesystem_cache should provide resolver")
136-
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
137-
138-
let path = if let FileName::Real(value) = resolved_path {
139-
Arc::new(value)
140-
} else {
141-
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
142-
};
143152
drop(context_span_guard);
144153

145154
let span = tracing::span!(
146155
tracing::Level::INFO,
147156
"execute_plugin_runner",
148157
plugin_module = p.0.as_str()
149-
);
150-
let transform_span_guard = span.enter();
151-
serialized = swc_plugin_runner::apply_transform_plugin(
152-
&p.0,
153-
&path,
154-
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
155-
serialized,
156-
config_json,
157-
context_json,
158-
should_enable_comments_proxy,
159-
&self.source_map,
160-
)?;
161-
drop(transform_span_guard);
158+
)
159+
.entered();
160+
161+
serialized_program = transform_plugin_executor
162+
.transform(
163+
&serialized_program,
164+
&serialized_config_json,
165+
&serialized_context_json,
166+
should_enable_comments_proxy,
167+
)
168+
.with_context(|| {
169+
format!(
170+
"failed to invoke `{}` as js transform plugin at {}",
171+
&p.0,
172+
path.display()
173+
)
174+
})?;
175+
drop(span);
162176
}
163177
}
164178

165179
// Plugin transformation is done. Deserialize transformed bytes back
166180
// into Program
167-
serialized.deserialize().map(|v| v.into_inner())
181+
serialized_program.deserialize().map(|v| v.into_inner())
168182
},
169183
)
170184
}
@@ -188,40 +202,47 @@ impl RustPlugins {
188202
},
189203
|| {
190204
let program = VersionedSerializable::new(n);
191-
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;
205+
let mut serialized_program = PluginSerializedBytes::try_serialize(&program)?;
192206

193207
if let Some(plugins) = &self.plugins {
194208
for p in plugins {
195-
let config_json = serde_json::to_string(&p.1)
209+
let serialized_config_json = serde_json::to_string(&p.1)
196210
.context("Failed to serialize plugin config as json")
197211
.and_then(|value| {
198212
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
199213
value,
200214
))
201215
})?;
202216

203-
let context_json = serde_json::to_string(&self.plugin_context)
217+
let serialized_context_json = serde_json::to_string(&self.plugin_context)
204218
.context("Failed to serialize plugin context as json")
205219
.and_then(|value| {
206220
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
207221
value,
208222
))
209223
})?;
210224

211-
serialized = swc_plugin_runner::apply_transform_plugin(
212-
&p.0,
213-
&PathBuf::from(&p.0),
214-
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
215-
serialized,
216-
config_json,
217-
context_json,
218-
should_enable_comments_proxy,
219-
&self.source_map,
220-
)?;
225+
let mut transform_plugin_executor =
226+
swc_plugin_runner::create_plugin_transform_executor(
227+
&PathBuf::from(&p.0),
228+
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
229+
&self.source_map,
230+
)?;
231+
232+
serialized_program = transform_plugin_executor
233+
.transform(
234+
&serialized_program,
235+
&serialized_config_json,
236+
&serialized_context_json,
237+
should_enable_comments_proxy,
238+
)
239+
.with_context(|| {
240+
format!("failed to invoke `{}` as js transform plugin", &p.0)
241+
})?;
221242
}
222243
}
223244

224-
serialized.deserialize().map(|v| v.into_inner())
245+
serialized_program.deserialize().map(|v| v.into_inner())
225246
},
226247
)
227248
}

crates/swc_cli/src/commands/plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl VisitMut for TransformVisitor {
228228
/// as returning ptr back to host.
229229
///
230230
/// It is possible to opt out from macro by writing transform fn manually via
231-
/// `__plugin_process_impl(
231+
/// `__transform_plugin_process_impl(
232232
/// ast_ptr: *const u8,
233233
/// ast_ptr_len: i32,
234234
/// config_str_ptr: *const u8,

crates/swc_plugin_macro/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub fn plugin_transform(
1919

2020
fn handle_func(func: ItemFn) -> TokenStream {
2121
let ident = func.sig.ident.clone();
22-
let process_impl_ident = Ident::new("__plugin_process_impl", Span::call_site());
22+
let transform_process_impl_ident =
23+
Ident::new("__transform_plugin_process_impl", Span::call_site());
2324

2425
let ret = quote! {
2526
#func
@@ -59,7 +60,7 @@ fn handle_func(func: ItemFn) -> TokenStream {
5960
// There are some cases error won't be wrapped up however - for example, we expect
6061
// serialization of PluginError itself should succeed.
6162
#[no_mangle]
62-
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 {
63+
pub fn #transform_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 {
6364
// Reconstruct `Program` & config string from serialized program
6465
// Host (SWC) should allocate memory, copy bytes and pass ptr to plugin.
6566
let program = unsafe { swc_plugin::deserialize_from_ptr(ast_ptr, ast_ptr_len).map(|v| v.into_inner()) };

crates/swc_plugin_proxy/src/comments/host_comments_storage.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
/// specifically `SingleThreadedComments`. It doesn't support thread-safety
66
/// which does not allow to be passed into wasmerEnv (HostEnvironment). A scoped
77
/// tls holds inner comments as global, per each transform execution. Refer
8-
/// `swc::RustPlugins::apply_transform_plugin` for the responsibility to manage
9-
/// actual data.
8+
/// `swc_plugin::transform_execytor::TransformExecutor::transform` for the
9+
/// responsibility to manage actual data.
1010
///
1111
/// Should never attempt to use this other than plugin_runner.
1212
// TODO: This storage does not support mutable yet

crates/swc_plugin_runner/benches/invoke.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,32 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
6262
let program = VersionedSerializable::new(program);
6363
let program_ser = PluginSerializedBytes::try_serialize(&program).unwrap();
6464

65-
let res = swc_plugin_runner::apply_transform_plugin(
66-
"test",
65+
let mut transform_plugin_executor = swc_plugin_runner::create_plugin_transform_executor(
6766
&plugin_dir
6867
.join("target")
6968
.join("wasm32-unknown-unknown")
7069
.join("release")
7170
.join("swc_internal_plugin.wasm"),
72-
&cache,
73-
program_ser,
74-
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from("{}")))
75-
.unwrap(),
76-
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from("{}")))
77-
.unwrap(),
78-
true,
71+
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
7972
&cm,
8073
)
8174
.unwrap();
8275

76+
let res = transform_plugin_executor
77+
.transform(
78+
&program_ser,
79+
&PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from(
80+
"{}",
81+
)))
82+
.unwrap(),
83+
&PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from(
84+
"{}",
85+
)))
86+
.unwrap(),
87+
true,
88+
)
89+
.unwrap();
90+
8391
let _ = black_box(res);
8492
})
8593
}

crates/swc_plugin_runner/src/lib.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{path::Path, sync::Arc};
22

3-
use anyhow::{Context, Error};
3+
use anyhow::Error;
44
use once_cell::sync::Lazy;
5-
use swc_common::{plugin::PluginSerializedBytes, SourceMap};
5+
use swc_common::SourceMap;
66
use transform_executor::TransformExecutor;
77

88
pub mod cache;
@@ -12,33 +12,18 @@ mod load_plugin;
1212
mod memory_interop;
1313
mod transform_executor;
1414

15-
// entrypoint fn swc calls to perform its transform via plugin.
16-
#[allow(clippy::too_many_arguments)]
17-
pub fn apply_transform_plugin(
18-
plugin_name: &str,
15+
/**
16+
* Attempt to create a executor to run plugin binaries.
17+
* Internally this will try to load binary from given cache which can fail,
18+
* returns error in that case.
19+
*
20+
* Note you CANNOT reuse executor once trasform has been executed: executor
21+
* is stateful.
22+
*/
23+
pub fn create_plugin_transform_executor(
1924
path: &Path,
2025
cache: &Lazy<cache::PluginModuleCache>,
21-
program: PluginSerializedBytes,
22-
config_json: PluginSerializedBytes,
23-
context_json: PluginSerializedBytes,
24-
should_enable_comments_proxy: bool,
2526
source_map: &Arc<SourceMap>,
26-
) -> Result<PluginSerializedBytes, Error> {
27-
(|| -> Result<_, Error> {
28-
let mut transform_tracker = TransformExecutor::new(path, cache, source_map)?;
29-
let should_enable_comments_proxy = if should_enable_comments_proxy { 1 } else { 0 };
30-
transform_tracker.transform(
31-
&program,
32-
&config_json,
33-
&context_json,
34-
should_enable_comments_proxy,
35-
)
36-
})()
37-
.with_context(|| {
38-
format!(
39-
"failed to invoke `{}` as js transform plugin at {}",
40-
plugin_name,
41-
path.display()
42-
)
43-
})
27+
) -> Result<TransformExecutor, Error> {
28+
TransformExecutor::new(path, cache, source_map)
4429
}

crates/swc_plugin_runner/src/transform_executor.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl TransformExecutor {
4040
exported_plugin_transform: instance
4141
.exports
4242
.get_native_function::<(i32, i32, i32, i32, i32, i32, i32), i32>(
43-
"__plugin_process_impl",
43+
"__transform_plugin_process_impl",
4444
)?,
4545
exported_plugin_free: instance
4646
.exports
@@ -102,14 +102,26 @@ impl TransformExecutor {
102102
}
103103
}
104104

105+
/**
106+
* Check compile-time versions of AST schema between the plugin and
107+
* the host. Returns true if it's compatible, false otherwise.
108+
*
109+
* Host should appropriately handle if plugin is not compatible to the
110+
* current runtime.
111+
*/
112+
pub fn is_transform_schema_compatible(&self) -> bool {
113+
todo!("Not supported yet");
114+
}
115+
105116
#[tracing::instrument(level = "info", skip_all)]
106117
pub fn transform(
107118
&mut self,
108119
program: &PluginSerializedBytes,
109120
config: &PluginSerializedBytes,
110121
context: &PluginSerializedBytes,
111-
should_enable_comments_proxy: i32,
122+
should_enable_comments_proxy: bool,
112123
) -> Result<PluginSerializedBytes, Error> {
124+
let should_enable_comments_proxy = if should_enable_comments_proxy { 1 } else { 0 };
113125
let guest_program_ptr = self.write_bytes_into_guest(program)?;
114126
let config_str_ptr = self.write_bytes_into_guest(config)?;
115127
let context_str_ptr = self.write_bytes_into_guest(context)?;

0 commit comments

Comments
 (0)