mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
feat(plugin): Wrap serialized struct with a version (#5128)
This commit is contained in:
parent
09d4aa4a0d
commit
82fbe15a57
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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())
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -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();
|
||||
@ -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,
|
||||
@ -197,7 +221,7 @@ impl RustPlugins {
|
||||
}
|
||||
}
|
||||
|
||||
serialized.deserialize()
|
||||
serialized.deserialize().map(|v| v.into_inner())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -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>>,
|
||||
{
|
||||
@ -105,7 +105,7 @@ 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>,
|
||||
@ -113,7 +113,7 @@ impl PluginSerializedBytes {
|
||||
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())
|
||||
@ -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>,
|
||||
@ -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>,
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
@ -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);
|
||||
@ -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();
|
||||
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
||||
@ -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()
|
||||
@ -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);
|
||||
@ -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());
|
||||
|
@ -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 {
|
||||
@ -73,7 +74,7 @@ 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);
|
||||
@ -81,7 +82,7 @@ impl Comments for PluginCommentsProxy {
|
||||
}
|
||||
|
||||
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);
|
||||
@ -129,7 +130,7 @@ 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);
|
||||
@ -137,7 +138,7 @@ impl Comments for PluginCommentsProxy {
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
|
||||
use swc_common::plugin::{
|
||||
deserialize_from_ptr, deserialize_from_ptr_into_fallible, PluginSerializedBytes,
|
||||
VersionedSerializable,
|
||||
};
|
||||
|
||||
/// A struct to exchange allocated data between memory spaces.
|
||||
@ -22,7 +23,7 @@ where
|
||||
F: FnOnce(i32) -> i32,
|
||||
{
|
||||
// Allocate AllocatedBytesPtr to get return value from the host
|
||||
let allocated_bytes_ptr = AllocatedBytesPtr(0, 0);
|
||||
let allocated_bytes_ptr = 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) =
|
||||
@ -50,6 +51,7 @@ where
|
||||
.expect("Should able to convert ptr length"),
|
||||
)
|
||||
.expect("Should able to deserialize AllocatedBytesPtr")
|
||||
.into_inner()
|
||||
})
|
||||
}
|
||||
|
||||
@ -72,6 +74,7 @@ where
|
||||
allocated_returned_value_ptr.1,
|
||||
)
|
||||
.expect("Returned value should be serializable")
|
||||
.into_inner()
|
||||
})
|
||||
}
|
||||
|
||||
@ -89,7 +92,7 @@ where
|
||||
R::Archived: rkyv::Deserialize<R, rkyv::de::deserializers::SharedDeserializeMap>,
|
||||
{
|
||||
// Allocate AllocatedBytesPtr to get return value from the host
|
||||
let allocated_bytes_ptr = AllocatedBytesPtr(0, 0);
|
||||
let allocated_bytes_ptr = 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) =
|
||||
@ -112,11 +115,10 @@ where
|
||||
let allocated_returned_value_ptr: AllocatedBytesPtr = unsafe {
|
||||
deserialize_from_ptr(
|
||||
serialized_allocated_bytes_raw_ptr,
|
||||
serialized_allocated_bytes_raw_ptr_size
|
||||
.try_into()
|
||||
.expect("Should able to convert ptr length"),
|
||||
serialized_allocated_bytes_raw_ptr_size as i32,
|
||||
)
|
||||
.expect("Should able to deserialize AllocatedBytesPtr")
|
||||
.into_inner()
|
||||
};
|
||||
|
||||
// Using AllocatedBytesPtr's value, reconstruct actual return value
|
||||
@ -126,5 +128,6 @@ where
|
||||
allocated_returned_value_ptr.1,
|
||||
)
|
||||
.expect("Returned value should be serializable")
|
||||
.into_inner()
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![allow(unused_variables)]
|
||||
#[cfg(feature = "plugin-mode")]
|
||||
use swc_common::{
|
||||
plugin::VersionedSerializable,
|
||||
source_map::{
|
||||
DistinctSources, FileLinesResult, MalformedSourceMapPositions, Pos, SpanSnippetError,
|
||||
},
|
||||
@ -225,8 +226,10 @@ impl SourceMapper for PluginSourceMapProxy {
|
||||
ctxt: swc_common::SyntaxContext::empty(),
|
||||
};
|
||||
|
||||
let serialized = swc_common::plugin::PluginSerializedBytes::try_serialize(&span)
|
||||
.expect("Should be serializable");
|
||||
let serialized = swc_common::plugin::PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(span),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
let (ptr, len) = serialized.as_ptr();
|
||||
|
||||
let ret = __merge_spans_proxy(
|
||||
|
@ -9,7 +9,10 @@ use std::{
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion};
|
||||
use once_cell::sync::Lazy;
|
||||
use swc_common::{plugin::PluginSerializedBytes, FileName, FilePathMapping, SourceMap};
|
||||
use swc_common::{
|
||||
plugin::{PluginSerializedBytes, VersionedSerializable},
|
||||
FileName, FilePathMapping, SourceMap,
|
||||
};
|
||||
use swc_ecma_ast::EsVersion;
|
||||
use swc_ecma_parser::parse_file_as_program;
|
||||
use swc_plugin_runner::cache::PluginModuleCache;
|
||||
@ -56,6 +59,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 res = swc_plugin_runner::apply_transform_plugin(
|
||||
@ -67,8 +71,10 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
|
||||
.join("swc_internal_plugin.wasm"),
|
||||
&cache,
|
||||
program_ser,
|
||||
PluginSerializedBytes::try_serialize(&String::from("{}")).unwrap(),
|
||||
PluginSerializedBytes::try_serialize(&String::from("{}")).unwrap(),
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from("{}")))
|
||||
.unwrap(),
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(String::from("{}")))
|
||||
.unwrap(),
|
||||
true,
|
||||
&cm,
|
||||
)
|
||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use parking_lot::Mutex;
|
||||
use swc_common::{
|
||||
comments::{Comments, SingleThreadedComments},
|
||||
plugin::PluginSerializedBytes,
|
||||
plugin::{PluginSerializedBytes, VersionedSerializable},
|
||||
BytePos,
|
||||
};
|
||||
use swc_plugin_proxy::COMMENTS;
|
||||
@ -124,7 +124,8 @@ pub fn add_leading_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
byte_pos,
|
||||
serialized
|
||||
.deserialize()
|
||||
.expect("Should be able to deserialize"),
|
||||
.expect("Should be able to deserialize")
|
||||
.into_inner(),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -135,7 +136,8 @@ pub fn add_leading_comments_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
byte_pos,
|
||||
serialized
|
||||
.deserialize()
|
||||
.expect("Should be able to deserialize"),
|
||||
.expect("Should be able to deserialize")
|
||||
.into_inner(),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -160,9 +162,10 @@ pub fn take_leading_comments_proxy(
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let leading_comments = comments.take_leading(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = leading_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
PluginSerializedBytes::try_serialize(&leading_comments)
|
||||
.expect("Should be serializable");
|
||||
let serialized_leading_comments_vec_bytes = PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(leading_comments),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
@ -194,9 +197,10 @@ pub fn get_leading_comments_proxy(
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let leading_comments = comments.get_leading(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = leading_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
PluginSerializedBytes::try_serialize(&leading_comments)
|
||||
.expect("Should be serializable");
|
||||
let serialized_leading_comments_vec_bytes = PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(leading_comments),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
@ -219,7 +223,8 @@ pub fn add_trailing_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
byte_pos,
|
||||
serialized
|
||||
.deserialize()
|
||||
.expect("Should be able to deserialize"),
|
||||
.expect("Should be able to deserialize")
|
||||
.into_inner(),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -230,7 +235,8 @@ pub fn add_trailing_comments_proxy(env: &CommentHostEnvironment, byte_pos: u32)
|
||||
byte_pos,
|
||||
serialized
|
||||
.deserialize()
|
||||
.expect("Should be able to deserialize"),
|
||||
.expect("Should be able to deserialize")
|
||||
.into_inner(),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -258,9 +264,10 @@ pub fn take_trailing_comments_proxy(
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let trailing_comments = comments.take_trailing(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = trailing_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
PluginSerializedBytes::try_serialize(&leading_comments)
|
||||
.expect("Should be serializable");
|
||||
let serialized_leading_comments_vec_bytes = PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(leading_comments),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
@ -287,9 +294,10 @@ pub fn get_trailing_comments_proxy(
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let trailing_comments = comments.get_trailing(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = trailing_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
PluginSerializedBytes::try_serialize(&leading_comments)
|
||||
.expect("Should be serializable");
|
||||
let serialized_leading_comments_vec_bytes = PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(leading_comments),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
|
@ -12,7 +12,8 @@ pub fn emit_diagnostics(env: &BaseHostEnvironment, bytes_ptr: i32, bytes_ptr_len
|
||||
let diagnostics_bytes = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
|
||||
let serialized = PluginSerializedBytes::from_slice(&diagnostics_bytes[..]);
|
||||
let diagnostic = PluginSerializedBytes::deserialize::<Diagnostic>(&serialized)
|
||||
.expect("Should able to be deserialized into diagnostic");
|
||||
.expect("Should able to be deserialized into diagnostic")
|
||||
.into_inner();
|
||||
|
||||
let mut builder =
|
||||
swc_common::errors::DiagnosticBuilder::new_diagnostic(handler, diagnostic);
|
||||
|
@ -1,4 +1,8 @@
|
||||
use swc_common::{hygiene::MutableMarkContext, plugin::PluginSerializedBytes, Mark, SyntaxContext};
|
||||
use swc_common::{
|
||||
hygiene::MutableMarkContext,
|
||||
plugin::{PluginSerializedBytes, VersionedSerializable},
|
||||
Mark, SyntaxContext,
|
||||
};
|
||||
|
||||
use crate::{host_environment::BaseHostEnvironment, memory_interop::write_into_memory_view};
|
||||
|
||||
@ -38,12 +42,13 @@ pub fn mark_is_descendant_of_proxy(
|
||||
let return_value = self_mark.is_descendant_of(ancestor);
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let serialized_bytes = PluginSerializedBytes::try_serialize(&MutableMarkContext(
|
||||
let context = VersionedSerializable::new(MutableMarkContext(
|
||||
self_mark.as_u32(),
|
||||
0,
|
||||
return_value as u32,
|
||||
))
|
||||
.expect("Should be serializable");
|
||||
));
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
}
|
||||
@ -56,12 +61,10 @@ pub fn mark_least_ancestor_proxy(env: &BaseHostEnvironment, a: u32, b: u32, allo
|
||||
let return_value = Mark::least_ancestor(a, b).as_u32();
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let serialized_bytes = PluginSerializedBytes::try_serialize(&MutableMarkContext(
|
||||
a.as_u32(),
|
||||
b.as_u32(),
|
||||
return_value,
|
||||
))
|
||||
.expect("Should be serializable");
|
||||
let context =
|
||||
VersionedSerializable::new(MutableMarkContext(a.as_u32(), b.as_u32(), return_value));
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
}
|
||||
@ -83,12 +86,13 @@ pub fn syntax_context_remove_mark_proxy(
|
||||
let return_value = self_mark.remove_mark();
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let serialized_bytes = PluginSerializedBytes::try_serialize(&MutableMarkContext(
|
||||
let context = VersionedSerializable::new(MutableMarkContext(
|
||||
self_mark.as_u32(),
|
||||
0,
|
||||
return_value.as_u32(),
|
||||
))
|
||||
.expect("Should be serializable");
|
||||
));
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use swc_common::{plugin::PluginSerializedBytes, BytePos, SourceMap, Span, SyntaxContext};
|
||||
use swc_common::{
|
||||
plugin::{PluginSerializedBytes, VersionedSerializable},
|
||||
BytePos, SourceMap, Span, SyntaxContext,
|
||||
};
|
||||
use wasmer::{LazyInit, Memory, NativeFunc};
|
||||
|
||||
use crate::memory_interop::{allocate_return_values_into_guest, write_into_memory_view};
|
||||
@ -41,7 +44,8 @@ pub fn lookup_char_pos_proxy(
|
||||
allocated_ret_ptr: i32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let ret = (env.source_map.lock()).lookup_char_pos(BytePos(byte_pos));
|
||||
let ret =
|
||||
VersionedSerializable::new((env.source_map.lock()).lookup_char_pos(BytePos(byte_pos)));
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
@ -92,7 +96,8 @@ pub fn merge_spans_proxy(
|
||||
let ret = (env.source_map.lock()).merge_spans(sp_lhs, sp_rhs);
|
||||
if let Some(span) = ret {
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&span).expect("Should be serializable");
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(span))
|
||||
.expect("Should be serializable");
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
1
|
||||
} else {
|
||||
@ -116,7 +121,7 @@ pub fn span_to_lines_proxy(
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_lines(span);
|
||||
let ret = VersionedSerializable::new((env.source_map.lock()).span_to_lines(span));
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
@ -144,7 +149,7 @@ pub fn lookup_byte_offset_proxy(
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let byte_pos = BytePos(byte_pos);
|
||||
let ret = (env.source_map.lock()).lookup_byte_offset(byte_pos);
|
||||
let ret = VersionedSerializable::new((env.source_map.lock()).lookup_byte_offset(byte_pos));
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
@ -178,7 +183,7 @@ pub fn span_to_string_proxy(
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_string(span);
|
||||
let ret = VersionedSerializable::new((env.source_map.lock()).span_to_string(span));
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
@ -211,7 +216,7 @@ pub fn span_to_filename_proxy(
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_filename(span);
|
||||
let ret = VersionedSerializable::new((env.source_map.lock()).span_to_filename(span));
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use swc_common::plugin::PluginSerializedBytes;
|
||||
use swc_common::plugin::{PluginSerializedBytes, VersionedSerializable};
|
||||
use swc_plugin_proxy::AllocatedBytesPtr;
|
||||
use wasmer::{Array, Memory, NativeFunc, WasmPtr};
|
||||
|
||||
@ -92,10 +92,11 @@ pub fn allocate_return_values_into_guest(
|
||||
.expect("Should able to allocate memory in the plugin")
|
||||
});
|
||||
|
||||
let allocated_bytes =
|
||||
VersionedSerializable::new(AllocatedBytesPtr(allocated_ptr, allocated_ptr_len));
|
||||
// Retuning (allocated_ptr, len) into caller (plugin)
|
||||
let comment_ptr_serialized =
|
||||
PluginSerializedBytes::try_serialize(&AllocatedBytesPtr(allocated_ptr, allocated_ptr_len))
|
||||
.expect("Should be serializable");
|
||||
PluginSerializedBytes::try_serialize(&allocated_bytes).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &comment_ptr_serialized, |_| allocated_ret_ptr);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ impl TransformExecutor {
|
||||
if returned_ptr_result == 0 {
|
||||
Ok(ret)
|
||||
} else {
|
||||
let err: PluginError = ret.deserialize()?;
|
||||
let err: PluginError = ret.deserialize()?.into_inner();
|
||||
match err {
|
||||
PluginError::SizeInteropFailure(msg) => Err(anyhow!(
|
||||
"Failed to convert pointer size to calculate: {}",
|
||||
|
@ -5,7 +5,12 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use swc_common::{errors::HANDLER, plugin::PluginSerializedBytes, sync::Lazy, FileName};
|
||||
use swc_common::{
|
||||
errors::HANDLER,
|
||||
plugin::{PluginSerializedBytes, VersionedSerializable},
|
||||
sync::Lazy,
|
||||
FileName,
|
||||
};
|
||||
use swc_ecma_ast::{CallExpr, Callee, EsVersion, Expr, Lit, MemberExpr, Program, Str};
|
||||
use swc_ecma_parser::{parse_file_as_program, EsConfig, Syntax};
|
||||
use swc_ecma_visit::{Visit, VisitWith};
|
||||
@ -80,12 +85,14 @@ fn internal() -> Result<(), Error> {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let program = PluginSerializedBytes::try_serialize(&program).expect("Should serializable");
|
||||
let program = PluginSerializedBytes::try_serialize(&VersionedSerializable::new(program))
|
||||
.expect("Should serializable");
|
||||
let config =
|
||||
PluginSerializedBytes::try_serialize(&"{}".to_string()).expect("Should serializable");
|
||||
let context = PluginSerializedBytes::try_serialize(
|
||||
&"{sourceFileName: 'single_plugin_test'}".to_string(),
|
||||
)
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new("{}".to_string()))
|
||||
.expect("Should serializable");
|
||||
let context = PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
|
||||
"{sourceFileName: 'single_plugin_test'}".to_string(),
|
||||
))
|
||||
.expect("Should serializable");
|
||||
|
||||
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
|
||||
@ -104,7 +111,8 @@ fn internal() -> Result<(), Error> {
|
||||
|
||||
let program: Program = program_bytes
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize");
|
||||
.expect("Should able to deserialize")
|
||||
.into_inner();
|
||||
let mut visitor = TestVisitor {
|
||||
plugin_transform_found: false,
|
||||
};
|
||||
@ -132,12 +140,14 @@ fn internal() -> Result<(), Error> {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let program = PluginSerializedBytes::try_serialize(&program).expect("Should serializable");
|
||||
let program = PluginSerializedBytes::try_serialize(&VersionedSerializable::new(program))
|
||||
.expect("Should serializable");
|
||||
let config =
|
||||
PluginSerializedBytes::try_serialize(&"{}".to_string()).expect("Should serializable");
|
||||
let context = PluginSerializedBytes::try_serialize(
|
||||
&"{sourceFileName: 'single_plugin_handler_test'}".to_string(),
|
||||
)
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new("{}".to_string()))
|
||||
.expect("Should serializable");
|
||||
let context = PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
|
||||
"{sourceFileName: 'single_plugin_handler_test'}".to_string(),
|
||||
))
|
||||
.expect("Should serializable");
|
||||
|
||||
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
|
||||
@ -176,7 +186,8 @@ fn internal() -> Result<(), Error> {
|
||||
.unwrap();
|
||||
|
||||
let mut serialized_program =
|
||||
PluginSerializedBytes::try_serialize(&program).expect("Should serializable");
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(program))
|
||||
.expect("Should serializable");
|
||||
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
|
||||
|
||||
serialized_program = swc_plugin_runner::apply_transform_plugin(
|
||||
@ -184,10 +195,11 @@ fn internal() -> Result<(), Error> {
|
||||
&path,
|
||||
&cache,
|
||||
serialized_program,
|
||||
PluginSerializedBytes::try_serialize(&"{}".to_string()).expect("Should serializable"),
|
||||
PluginSerializedBytes::try_serialize(
|
||||
&"{sourceFileName: 'multiple_plugin_test'}".to_string(),
|
||||
)
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new("{}".to_string()))
|
||||
.expect("Should serializable"),
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
|
||||
"{sourceFileName: 'multiple_plugin_test'}".to_string(),
|
||||
))
|
||||
.expect("Should serializable"),
|
||||
false,
|
||||
&cm,
|
||||
@ -200,10 +212,11 @@ fn internal() -> Result<(), Error> {
|
||||
&path,
|
||||
&cache,
|
||||
serialized_program,
|
||||
PluginSerializedBytes::try_serialize(&"{}".to_string()).expect("Should serializable"),
|
||||
PluginSerializedBytes::try_serialize(
|
||||
&"{sourceFileName: 'multiple_plugin_test2'}".to_string(),
|
||||
)
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new("{}".to_string()))
|
||||
.expect("Should serializable"),
|
||||
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(
|
||||
"{sourceFileName: 'multiple_plugin_test2'}".to_string(),
|
||||
))
|
||||
.expect("Should serializable"),
|
||||
false,
|
||||
&cm,
|
||||
@ -212,7 +225,8 @@ fn internal() -> Result<(), Error> {
|
||||
|
||||
let program: Program = serialized_program
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize");
|
||||
.expect("Should able to deserialize")
|
||||
.into_inner();
|
||||
let mut visitor = TestVisitor {
|
||||
plugin_transform_found: false,
|
||||
};
|
||||
|
16
tests/rust-plugins/swc_internal_plugin/Cargo.lock
generated
16
tests/rust-plugins/swc_internal_plugin/Cargo.lock
generated
@ -722,7 +722,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_common"
|
||||
version = "0.20.2"
|
||||
version = "0.21.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@ -750,7 +750,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_ast"
|
||||
version = "0.81.0"
|
||||
version = "0.82.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytecheck",
|
||||
@ -767,7 +767,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_parser"
|
||||
version = "0.108.1"
|
||||
version = "0.109.1"
|
||||
dependencies = [
|
||||
"either",
|
||||
"enum_kind",
|
||||
@ -784,7 +784,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_utils"
|
||||
version = "0.90.0"
|
||||
version = "0.91.0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
@ -798,7 +798,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_visit"
|
||||
version = "0.67.1"
|
||||
version = "0.68.0"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
@ -810,7 +810,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecmascript"
|
||||
version = "0.175.0"
|
||||
version = "0.176.0"
|
||||
dependencies = [
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
@ -848,7 +848,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_plugin"
|
||||
version = "0.71.0"
|
||||
version = "0.72.0"
|
||||
dependencies = [
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
@ -868,7 +868,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_plugin_proxy"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"better_scoped_tls",
|
||||
"bytecheck",
|
||||
|
Loading…
Reference in New Issue
Block a user