mirror of
https://github.com/swc-project/swc.git
synced 2024-12-22 21:21:31 +03:00
feat(plugin/runner): Update wasmer
to v3
(#7197)
**Description:** This PR reattempts https://github.com/swc-project/swc/pull/5456. Most of the changes are for the breaking changes of wasmer@3, as well as enabling rkyv's strict mode (https://github.com/swc-project/swc/pull/6922). This could not be seperated since wasmer@3 enables strict mode by default without a way to turn it off. There are a couple of changes worth noting: - Disabling in-memory module lookup: https://github.com/swc-project/swc/pull/7197/files#diff-3bda5def6ce2b7553c3b3a5ad241c0bdb7021e67b7de1e594df4cd5a54d403b3R154-R159 - Disabling plugin_runner in bindings_wasm: https://github.com/swc-project/swc/pull/7197/files#diff-dc3ded556a1fd709a129acd588e5eda651b842c6acc3f5340d40088a1f927facR310-R312 - Skipping plugin compat test: https://github.com/swc-project/swc/pull/7197/files#diff-531197dfcefba05faca53f0cf442ecc2dc6b59d5ead01979f5ffb912aa36249aR64-R66
This commit is contained in:
parent
e116fedd22
commit
56bdacc72d
2
.github/workflows/CI.yml
vendored
2
.github/workflows/CI.yml
vendored
@ -232,7 +232,7 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
runner: ubuntu-latest
|
||||
check: |
|
||||
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin --exclude-features plugin_transform_schema_v1 --exclude-features plugin_transform_schema_vtest --exclude-features plugin-bytecheck
|
||||
cargo hack check --feature-powerset --no-dev-deps --exclude-features debug --exclude-features plugin --exclude-features plugin_transform_schema_v1 --exclude-features plugin_transform_schema_vtest --exclude-features plugin-bytecheck --exclude-features plugin_transform_host_js --exclude-features plugin_transform_host_native
|
||||
- crate: swc
|
||||
os: windows-latest
|
||||
runner: windows-latest
|
||||
|
1428
Cargo.lock
generated
1428
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,20 @@ default = ["swc_v1"]
|
||||
swc_v1 = []
|
||||
swc_v2 = []
|
||||
# This feature exists to allow cargo operations
|
||||
plugin = ["swc_core/plugin_transform_host_js"]
|
||||
# [TODO]: this is disabled due to signature mismatch between host_native and host_js,
|
||||
# which causes build errors like
|
||||
# .call(&mut self.store, ptr.0, ptr.1)
|
||||
# | ^^^^ the trait `NativeWasmTypeInto` is not implemented for `u32`
|
||||
# |
|
||||
# = help: the following other types implement trait `NativeWasmTypeInto`:
|
||||
# f32
|
||||
# f64
|
||||
# i32
|
||||
# i64
|
||||
# u128
|
||||
plugin = [
|
||||
#"swc_core/plugin_transform_host_js"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.66"
|
||||
|
@ -307,7 +307,9 @@ macro_rules! build_transform_sync {
|
||||
|
||||
let c = $crate::wasm::compiler();
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
//[TODO]: refer binding_core_wasm/Cargo.toml,
|
||||
//disables via renaming feature to arbitary name
|
||||
#[cfg(feature = "__plugin")]
|
||||
{
|
||||
if experimental_plugin_bytes_resolver.is_object() {
|
||||
use $crate::wasm::js_sys::{Array, Object, Uint8Array};
|
||||
|
@ -46,6 +46,11 @@ plugin_transform_schema_vtest = [
|
||||
"swc_plugin_runner/plugin_transform_schema_vtest",
|
||||
]
|
||||
|
||||
plugin_transform_host_js = ["swc_plugin_runner/plugin_transform_host_js"]
|
||||
plugin_transform_host_native = [
|
||||
"swc_plugin_runner/plugin_transform_host_native",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
ahash = "0.7.4"
|
||||
anyhow = "1"
|
||||
|
@ -22,14 +22,18 @@ rkyv-bytecheck-impl = ["__rkyv", "rkyv-latest"]
|
||||
[dependencies]
|
||||
bytecheck = { version = "0.6.9", optional = true }
|
||||
once_cell = "1"
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true }
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true, features = [
|
||||
"strict",
|
||||
] }
|
||||
# This is to avoid cargo version selection conflict between rkyv=0.7.40 and other versions, as it is strictly pinned
|
||||
# cannot be merged.
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true }
|
||||
rustc-hash = "1.1.0"
|
||||
serde = "1"
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true, features = [
|
||||
"strict",
|
||||
] }
|
||||
rustc-hash = "1.1.0"
|
||||
serde = "1"
|
||||
string_cache = "0.8.7"
|
||||
triomphe = "0.1.8"
|
||||
triomphe = "0.1.8"
|
||||
|
||||
[build-dependencies]
|
||||
string_cache_codegen = "0.5.2"
|
||||
|
@ -60,7 +60,7 @@ new_debug_unreachable = "1.0.4"
|
||||
num-bigint = "0.4"
|
||||
once_cell = "1.10.0"
|
||||
parking_lot = { version = "0.12.0", optional = true }
|
||||
rkyv = { version = "=0.7.40", optional = true }
|
||||
rkyv = { version = "=0.7.40", optional = true, features = ["strict"] }
|
||||
# This is to avoid cargo version selection conflict between rkyv=0.7.40 and other versions, as it is strictly pinned
|
||||
# cannot be merged.
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true }
|
||||
|
@ -16,6 +16,17 @@ use rkyv_latest as rkyv;
|
||||
use super::{snippet::Style, Applicability, CodeSuggestion, Level, Substitution, SubstitutionPart};
|
||||
use crate::syntax_pos::{MultiSpan, Span};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub struct Message(pub String, pub Style);
|
||||
|
||||
#[must_use]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
@ -28,7 +39,7 @@ use crate::syntax_pos::{MultiSpan, Span};
|
||||
)]
|
||||
pub struct Diagnostic {
|
||||
pub level: Level,
|
||||
pub message: Vec<(String, Style)>,
|
||||
pub message: Vec<Message>,
|
||||
pub code: Option<DiagnosticId>,
|
||||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
@ -61,7 +72,7 @@ pub enum DiagnosticId {
|
||||
)]
|
||||
pub struct SubDiagnostic {
|
||||
pub level: Level,
|
||||
pub message: Vec<(String, Style)>,
|
||||
pub message: Vec<Message>,
|
||||
pub span: MultiSpan,
|
||||
pub render_span: Option<MultiSpan>,
|
||||
}
|
||||
@ -117,7 +128,7 @@ impl Diagnostic {
|
||||
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
|
||||
Diagnostic {
|
||||
level,
|
||||
message: vec![(message.to_owned(), Style::NoStyle)],
|
||||
message: vec![Message(message.to_owned(), Style::NoStyle)],
|
||||
code,
|
||||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
@ -184,18 +195,18 @@ impl Diagnostic {
|
||||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self {
|
||||
let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
|
||||
let mut msg: Vec<_> = vec![Message(format!("expected {} `", label), Style::NoStyle)];
|
||||
msg.extend(expected.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
|
||||
StringPart::Normal(ref s) => Message(s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => Message(s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
|
||||
msg.push((format!(" found {} `", label), Style::NoStyle));
|
||||
msg.push(Message(format!("`{}\n", expected_extra), Style::NoStyle));
|
||||
msg.push(Message(format!(" found {} `", label), Style::NoStyle));
|
||||
msg.extend(found.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
|
||||
StringPart::Normal(ref s) => Message(s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => Message(s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push((format!("`{}", found_extra), Style::NoStyle));
|
||||
msg.push(Message(format!("`{}", found_extra), Style::NoStyle));
|
||||
|
||||
// For now, just attach these as notes
|
||||
self.highlighted_note(msg);
|
||||
@ -204,9 +215,9 @@ impl Diagnostic {
|
||||
|
||||
pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
|
||||
self.highlighted_note(vec![
|
||||
(format!("`{}` from trait: `", name), Style::NoStyle),
|
||||
(signature, Style::Highlight),
|
||||
("`".to_string(), Style::NoStyle),
|
||||
Message(format!("`{}` from trait: `", name), Style::NoStyle),
|
||||
Message(signature, Style::Highlight),
|
||||
Message("`".to_string(), Style::NoStyle),
|
||||
]);
|
||||
self
|
||||
}
|
||||
@ -216,7 +227,7 @@ impl Diagnostic {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
|
||||
pub fn highlighted_note(&mut self, msg: Vec<Message>) -> &mut Self {
|
||||
self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
@ -431,7 +442,7 @@ impl Diagnostic {
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<(String, Style)> {
|
||||
pub fn styled_message(&self) -> &Vec<Message> {
|
||||
&self.message
|
||||
}
|
||||
|
||||
@ -454,7 +465,7 @@ impl Diagnostic {
|
||||
) {
|
||||
let sub = SubDiagnostic {
|
||||
level,
|
||||
message: vec![(message.to_owned(), Style::NoStyle)],
|
||||
message: vec![Message(message.to_owned(), Style::NoStyle)],
|
||||
span,
|
||||
render_span,
|
||||
};
|
||||
@ -466,7 +477,7 @@ impl Diagnostic {
|
||||
fn sub_with_highlights(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: Vec<(String, Style)>,
|
||||
message: Vec<Message>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<MultiSpan>,
|
||||
) {
|
||||
@ -488,7 +499,7 @@ impl SubDiagnostic {
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<(String, Style)> {
|
||||
pub fn styled_message(&self) -> &Vec<Message> {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ use unicode_width;
|
||||
|
||||
use self::Destination::*;
|
||||
use super::{
|
||||
diagnostic::Message,
|
||||
snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString},
|
||||
styled_buffer::StyledBuffer,
|
||||
CodeSuggestion, DiagnosticBuilder, DiagnosticId, Level, SourceMapperDyn, SubDiagnostic,
|
||||
@ -842,7 +843,7 @@ impl EmitterWriter {
|
||||
if spans_updated {
|
||||
children.push(SubDiagnostic {
|
||||
level: Level::Note,
|
||||
message: vec![(
|
||||
message: vec![Message(
|
||||
"this error originates in a macro outside of the current crate (in Nightly \
|
||||
builds, run with -Z external-macro-backtrace for more info)"
|
||||
.to_string(),
|
||||
@ -859,7 +860,7 @@ impl EmitterWriter {
|
||||
fn msg_to_buffer(
|
||||
&self,
|
||||
buffer: &mut StyledBuffer,
|
||||
msg: &[(String, Style)],
|
||||
msg: &[Message],
|
||||
padding: usize,
|
||||
label: &str,
|
||||
override_style: Option<Style>,
|
||||
@ -912,7 +913,7 @@ impl EmitterWriter {
|
||||
// see how it *looks* with
|
||||
// very *weird* formats
|
||||
// see?
|
||||
for (text, style) in msg.iter() {
|
||||
for Message(text, ref style) in msg.iter() {
|
||||
let lines = text.split('\n').collect::<Vec<_>>();
|
||||
if lines.len() > 1 {
|
||||
for (i, line) in lines.iter().enumerate() {
|
||||
@ -932,7 +933,7 @@ impl EmitterWriter {
|
||||
fn emit_message_default(
|
||||
&mut self,
|
||||
msp: &MultiSpan,
|
||||
msg: &[(String, Style)],
|
||||
msg: &[Message],
|
||||
code: &Option<DiagnosticId>,
|
||||
level: Level,
|
||||
max_line_num_len: usize,
|
||||
@ -975,7 +976,7 @@ impl EmitterWriter {
|
||||
if !level_str.is_empty() {
|
||||
buffer.append(0, ": ", header_style);
|
||||
}
|
||||
for (text, _) in msg.iter() {
|
||||
for Message(text, _) in msg.iter() {
|
||||
buffer.append(0, text, header_style);
|
||||
}
|
||||
}
|
||||
@ -1212,7 +1213,7 @@ impl EmitterWriter {
|
||||
}
|
||||
self.msg_to_buffer(
|
||||
&mut buffer,
|
||||
&[(suggestion.msg.to_owned(), Style::NoStyle)],
|
||||
&[Message(suggestion.msg.to_owned(), Style::NoStyle)],
|
||||
max_line_num_len,
|
||||
"suggestion",
|
||||
Some(Style::HeaderMsg),
|
||||
@ -1332,7 +1333,7 @@ impl EmitterWriter {
|
||||
fn emit_messages_default(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: &[(String, Style)],
|
||||
message: &[Message],
|
||||
code: &Option<DiagnosticId>,
|
||||
span: &MultiSpan,
|
||||
children: &[SubDiagnostic],
|
||||
|
@ -488,8 +488,8 @@ impl SourceMap {
|
||||
|
||||
if lo.file.start_pos != hi.file.start_pos {
|
||||
return Err(Box::new(SpanLinesError::DistinctSources(DistinctSources {
|
||||
begin: (lo.file.name.clone(), lo.file.start_pos),
|
||||
end: (hi.file.name.clone(), hi.file.start_pos),
|
||||
begin: FilePos(lo.file.name.clone(), lo.file.start_pos),
|
||||
end: FilePos(hi.file.name.clone(), hi.file.start_pos),
|
||||
})));
|
||||
}
|
||||
assert!(hi.line >= lo.line);
|
||||
@ -565,8 +565,8 @@ impl SourceMap {
|
||||
if local_begin.sf.start_pos != local_end.sf.start_pos {
|
||||
Err(Box::new(SpanSnippetError::DistinctSources(
|
||||
DistinctSources {
|
||||
begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos),
|
||||
end: (local_end.sf.name.clone(), local_end.sf.start_pos),
|
||||
begin: FilePos(local_begin.sf.name.clone(), local_begin.sf.start_pos),
|
||||
end: FilePos(local_end.sf.name.clone(), local_end.sf.start_pos),
|
||||
},
|
||||
)))
|
||||
} else {
|
||||
|
@ -312,6 +312,17 @@ impl FileName {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub struct PrimarySpanLabel(pub Span, pub String);
|
||||
|
||||
/// A collection of spans. Spans have two orthogonal attributes:
|
||||
///
|
||||
/// - they can be *primary spans*. In this case they are the locus of the error,
|
||||
@ -329,7 +340,7 @@ impl FileName {
|
||||
)]
|
||||
pub struct MultiSpan {
|
||||
primary_spans: Vec<Span>,
|
||||
span_labels: Vec<(Span, String)>,
|
||||
span_labels: Vec<PrimarySpanLabel>,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -633,7 +644,7 @@ impl MultiSpan {
|
||||
}
|
||||
|
||||
pub fn push_span_label(&mut self, span: Span, label: String) {
|
||||
self.span_labels.push((span, label));
|
||||
self.span_labels.push(PrimarySpanLabel(span, label));
|
||||
}
|
||||
|
||||
/// Selects the first primary span (if any)
|
||||
@ -689,7 +700,7 @@ impl MultiSpan {
|
||||
let mut span_labels = self
|
||||
.span_labels
|
||||
.iter()
|
||||
.map(|&(span, ref label)| SpanLabel {
|
||||
.map(|&PrimarySpanLabel(span, ref label)| SpanLabel {
|
||||
span,
|
||||
is_primary: is_primary(span),
|
||||
label: Some(label.clone()),
|
||||
@ -1296,14 +1307,21 @@ pub enum SpanSnippetError {
|
||||
SourceNotAvailable { filename: FileName },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub struct FilePos(pub FileName, pub BytePos);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub struct DistinctSources {
|
||||
pub begin: (FileName, BytePos),
|
||||
pub end: (FileName, BytePos),
|
||||
pub begin: FilePos,
|
||||
pub end: FilePos,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
|
@ -295,15 +295,15 @@ __plugin_transform_host_bytecheck = [
|
||||
|
||||
# Internal flags to control plugin environment
|
||||
__plugin_transform_env_native = [
|
||||
"swc/plugin_transform_host_native",
|
||||
"swc_plugin_runner/filesystem_cache",
|
||||
"wasmer/default",
|
||||
"wasmer-wasi/default",
|
||||
"swc_plugin_runner/plugin_transform_host_native",
|
||||
]
|
||||
|
||||
__plugin_transform_env_js = [
|
||||
"swc/plugin_transform_host_js",
|
||||
"swc_plugin_runner/memory_cache",
|
||||
"wasmer/js-default",
|
||||
"wasmer-wasi/js-default",
|
||||
"swc_plugin_runner/plugin_transform_host_js",
|
||||
]
|
||||
|
||||
# Do not use: testing purpose only
|
||||
@ -337,9 +337,7 @@ __visit = ["__ecma", "swc_ecma_visit"]
|
||||
|
||||
[dependencies]
|
||||
# 3rd party dependencies
|
||||
once_cell = { optional = true, version = "1.13.0" }
|
||||
wasmer = { optional = true, version = "2.3.0", default-features = false }
|
||||
wasmer-wasi = { optional = true, version = "2.3.0", default-features = false }
|
||||
once_cell = { optional = true, version = "1.13.0" }
|
||||
|
||||
# swc_* dependencies
|
||||
binding_macros = { optional = true, version = "0.48.6", path = "../binding_macros" }
|
||||
@ -350,6 +348,7 @@ swc_cached = { optional = true, version = "0.3.15", path =
|
||||
swc_common = { optional = true, version = "0.30.5", path = "../swc_common" }
|
||||
swc_css_ast = { optional = true, version = "0.136.6", path = "../swc_css_ast" }
|
||||
swc_css_codegen = { optional = true, version = "0.146.6", path = "../swc_css_codegen" }
|
||||
swc_css_compat = { optional = true, version = "0.22.7", path = "../swc_css_compat" }
|
||||
swc_css_minifier = { optional = true, version = "0.111.6", path = "../swc_css_minifier" }
|
||||
swc_css_modules = { optional = true, version = "0.24.1", path = "../swc_css_modules" }
|
||||
swc_css_parser = { optional = true, version = "0.145.6", path = "../swc_css_parser" }
|
||||
@ -383,8 +382,7 @@ swc_plugin_proxy = { optional = true, version = "0.31.5", path =
|
||||
swc_trace_macro = { optional = true, version = "0.1.2", path = "../swc_trace_macro" }
|
||||
testing = { optional = true, version = "0.32.5", path = "../testing" }
|
||||
# TODO: eventually swc_plugin_runner needs to remove default features
|
||||
swc_css_compat = { version = "0.22.7", path = "../swc_css_compat", optional = true }
|
||||
swc_plugin_runner = { optional = true, version = "0.93.8", path = "../swc_plugin_runner", default-features = false }
|
||||
swc_plugin_runner = { optional = true, version = "0.93.7", path = "../swc_plugin_runner", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "7.3.2", default-features = false, features = ["cargo"] }
|
||||
|
@ -24,7 +24,9 @@ swc_core = { path = "../../../../swc_core", features = [
|
||||
"binding_macro_wasm",
|
||||
"ecma_transforms",
|
||||
"ecma_visit",
|
||||
"plugin_transform_host_js",
|
||||
# Disabled for now, until resolve type mismatches. Refer bindings/binding_core_wasm/Cargo.toml
|
||||
# for the detail.
|
||||
# "plugin_transform_host_js",
|
||||
] }
|
||||
tracing = { version = "0.1.37", features = ["max_level_off"] }
|
||||
wasm-bindgen = { version = "0.2.82", features = ["enable-interning"] }
|
||||
|
@ -29,7 +29,7 @@ fn build_fixture_binary(dir: &Path, target: Option<&str>) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swc_core_napi_integartion_build() -> Result<(), Error> {
|
||||
fn swc_core_napi_integration_build() -> Result<(), Error> {
|
||||
build_fixture_binary(
|
||||
&PathBuf::from(env::var("CARGO_MANIFEST_DIR")?)
|
||||
.join("tests")
|
||||
@ -40,7 +40,7 @@ fn swc_core_napi_integartion_build() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swc_core_wasm_integartion_build() -> Result<(), Error> {
|
||||
fn swc_core_wasm_integration_build() -> Result<(), Error> {
|
||||
build_fixture_binary(
|
||||
&PathBuf::from(env::var("CARGO_MANIFEST_DIR")?)
|
||||
.join("tests")
|
||||
|
@ -21,7 +21,7 @@ serde-impl = ["serde"]
|
||||
[dependencies]
|
||||
bytecheck = { version = "0.6.9", optional = true }
|
||||
is-macro = "0.2.0"
|
||||
rkyv = { version = "=0.7.40", optional = true }
|
||||
rkyv = { version = "=0.7.40", optional = true, features = ["strict"] }
|
||||
serde = { version = "1.0.127", features = ["derive"], optional = true }
|
||||
|
||||
string_enum = { version = "0.4.0", path = "../string_enum/" }
|
||||
|
@ -25,6 +25,14 @@ impl Take for TokenAndSpan {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, EqIgnoreSpan, Hash)]
|
||||
#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl", feature = "rkyv-bytecheck-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub struct UrlKeyValue(pub Atom, pub Atom);
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Is, EqIgnoreSpan)]
|
||||
#[cfg_attr(
|
||||
feature = "rkyv",
|
||||
@ -114,7 +122,7 @@ pub enum Token {
|
||||
#[cfg_attr(feature = "rkyv", with(swc_atoms::EncodeJsWord))]
|
||||
value: JsWord,
|
||||
/// Name and value
|
||||
raw: Box<(Atom, Atom)>,
|
||||
raw: Box<UrlKeyValue>,
|
||||
},
|
||||
BadUrl {
|
||||
raw: Atom,
|
||||
|
@ -2,7 +2,9 @@ use std::{cell::RefCell, char::REPLACEMENT_CHARACTER, rc::Rc};
|
||||
|
||||
use swc_atoms::{js_word, Atom, JsWord};
|
||||
use swc_common::{input::Input, BytePos, Span};
|
||||
use swc_css_ast::{matches_eq_ignore_ascii_case, DimensionToken, NumberType, Token, TokenAndSpan};
|
||||
use swc_css_ast::{
|
||||
matches_eq_ignore_ascii_case, DimensionToken, NumberType, Token, TokenAndSpan, UrlKeyValue,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{Error, ErrorKind},
|
||||
@ -755,7 +757,7 @@ where
|
||||
Some(')') => {
|
||||
return Ok(Token::Url {
|
||||
value: (&**out).into(),
|
||||
raw: Box::new((name.1, (&**raw).into())),
|
||||
raw: Box::new(UrlKeyValue(name.1, (&**raw).into())),
|
||||
});
|
||||
}
|
||||
|
||||
@ -766,7 +768,7 @@ where
|
||||
|
||||
return Ok(Token::Url {
|
||||
value: (&**out).into(),
|
||||
raw: Box::new((name.1, (&**raw).into())),
|
||||
raw: Box::new(UrlKeyValue(name.1, (&**raw).into())),
|
||||
});
|
||||
}
|
||||
|
||||
@ -800,7 +802,7 @@ where
|
||||
|
||||
return Ok(Token::Url {
|
||||
value: (&**out).into(),
|
||||
raw: Box::new((name.1, (&**raw).into())),
|
||||
raw: Box::new(UrlKeyValue(name.1, (&**raw).into())),
|
||||
});
|
||||
}
|
||||
None => {
|
||||
@ -810,7 +812,7 @@ where
|
||||
|
||||
return Ok(Token::Url {
|
||||
value: (&**out).into(),
|
||||
raw: Box::new((name.1, (&**raw).into())),
|
||||
raw: Box::new(UrlKeyValue(name.1, (&**raw).into())),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
|
@ -2037,7 +2037,7 @@
|
||||
16 | :unknown({!}) {}
|
||||
`----
|
||||
|
||||
x Url { value: Atom('foo.png' type=inline), raw: ("url", "foo.png") }
|
||||
x Url { value: Atom('foo.png' type=inline), raw: UrlKeyValue("url", "foo.png") }
|
||||
,-[$DIR/tests/fixture/selector/pseudo-class/unknown/input.css:14:1]
|
||||
14 | :unknown('string') {}
|
||||
15 | :unknown(url(foo.png)) {}
|
||||
|
@ -2036,7 +2036,7 @@
|
||||
16 | ::unknown({!}) {}
|
||||
`----
|
||||
|
||||
x Url { value: Atom('foo.png' type=inline), raw: ("url", "foo.png") }
|
||||
x Url { value: Atom('foo.png' type=inline), raw: UrlKeyValue("url", "foo.png") }
|
||||
,-[$DIR/tests/fixture/selector/pseudo-element/unknown/input.css:14:1]
|
||||
14 | ::unknown('string') {}
|
||||
15 | ::unknown(url(foo.png)) {}
|
||||
|
@ -31,18 +31,22 @@ rkyv-bytecheck-impl = [
|
||||
serde-impl = ["serde"]
|
||||
|
||||
[dependencies]
|
||||
arbitrary = { version = "1", optional = true, features = ["derive"] }
|
||||
bitflags = "1"
|
||||
bytecheck = { version = "0.6.9", optional = true }
|
||||
is-macro = "0.2.1"
|
||||
arbitrary = { version = "1", optional = true, features = ["derive"] }
|
||||
bitflags = "1"
|
||||
bytecheck = { version = "0.6.9", optional = true }
|
||||
is-macro = "0.2.1"
|
||||
num-bigint = { version = "0.4", features = ["serde"] }
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true }
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true, features = [
|
||||
"strict",
|
||||
] }
|
||||
# This is to avoid cargo version selection conflict between rkyv=0.7.40 and other versions, as it is strictly pinned
|
||||
# cannot be merged.
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true }
|
||||
scoped-tls = "1.0.0"
|
||||
serde = { version = "1.0.133", features = ["derive"], optional = true }
|
||||
unicode-id = "0.3"
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true, features = [
|
||||
"strict",
|
||||
] }
|
||||
scoped-tls = "1.0.0"
|
||||
serde = { version = "1.0.133", features = ["derive"], optional = true }
|
||||
unicode-id = "0.3"
|
||||
|
||||
string_enum = { version = "0.4.0", path = "../string_enum" }
|
||||
swc_atoms = { version = "0.4.43", path = "../swc_atoms" }
|
||||
|
@ -23,7 +23,7 @@ serde-impl = ["serde"]
|
||||
[dependencies]
|
||||
bytecheck = { version = "0.6.9", optional = true }
|
||||
is-macro = "0.2.0"
|
||||
rkyv = { version = "=0.7.40", optional = true }
|
||||
rkyv = { version = "=0.7.40", optional = true, features = ["strict"] }
|
||||
serde = { version = "1.0.127", features = ["derive"], optional = true }
|
||||
|
||||
string_enum = { version = "0.4.0", path = "../string_enum/" }
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::alloc::{alloc as global_alloc, dealloc as global_dealloc, Layout};
|
||||
|
||||
/// Allocate bytes that won't be dropped by the allocator.
|
||||
/// Return the pointer to the leaked allocation so the host can write to it.
|
||||
///
|
||||
@ -31,5 +33,46 @@ pub extern "C" fn __alloc(size: i32) -> *mut u8 {
|
||||
pub extern "C" fn __free(ptr: *mut u8, size: i32) -> i32 {
|
||||
let data = unsafe { Vec::from_raw_parts(ptr, size as usize, size as usize) };
|
||||
std::mem::drop(data);
|
||||
0
|
||||
0 as _
|
||||
}
|
||||
|
||||
/// Allocates memory area of specified size and returns its address.
|
||||
/// Returns 0 if supplied size is too long.
|
||||
/// [TODO]: This is for the experiment to alloc memory with specified layout instead of
|
||||
/// manually creating vec![] and forget it. This is not used yet.
|
||||
#[doc(hidden)]
|
||||
#[cfg(all(target_arch = "wasm32", feature = "layout_alloc"))]
|
||||
#[no_mangle]
|
||||
#[inline(always)]
|
||||
pub unsafe fn __alloc(size: usize) -> usize {
|
||||
let layout = match Layout::from_size_align(size as usize, std::mem::align_of::<u8>()) {
|
||||
Ok(layout) => layout,
|
||||
// in this case a err may occur only in a case of too long allocated size,
|
||||
// so just return 0
|
||||
Err(_) => return 0 as _,
|
||||
};
|
||||
|
||||
unsafe { global_alloc(layout) as _ }
|
||||
}
|
||||
|
||||
/// Deallocates memory area for provided memory pointer and size.
|
||||
/// Does nothing if supplied size is too long.
|
||||
/// [TODO]: This is for the experiment to free memory with specified layout with explicit
|
||||
/// dealloc instead of dropping it. This is not used yet.
|
||||
#[doc(hidden)]
|
||||
#[cfg(all(target_arch = "wasm32", feature = "layout_alloc"))]
|
||||
#[no_mangle]
|
||||
#[inline(always)]
|
||||
pub unsafe fn __free(ptr: *mut u8, size: usize) {
|
||||
let layout = match Layout::from_size_align(size as usize, std::mem::align_of::<u8>()) {
|
||||
Ok(layout) => layout,
|
||||
// in this case a err may occur only in a case of too long allocated size,
|
||||
// so just done nothing
|
||||
Err(_) => return 0 as _,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
global_dealloc(ptr, layout);
|
||||
}
|
||||
0 as _
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ plugin-mode = ["__plugin_mode", "swc_common/plugin-base", "rkyv-impl"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true }
|
||||
rkyv = { package = "rkyv", version = "=0.7.40", optional = true, features = [
|
||||
"strict",
|
||||
] }
|
||||
# This is to avoid cargo version selection conflict between rkyv=0.7.40 and other versions, as it is strictly pinned
|
||||
# cannot be merged.
|
||||
rkyv-latest = { package = "rkyv-test", version = "=0.7.38-test.2", optional = true }
|
||||
|
@ -12,9 +12,19 @@ version = "0.93.8"
|
||||
bench = false
|
||||
|
||||
[features]
|
||||
default = ["filesystem_cache"]
|
||||
default = ["filesystem_cache", "plugin_transform_host_native"]
|
||||
plugin_transform_host_js = [
|
||||
"wasmer/js-default",
|
||||
"wasmer-wasix/js-default",
|
||||
"wasmer-compiler-cranelift/wasm",
|
||||
]
|
||||
plugin_transform_host_native = [
|
||||
"wasmer/default",
|
||||
"wasmer-wasix/default",
|
||||
"wasmer-compiler-cranelift/default",
|
||||
]
|
||||
# Supports a cache allow to store compiled bytecode into filesystem location.
|
||||
# This feature implies in-memory cache enabled always.
|
||||
# This feature implies in-memory cache support, but not via `memory_cache` feature.
|
||||
filesystem_cache = ["wasmer-cache"]
|
||||
# Supports a cache allow to store wasm module in-memory. This avoids recompilation
|
||||
# to the same module in a single procress lifecycle.
|
||||
@ -36,15 +46,15 @@ rkyv-bytecheck-impl = [
|
||||
rkyv-impl = ["__rkyv", "swc_common/plugin-rt", "swc_plugin_proxy/plugin-rt"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.42"
|
||||
enumset = "1.0.12"
|
||||
once_cell = "1.10.0"
|
||||
parking_lot = "0.12.0"
|
||||
serde = { version = "1.0.126", features = ["derive"] }
|
||||
serde_json = "1.0.64"
|
||||
tracing = "0.1.32"
|
||||
wasmer = { version = "2.3.0", default-features = false }
|
||||
wasmer-wasi = { version = "2.3.0", default-features = false }
|
||||
anyhow = "1.0.42"
|
||||
enumset = "1.0.12"
|
||||
once_cell = "1.10.0"
|
||||
parking_lot = "0.12.0"
|
||||
serde = { version = "1.0.126", features = ["derive"] }
|
||||
serde_json = "1.0.64"
|
||||
tracing = "0.1.32"
|
||||
wasmer = { version = "3.2.0-beta.2", default-features = false }
|
||||
wasmer-wasix = { version = "0.2", default-features = false }
|
||||
|
||||
swc_common = { version = "0.30.5", path = "../swc_common", features = [
|
||||
"concurrent",
|
||||
@ -53,16 +63,12 @@ swc_css_ast = { version = "0.136.6", path = "../swc_css_ast", optional = true }
|
||||
swc_ecma_ast = { version = "0.102.5", path = "../swc_ecma_ast", optional = true }
|
||||
swc_plugin_proxy = { version = "0.31.5", path = "../swc_plugin_proxy" }
|
||||
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
wasmer-cache = { version = "2.3.0", optional = true }
|
||||
wasmer-compiler-cranelift = { version = "2.3.0" }
|
||||
wasmer-engine-universal = { version = "2.3.0" }
|
||||
wasmer-cache = { version = "3.2.0-beta.2", optional = true }
|
||||
wasmer-compiler-cranelift = { version = "3.2.0-beta.2", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
wasmer = "2.3.0"
|
||||
wasmer-wasi = "2.3.0"
|
||||
criterion = "0.3"
|
||||
|
||||
swc_atoms = { version = "0.4.43", path = '../swc_atoms' }
|
||||
swc_css_ast = { version = "0.136.6", path = "../swc_css_ast", features = [
|
||||
|
@ -35,7 +35,7 @@ compile_error!(
|
||||
/// however it is not gauranteed to be compatible across wasmer's
|
||||
/// internal changes.
|
||||
/// https://github.com/wasmerio/wasmer/issues/2781
|
||||
const MODULE_SERIALIZATION_VERSION: &str = "v4";
|
||||
const MODULE_SERIALIZATION_VERSION: &str = "v5";
|
||||
|
||||
/// A shared instance to plugin's module bytecode cache.
|
||||
pub static PLUGIN_MODULE_CACHE: Lazy<PluginModuleCache> = Lazy::new(Default::default);
|
||||
@ -112,7 +112,7 @@ pub fn init_plugin_module_cache_once(filesystem_cache_root: &Option<String>) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "memory_cache")]
|
||||
pub fn init_plugin_module_cache_once() {
|
||||
pub fn init_plugin_module_cache_once(_unused_cache_root: &Option<String>) {
|
||||
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
|
||||
Mutex::new(CacheInner {
|
||||
loaded_module_bytes: Default::default(),
|
||||
@ -142,24 +142,30 @@ impl PluginModuleCache {
|
||||
/// In actual transform, `plugins` is also being called per each transform.
|
||||
#[cfg(feature = "filesystem_cache")]
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn load_module(&self, binary_path: &Path) -> Result<Module, Error> {
|
||||
pub fn load_module(&self, wasmer_store: &Store, binary_path: &Path) -> Result<Module, Error> {
|
||||
let binary_path = binary_path.to_path_buf();
|
||||
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
|
||||
|
||||
// if constructed Module is available in-memory, directly return it.
|
||||
// Note we do not invalidate in-memory cache currently: if wasm binary is
|
||||
// replaced in-process lifecycle (i.e devserver) it won't be reflected.
|
||||
|
||||
/*
|
||||
[TODO]: This is currently disabled, since on the latest wasmer@3 subsequent
|
||||
plugin load via in memory module causes intermittent heap_get_oob when
|
||||
host tries to allocate memory inside of the guest.
|
||||
|
||||
Current guess is memory instance is being corrupted by the previous run, but
|
||||
until figure out root cause & fix will only use fs_cache directly.
|
||||
let in_memory_module = inner_cache.loaded_module_bytes.get(&binary_path);
|
||||
if let Some(module) = in_memory_module {
|
||||
return Ok(module.clone());
|
||||
}
|
||||
}*/
|
||||
|
||||
let module_bytes =
|
||||
std::fs::read(&binary_path).context("Cannot read plugin from specified path")?;
|
||||
let module_bytes_hash = Hash::generate(&module_bytes);
|
||||
|
||||
let wasmer_store = new_store();
|
||||
|
||||
let load_cold_wasm_bytes = || {
|
||||
let span = tracing::span!(
|
||||
tracing::Level::INFO,
|
||||
@ -169,7 +175,7 @@ impl PluginModuleCache {
|
||||
let span_guard = span.enter();
|
||||
let _lock = self.instantiation_lock.lock();
|
||||
let ret =
|
||||
Module::new(&wasmer_store, module_bytes).context("Cannot compile plugin binary");
|
||||
Module::new(wasmer_store, module_bytes).context("Cannot compile plugin binary");
|
||||
drop(span_guard);
|
||||
ret
|
||||
};
|
||||
@ -177,7 +183,7 @@ impl PluginModuleCache {
|
||||
// Try to load compiled bytes from filesystem cache if available.
|
||||
// Otherwise, cold compile instead.
|
||||
let module = if let Some(fs_cache) = &mut inner_cache.fs_cache {
|
||||
let load_result = unsafe { fs_cache.load(&wasmer_store, module_bytes_hash) };
|
||||
let load_result = unsafe { fs_cache.load(wasmer_store, module_bytes_hash) };
|
||||
if let Ok(module) = load_result {
|
||||
module
|
||||
} else {
|
||||
@ -198,7 +204,7 @@ impl PluginModuleCache {
|
||||
|
||||
#[cfg(feature = "memory_cache")]
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn load_module(&self, binary_path: &Path) -> Result<Module, Error> {
|
||||
pub fn load_module(&self, wasmer_store: &Store, binary_path: &Path) -> Result<Module, Error> {
|
||||
let binary_path = binary_path.to_path_buf();
|
||||
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
|
||||
|
||||
@ -213,9 +219,7 @@ impl PluginModuleCache {
|
||||
|
||||
//TODO: In native runtime we have to reconstruct module using raw bytes in
|
||||
// memory cache. requires https://github.com/wasmerio/wasmer/pull/2821
|
||||
|
||||
let wasmer_store = new_store();
|
||||
let module = Module::new(&wasmer_store, in_memory_module_bytes)?;
|
||||
let module = Module::new(wasmer_store, in_memory_module_bytes)?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
@ -243,28 +247,3 @@ impl PluginModuleCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an instnace of [Store].
|
||||
///
|
||||
/// This function exists because we need to disable simd.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[allow(unused_mut)]
|
||||
fn new_store() -> Store {
|
||||
// Use empty enumset to disable simd.
|
||||
let mut set = EnumSet::new();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
set.insert(CpuFeature::SSE2);
|
||||
let target = Target::new(Triple::host(), set);
|
||||
|
||||
let config = wasmer_compiler_cranelift::Cranelift::default();
|
||||
let engine = wasmer_engine_universal::Universal::new(config)
|
||||
.target(target)
|
||||
.engine();
|
||||
let tunables = BaseTunables::for_target(engine.target());
|
||||
Store::new_with_tunables(&engine, tunables)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn new_store() -> Store {
|
||||
Store::default()
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
use wasmer::{LazyInit, Memory};
|
||||
use wasmer::Memory;
|
||||
|
||||
/// An external environment state imported (declared in host, injected into
|
||||
/// guest) fn can access. This'll allow host to read from updated state from
|
||||
/// guest.
|
||||
///
|
||||
/// This is `base` environment exposes guest's memory space only. For other
|
||||
/// This is `base` environment exposes nothing. For other
|
||||
/// calls requires additional data to be set in the host, separate
|
||||
/// hostenvironments are declared. Refer `CommentsHostEnvironment` for an
|
||||
/// example.
|
||||
///
|
||||
/// ref: https://docs.wasmer.io/integrations/examples/host-functions#declaring-the-data
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct BaseHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
}
|
||||
|
||||
impl BaseHostEnvironment {
|
||||
pub fn new() -> BaseHostEnvironment {
|
||||
BaseHostEnvironment {
|
||||
memory: LazyInit::new(),
|
||||
}
|
||||
BaseHostEnvironment { memory: None }
|
||||
}
|
||||
}
|
||||
|
@ -7,20 +7,18 @@ use swc_common::{
|
||||
BytePos,
|
||||
};
|
||||
use swc_plugin_proxy::COMMENTS;
|
||||
use wasmer::{LazyInit, Memory, NativeFunc};
|
||||
use wasmer::{AsStoreMut, FunctionEnvMut, Memory, TypedFunction};
|
||||
|
||||
use crate::memory_interop::{allocate_return_values_into_guest, copy_bytes_into_host};
|
||||
|
||||
/// External environment state for imported (declared in host, injected into
|
||||
/// guest) fn for comments proxy.
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct CommentHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
/// Attached imported fn `__alloc` to the hostenvironment to allow any other
|
||||
/// imported fn can allocate guest's memory space from host runtime.
|
||||
#[wasmer(export(name = "__alloc"))]
|
||||
pub alloc_guest_memory: LazyInit<NativeFunc<u32, u32>>,
|
||||
pub alloc_guest_memory: Option<TypedFunction<u32, u32>>,
|
||||
/// A buffer to `Comment`, or `Vec<Comment>` plugin need to pass to the host
|
||||
/// to perform mutable comment operations like `add_leading, or
|
||||
/// add_leading_comments`. This is vec to serialized bytes, doesn't
|
||||
@ -32,8 +30,8 @@ pub struct CommentHostEnvironment {
|
||||
impl CommentHostEnvironment {
|
||||
pub fn new(mutable_comment_buffer: &Arc<Mutex<Vec<u8>>>) -> CommentHostEnvironment {
|
||||
CommentHostEnvironment {
|
||||
memory: LazyInit::default(),
|
||||
alloc_guest_memory: LazyInit::default(),
|
||||
memory: None,
|
||||
alloc_guest_memory: None,
|
||||
mutable_comment_buffer: mutable_comment_buffer.clone(),
|
||||
}
|
||||
}
|
||||
@ -42,11 +40,18 @@ impl CommentHostEnvironment {
|
||||
/// Copy given serialized byte into host's comment buffer, subsequent proxy call
|
||||
/// in the host can read it.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn copy_comment_to_host_env(env: &CommentHostEnvironment, bytes_ptr: u32, bytes_ptr_len: u32) {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
(*env.mutable_comment_buffer.lock()) =
|
||||
copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
pub fn copy_comment_to_host_env(
|
||||
mut env: FunctionEnvMut<CommentHostEnvironment>,
|
||||
bytes_ptr: i32,
|
||||
bytes_ptr_len: i32,
|
||||
) {
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
(*env.data_mut().mutable_comment_buffer.lock()) =
|
||||
copy_bytes_into_host(&memory.view(&env), bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
|
||||
/// Utility fn to unwrap necessary values for the comments fn operation when fn
|
||||
@ -88,31 +93,42 @@ where
|
||||
/// Utility fn to unwrap necessary values for the comments, as well as host
|
||||
/// environment's state.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
fn unwrap_comments_storage_with_env<F, R>(env: &CommentHostEnvironment, f: F, default: R) -> R
|
||||
fn unwrap_comments_storage_with_env<F, R>(
|
||||
env: &FunctionEnvMut<CommentHostEnvironment>,
|
||||
f: F,
|
||||
default: R,
|
||||
) -> R
|
||||
where
|
||||
F: FnOnce(&SingleThreadedComments, &Memory, &NativeFunc<u32, u32>) -> R,
|
||||
F: FnOnce(&SingleThreadedComments, &Memory, &TypedFunction<u32, u32>) -> R,
|
||||
{
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| f(comments, memory, alloc_guest_memory),
|
||||
default,
|
||||
);
|
||||
}
|
||||
}
|
||||
default
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env
|
||||
.data()
|
||||
.alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| f(comments, memory, alloc_guest_memory),
|
||||
default,
|
||||
);
|
||||
}
|
||||
|
||||
/// Common logics for add_*_comment/comments.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
fn add_comments_inner<F>(env: &CommentHostEnvironment, byte_pos: u32, f: F)
|
||||
fn add_comments_inner<F>(mut env: FunctionEnvMut<CommentHostEnvironment>, byte_pos: u32, f: F)
|
||||
where
|
||||
F: FnOnce(&SingleThreadedComments, BytePos, PluginSerializedBytes),
|
||||
{
|
||||
unwrap_comments_storage(|comments| {
|
||||
let byte_pos = BytePos(byte_pos);
|
||||
// PluginCommentProxy in the guest should've copied buffer already
|
||||
let comment_byte = &mut (*env.mutable_comment_buffer.lock());
|
||||
let comment_byte = &mut (*env.data_mut().mutable_comment_buffer.lock());
|
||||
let serialized = PluginSerializedBytes::from_slice(comment_byte);
|
||||
|
||||
f(comments, byte_pos, serialized);
|
||||
@ -123,7 +139,7 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_leading_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
pub fn add_leading_comment_proxy(env: FunctionEnvMut<CommentHostEnvironment>, byte_pos: u32) {
|
||||
add_comments_inner(env, byte_pos, |comments, byte_pos, serialized| {
|
||||
comments.add_leading(
|
||||
byte_pos,
|
||||
@ -135,7 +151,7 @@ pub fn add_leading_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn add_leading_comments_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
pub fn add_leading_comments_proxy(env: FunctionEnvMut<CommentHostEnvironment>, byte_pos: u32) {
|
||||
add_comments_inner(env, byte_pos, |comments, byte_pos, serialized| {
|
||||
comments.add_leading_comments(
|
||||
byte_pos,
|
||||
@ -160,13 +176,22 @@ pub fn move_leading_comments_proxy(from_byte_pos: u32, to_byte_pos: u32) {
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn take_leading_comments_proxy(
|
||||
env: &CommentHostEnvironment,
|
||||
mut env: FunctionEnvMut<CommentHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
unwrap_comments_storage_with_env(
|
||||
env,
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| {
|
||||
let leading_comments = comments.take_leading(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = leading_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
@ -175,6 +200,7 @@ pub fn take_leading_comments_proxy(
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_leading_comments_vec_bytes,
|
||||
@ -185,7 +211,7 @@ pub fn take_leading_comments_proxy(
|
||||
}
|
||||
},
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// Ask to get leading_comments from currently scoped comments held by
|
||||
@ -195,13 +221,22 @@ pub fn take_leading_comments_proxy(
|
||||
/// Allocated results should be read through CommentsPtr.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_leading_comments_proxy(
|
||||
env: &CommentHostEnvironment,
|
||||
mut env: FunctionEnvMut<CommentHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
unwrap_comments_storage_with_env(
|
||||
env,
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| {
|
||||
let leading_comments = comments.get_leading(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = leading_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
@ -210,6 +245,7 @@ pub fn get_leading_comments_proxy(
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_leading_comments_vec_bytes,
|
||||
@ -220,11 +256,11 @@ pub fn get_leading_comments_proxy(
|
||||
}
|
||||
},
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn add_trailing_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
pub fn add_trailing_comment_proxy(env: FunctionEnvMut<CommentHostEnvironment>, byte_pos: u32) {
|
||||
add_comments_inner(env, byte_pos, |comments, byte_pos, serialized| {
|
||||
comments.add_trailing(
|
||||
byte_pos,
|
||||
@ -236,7 +272,7 @@ pub fn add_trailing_comment_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn add_trailing_comments_proxy(env: &CommentHostEnvironment, byte_pos: u32) {
|
||||
pub fn add_trailing_comments_proxy(env: FunctionEnvMut<CommentHostEnvironment>, byte_pos: u32) {
|
||||
add_comments_inner(env, byte_pos, |comments, byte_pos, serialized| {
|
||||
comments.add_trailing_comments(
|
||||
byte_pos,
|
||||
@ -264,13 +300,22 @@ pub fn move_trailing_comments_proxy(from_byte_pos: u32, to_byte_pos: u32) {
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn take_trailing_comments_proxy(
|
||||
env: &CommentHostEnvironment,
|
||||
mut env: FunctionEnvMut<CommentHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
unwrap_comments_storage_with_env(
|
||||
env,
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| {
|
||||
let trailing_comments = comments.take_trailing(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = trailing_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
@ -279,6 +324,7 @@ pub fn take_trailing_comments_proxy(
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_leading_comments_vec_bytes,
|
||||
@ -289,18 +335,27 @@ pub fn take_trailing_comments_proxy(
|
||||
}
|
||||
},
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_trailing_comments_proxy(
|
||||
env: &CommentHostEnvironment,
|
||||
mut env: FunctionEnvMut<CommentHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
unwrap_comments_storage_with_env(
|
||||
env,
|
||||
|comments, memory, alloc_guest_memory| {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return unwrap_comments_storage_or_default(
|
||||
|comments| {
|
||||
let trailing_comments = comments.get_trailing(BytePos(byte_pos));
|
||||
if let Some(leading_comments) = trailing_comments {
|
||||
let serialized_leading_comments_vec_bytes =
|
||||
@ -309,6 +364,7 @@ pub fn get_trailing_comments_proxy(
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_leading_comments_vec_bytes,
|
||||
@ -319,7 +375,7 @@ pub fn get_trailing_comments_proxy(
|
||||
}
|
||||
},
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
|
@ -1,23 +1,22 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use wasmer::{LazyInit, Memory};
|
||||
use wasmer::{FunctionEnvMut, Memory};
|
||||
|
||||
use crate::memory_interop::copy_bytes_into_host;
|
||||
|
||||
/// External environment to read swc_core diagnostics from the host.
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct DiagnosticContextHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
/// A buffer to store diagnostics data strings.
|
||||
pub core_diag_buffer: Arc<Mutex<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl DiagnosticContextHostEnvironment {
|
||||
pub fn new(core_diag_buffer: &Arc<Mutex<Vec<u8>>>) -> DiagnosticContextHostEnvironment {
|
||||
pub fn new(core_diag_buffer: &Arc<Mutex<Vec<u8>>>) -> Self {
|
||||
DiagnosticContextHostEnvironment {
|
||||
memory: LazyInit::default(),
|
||||
memory: None,
|
||||
core_diag_buffer: core_diag_buffer.clone(),
|
||||
}
|
||||
}
|
||||
@ -25,10 +24,16 @@ impl DiagnosticContextHostEnvironment {
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn set_plugin_core_pkg_diagnostics(
|
||||
env: &DiagnosticContextHostEnvironment,
|
||||
bytes_ptr: u32,
|
||||
bytes_ptr_len: u32,
|
||||
mut env: FunctionEnvMut<DiagnosticContextHostEnvironment>,
|
||||
bytes_ptr: i32,
|
||||
bytes_ptr_len: i32,
|
||||
) {
|
||||
let memory = env.memory_ref().expect("Memory should be initialized");
|
||||
(*env.core_diag_buffer.lock()) = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
(*env.data_mut().core_diag_buffer.lock()) =
|
||||
copy_bytes_into_host(&memory.view(&env), bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
|
@ -2,23 +2,33 @@ use swc_common::{
|
||||
errors::{Diagnostic, HANDLER},
|
||||
plugin::serialized::PluginSerializedBytes,
|
||||
};
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
use crate::{host_environment::BaseHostEnvironment, memory_interop::copy_bytes_into_host};
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn emit_diagnostics(env: &BaseHostEnvironment, bytes_ptr: u32, bytes_ptr_len: u32) {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
if HANDLER.is_set() {
|
||||
HANDLER.with(|handler| {
|
||||
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");
|
||||
pub fn emit_diagnostics(
|
||||
env: FunctionEnvMut<BaseHostEnvironment>,
|
||||
bytes_ptr: i32,
|
||||
bytes_ptr_len: i32,
|
||||
) {
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let mut builder =
|
||||
swc_common::errors::DiagnosticBuilder::new_diagnostic(handler, diagnostic);
|
||||
builder.emit();
|
||||
})
|
||||
}
|
||||
if HANDLER.is_set() {
|
||||
HANDLER.with(|handler| {
|
||||
let diagnostics_bytes =
|
||||
copy_bytes_into_host(&memory.view(&env), 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");
|
||||
|
||||
let mut builder =
|
||||
swc_common::errors::DiagnosticBuilder::new_diagnostic(handler, diagnostic);
|
||||
builder.emit();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use swc_common::{
|
||||
hygiene::MutableMarkContext, plugin::serialized::PluginSerializedBytes, Mark, SyntaxContext,
|
||||
};
|
||||
use wasmer::{AsStoreMut, FunctionEnvMut};
|
||||
|
||||
use crate::{host_environment::BaseHostEnvironment, memory_interop::write_into_memory_view};
|
||||
|
||||
@ -30,39 +31,60 @@ pub fn mark_set_builtin_proxy(self_mark: u32, is_builtin: u32) {
|
||||
/// with return value accordingly.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn mark_is_descendant_of_proxy(
|
||||
env: &BaseHostEnvironment,
|
||||
mut env: FunctionEnvMut<BaseHostEnvironment>,
|
||||
self_mark: u32,
|
||||
ancestor: u32,
|
||||
allocated_ptr: u32,
|
||||
) {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let self_mark = Mark::from_u32(self_mark);
|
||||
let ancestor = Mark::from_u32(ancestor);
|
||||
|
||||
let return_value = self_mark.is_descendant_of(ancestor);
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let context = MutableMarkContext(self_mark.as_u32(), 0, return_value as u32);
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
let context = MutableMarkContext(self_mark.as_u32(), 0, return_value as u32);
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
}
|
||||
write_into_memory_view(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
&serialized_bytes,
|
||||
|_, _| allocated_ptr,
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn mark_least_ancestor_proxy(env: &BaseHostEnvironment, a: u32, b: u32, allocated_ptr: u32) {
|
||||
pub fn mark_least_ancestor_proxy(
|
||||
mut env: FunctionEnvMut<BaseHostEnvironment>,
|
||||
a: u32,
|
||||
b: u32,
|
||||
allocated_ptr: u32,
|
||||
) {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let a = Mark::from_u32(a);
|
||||
let b = Mark::from_u32(b);
|
||||
|
||||
let return_value = Mark::least_ancestor(a, b).as_u32();
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let context = MutableMarkContext(a.as_u32(), b.as_u32(), return_value);
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
let context = 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);
|
||||
}
|
||||
write_into_memory_view(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
&serialized_bytes,
|
||||
|_, _| allocated_ptr,
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
@ -74,21 +96,29 @@ pub fn syntax_context_apply_mark_proxy(self_syntax_context: u32, mark: u32) -> u
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn syntax_context_remove_mark_proxy(
|
||||
env: &BaseHostEnvironment,
|
||||
mut env: FunctionEnvMut<BaseHostEnvironment>,
|
||||
self_mark: u32,
|
||||
allocated_ptr: u32,
|
||||
) {
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let mut self_mark = SyntaxContext::from_u32(self_mark);
|
||||
|
||||
let return_value = self_mark.remove_mark();
|
||||
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let context = MutableMarkContext(self_mark.as_u32(), 0, return_value.as_u32());
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
let context = MutableMarkContext(self_mark.as_u32(), 0, return_value.as_u32());
|
||||
let serialized_bytes =
|
||||
PluginSerializedBytes::try_serialize(&context).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
}
|
||||
write_into_memory_view(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
&serialized_bytes,
|
||||
|_, _| allocated_ptr,
|
||||
);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
|
@ -5,18 +5,16 @@ use swc_common::plugin::{
|
||||
metadata::{TransformPluginMetadataContext, TransformPluginMetadataContextKind},
|
||||
serialized::PluginSerializedBytes,
|
||||
};
|
||||
use wasmer::{LazyInit, Memory, NativeFunc};
|
||||
use wasmer::{AsStoreMut, FunctionEnvMut, Memory, TypedFunction};
|
||||
|
||||
use crate::memory_interop::{allocate_return_values_into_guest, copy_bytes_into_host};
|
||||
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct MetadataContextHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
/// Attached imported fn `__alloc` to the hostenvironment to allow any other
|
||||
/// imported fn can allocate guest's memory space from host runtime.
|
||||
#[wasmer(export(name = "__alloc"))]
|
||||
pub alloc_guest_memory: LazyInit<NativeFunc<u32, u32>>,
|
||||
pub alloc_guest_memory: Option<TypedFunction<u32, u32>>,
|
||||
pub metadata_context: Arc<TransformPluginMetadataContext>,
|
||||
pub transform_plugin_config: Option<serde_json::Value>,
|
||||
/// A buffer to string key to the context plugin need to pass to the host.
|
||||
@ -30,8 +28,8 @@ impl MetadataContextHostEnvironment {
|
||||
mutable_context_key_buffer: &Arc<Mutex<Vec<u8>>>,
|
||||
) -> Self {
|
||||
MetadataContextHostEnvironment {
|
||||
memory: LazyInit::default(),
|
||||
alloc_guest_memory: LazyInit::default(),
|
||||
memory: None,
|
||||
alloc_guest_memory: None,
|
||||
metadata_context: metadata_context.clone(),
|
||||
transform_plugin_config: plugin_config.clone(),
|
||||
mutable_context_key_buffer: mutable_context_key_buffer.clone(),
|
||||
@ -43,135 +41,167 @@ impl MetadataContextHostEnvironment {
|
||||
/// in the host can read it.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn copy_context_key_to_host_env(
|
||||
env: &MetadataContextHostEnvironment,
|
||||
bytes_ptr: u32,
|
||||
bytes_ptr_len: u32,
|
||||
mut env: FunctionEnvMut<MetadataContextHostEnvironment>,
|
||||
bytes_ptr: i32,
|
||||
bytes_ptr_len: i32,
|
||||
) {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
(*env.mutable_context_key_buffer.lock()) =
|
||||
copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
(*env.data_mut().mutable_context_key_buffer.lock()) =
|
||||
copy_bytes_into_host(&memory.view(&env), bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_transform_plugin_config(
|
||||
env: &MetadataContextHostEnvironment,
|
||||
mut env: FunctionEnvMut<MetadataContextHostEnvironment>,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
let config_value = &env.transform_plugin_config;
|
||||
if let Some(config_value) = config_value {
|
||||
// Lazy as possible as we can - only deserialize json value if transform plugin
|
||||
// actually needs it.
|
||||
let config = serde_json::to_string(config_value).ok();
|
||||
if let Some(config) = config {
|
||||
let serialized = PluginSerializedBytes::try_serialize(&config)
|
||||
.expect("Should be serializable");
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
let config_value = &env.data().transform_plugin_config;
|
||||
if let Some(config_value) = config_value {
|
||||
// Lazy as possible as we can - only deserialize json value if transform plugin
|
||||
// actually needs it.
|
||||
let config = serde_json::to_string(config_value).ok();
|
||||
if let Some(config) = config {
|
||||
let serialized =
|
||||
PluginSerializedBytes::try_serialize(&config).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
0
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_transform_context(
|
||||
env: &MetadataContextHostEnvironment,
|
||||
mut env: FunctionEnvMut<MetadataContextHostEnvironment>,
|
||||
key: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
let value = env
|
||||
.metadata_context
|
||||
.get(&TransformPluginMetadataContextKind::from(key));
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
if let Some(value) = value {
|
||||
let serialized =
|
||||
PluginSerializedBytes::try_serialize(&value).expect("Should be serializable");
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
let value = env
|
||||
.data()
|
||||
.metadata_context
|
||||
.get(&TransformPluginMetadataContextKind::from(key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if let Some(value) = value {
|
||||
let serialized =
|
||||
PluginSerializedBytes::try_serialize(&value).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
0
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_experimental_transform_context(
|
||||
env: &MetadataContextHostEnvironment,
|
||||
mut env: FunctionEnvMut<MetadataContextHostEnvironment>,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
let context_key_buffer = &*env.mutable_context_key_buffer.lock();
|
||||
let key: String = PluginSerializedBytes::from_slice(&context_key_buffer[..])
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize");
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let value = env
|
||||
.metadata_context
|
||||
.experimental
|
||||
.get(&key)
|
||||
.map(|v| v.to_string());
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
if let Some(value) = value {
|
||||
let serialized =
|
||||
PluginSerializedBytes::try_serialize(&value).expect("Should be serializable");
|
||||
let context_key_buffer = env.data().mutable_context_key_buffer.lock().clone();
|
||||
let key: String = PluginSerializedBytes::from_slice(&context_key_buffer[..])
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
let value = env
|
||||
.data()
|
||||
.metadata_context
|
||||
.experimental
|
||||
.get(&key)
|
||||
.map(|v| v.to_string());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if let Some(value) = value {
|
||||
let serialized =
|
||||
PluginSerializedBytes::try_serialize(&value).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized,
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
0
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn get_raw_experiemtal_transform_context(
|
||||
env: &MetadataContextHostEnvironment,
|
||||
mut env: FunctionEnvMut<MetadataContextHostEnvironment>,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let experimental_context = &env.metadata_context.experimental;
|
||||
let serialized_experimental_context_bytes =
|
||||
PluginSerializedBytes::try_serialize(experimental_context)
|
||||
.expect("Should be serializable");
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_experimental_context_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
let experimental_context = env.data().metadata_context.experimental.clone();
|
||||
let serialized_experimental_context_bytes =
|
||||
PluginSerializedBytes::try_serialize(&experimental_context)
|
||||
.expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_experimental_context_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
@ -41,11 +41,7 @@
|
||||
* actual vec into guest it'll write pointer to the vec into the struct.
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use swc_common::{plugin::metadata::TransformPluginMetadataContext, SourceMap};
|
||||
use wasmer::{imports, Function, ImportObject, Module};
|
||||
use wasmer::{imports, Function, FunctionEnv, Imports, Store};
|
||||
|
||||
use crate::{
|
||||
host_environment::BaseHostEnvironment,
|
||||
@ -57,247 +53,190 @@ use crate::{
|
||||
has_trailing_comments_proxy, move_leading_comments_proxy, move_trailing_comments_proxy,
|
||||
take_leading_comments_proxy, take_trailing_comments_proxy, CommentHostEnvironment,
|
||||
},
|
||||
diagnostics::{set_plugin_core_pkg_diagnostics, DiagnosticContextHostEnvironment},
|
||||
metadata_context::get_raw_experiemtal_transform_context,
|
||||
set_transform_result::{set_transform_result, TransformResultHostEnvironment},
|
||||
source_map::span_to_source_proxy,
|
||||
span::span_dummy_with_cmt_proxy,
|
||||
},
|
||||
};
|
||||
|
||||
mod comments;
|
||||
mod diagnostics;
|
||||
mod handler;
|
||||
mod hygiene;
|
||||
mod metadata_context;
|
||||
mod set_transform_result;
|
||||
mod source_map;
|
||||
mod span;
|
||||
pub(crate) mod comments;
|
||||
pub(crate) mod diagnostics;
|
||||
pub(crate) mod handler;
|
||||
pub(crate) mod hygiene;
|
||||
pub(crate) mod metadata_context;
|
||||
pub(crate) mod set_transform_result;
|
||||
pub(crate) mod source_map;
|
||||
pub(crate) mod span;
|
||||
|
||||
use handler::*;
|
||||
use hygiene::*;
|
||||
|
||||
use self::{
|
||||
diagnostics::{set_plugin_core_pkg_diagnostics, DiagnosticContextHostEnvironment},
|
||||
metadata_context::{
|
||||
copy_context_key_to_host_env, get_experimental_transform_context, get_transform_context,
|
||||
get_transform_plugin_config, MetadataContextHostEnvironment,
|
||||
},
|
||||
source_map::{
|
||||
doctest_offset_line_proxy, lookup_byte_offset_proxy, lookup_char_pos_proxy,
|
||||
merge_spans_proxy, span_to_filename_proxy, span_to_lines_proxy, span_to_source_proxy,
|
||||
span_to_string_proxy, SourceMapHostEnvironment,
|
||||
merge_spans_proxy, span_to_filename_proxy, span_to_lines_proxy, span_to_string_proxy,
|
||||
SourceMapHostEnvironment,
|
||||
},
|
||||
};
|
||||
|
||||
/// Create an ImportObject includes functions to be imported from host to the
|
||||
/// plugins.
|
||||
pub(crate) fn build_import_object(
|
||||
module: &Module,
|
||||
source_map: Arc<SourceMap>,
|
||||
metadata_context: Arc<TransformPluginMetadataContext>,
|
||||
plugin_config: Option<serde_json::Value>,
|
||||
transform_result: &Arc<Mutex<Vec<u8>>>,
|
||||
core_diag_buffer: &Arc<Mutex<Vec<u8>>>,
|
||||
) -> ImportObject {
|
||||
let store = module.store();
|
||||
|
||||
wasmer_store: &mut Store,
|
||||
metadata_env: &FunctionEnv<MetadataContextHostEnvironment>,
|
||||
transform_env: &FunctionEnv<TransformResultHostEnvironment>,
|
||||
base_env: &FunctionEnv<BaseHostEnvironment>,
|
||||
comments_env: &FunctionEnv<CommentHostEnvironment>,
|
||||
source_map_host_env: &FunctionEnv<SourceMapHostEnvironment>,
|
||||
diagnostics_env: &FunctionEnv<DiagnosticContextHostEnvironment>,
|
||||
) -> Imports {
|
||||
// core_diagnostics
|
||||
let set_transform_plugin_core_pkg_diagnostics_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
DiagnosticContextHostEnvironment::new(core_diag_buffer),
|
||||
let set_transform_plugin_core_pkg_diagnostics_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
diagnostics_env,
|
||||
set_plugin_core_pkg_diagnostics,
|
||||
);
|
||||
|
||||
// metadata
|
||||
let context_key_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let copy_context_key_to_host_env_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(&metadata_context, &plugin_config, &context_key_buffer),
|
||||
copy_context_key_to_host_env,
|
||||
);
|
||||
let get_transform_plugin_config_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(&metadata_context, &plugin_config, &context_key_buffer),
|
||||
get_transform_plugin_config,
|
||||
);
|
||||
let get_transform_context_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(&metadata_context, &plugin_config, &context_key_buffer),
|
||||
get_transform_context,
|
||||
);
|
||||
let get_experimental_transform_context_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(&metadata_context, &plugin_config, &context_key_buffer),
|
||||
let copy_context_key_to_host_env_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, metadata_env, copy_context_key_to_host_env);
|
||||
let get_transform_plugin_config_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, metadata_env, get_transform_plugin_config);
|
||||
let get_transform_context_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, metadata_env, get_transform_context);
|
||||
|
||||
let get_experimental_transform_context_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
metadata_env,
|
||||
get_experimental_transform_context,
|
||||
);
|
||||
let get_raw_experiemtal_transform_context_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(&metadata_context, &plugin_config, &context_key_buffer),
|
||||
let get_raw_experiemtal_transform_context_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
metadata_env,
|
||||
get_raw_experiemtal_transform_context,
|
||||
);
|
||||
|
||||
// transform_result
|
||||
let set_transform_result_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
TransformResultHostEnvironment::new(transform_result),
|
||||
set_transform_result,
|
||||
);
|
||||
let set_transform_result_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, transform_env, set_transform_result);
|
||||
|
||||
// handler
|
||||
let emit_diagnostics_fn_decl =
|
||||
Function::new_native_with_env(store, BaseHostEnvironment::new(), emit_diagnostics);
|
||||
Function::new_typed_with_env(wasmer_store, base_env, emit_diagnostics);
|
||||
|
||||
// hygiene
|
||||
let mark_fresh_fn_decl = Function::new_native(store, mark_fresh_proxy);
|
||||
let mark_parent_fn_decl = Function::new_native(store, mark_parent_proxy);
|
||||
let mark_is_builtin_fn_decl = Function::new_native(store, mark_is_builtin_proxy);
|
||||
let mark_set_builtin_fn_decl = Function::new_native(store, mark_set_builtin_proxy);
|
||||
let mark_is_descendant_of_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
BaseHostEnvironment::new(),
|
||||
mark_is_descendant_of_proxy,
|
||||
);
|
||||
let mark_fresh_fn_decl = Function::new_typed(wasmer_store, mark_fresh_proxy);
|
||||
let mark_parent_fn_decl = Function::new_typed(wasmer_store, mark_parent_proxy);
|
||||
let mark_is_builtin_fn_decl = Function::new_typed(wasmer_store, mark_is_builtin_proxy);
|
||||
let mark_set_builtin_fn_decl = Function::new_typed(wasmer_store, mark_set_builtin_proxy);
|
||||
let mark_is_descendant_of_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, base_env, mark_is_descendant_of_proxy);
|
||||
|
||||
let mark_least_ancestor_fn_decl =
|
||||
Function::new_native_with_env(store, BaseHostEnvironment::new(), mark_least_ancestor_proxy);
|
||||
Function::new_typed_with_env(wasmer_store, base_env, mark_least_ancestor_proxy);
|
||||
|
||||
let syntax_context_apply_mark_fn_decl =
|
||||
Function::new_native(store, syntax_context_apply_mark_proxy);
|
||||
let syntax_context_remove_mark_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
BaseHostEnvironment::new(),
|
||||
syntax_context_remove_mark_proxy,
|
||||
);
|
||||
let syntax_context_outer_fn_decl = Function::new_native(store, syntax_context_outer_proxy);
|
||||
Function::new_typed(wasmer_store, syntax_context_apply_mark_proxy);
|
||||
let syntax_context_remove_mark_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, base_env, syntax_context_remove_mark_proxy);
|
||||
let syntax_context_outer_fn_decl =
|
||||
Function::new_typed(wasmer_store, syntax_context_outer_proxy);
|
||||
|
||||
// Span
|
||||
let span_dummy_with_cmt_fn_decl = Function::new_native(store, span_dummy_with_cmt_proxy);
|
||||
let span_dummy_with_cmt_fn_decl = Function::new_typed(wasmer_store, span_dummy_with_cmt_proxy);
|
||||
|
||||
// comments
|
||||
let comment_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let copy_comment_to_host_env_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, comments_env, copy_comment_to_host_env);
|
||||
|
||||
let copy_comment_to_host_env_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
CommentHostEnvironment::new(&comment_buffer),
|
||||
copy_comment_to_host_env,
|
||||
);
|
||||
let add_leading_comment_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, comments_env, add_leading_comment_proxy);
|
||||
|
||||
let add_leading_comment_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
CommentHostEnvironment::new(&comment_buffer),
|
||||
add_leading_comment_proxy,
|
||||
);
|
||||
let add_leading_comments_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, comments_env, add_leading_comments_proxy);
|
||||
|
||||
let add_leading_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
CommentHostEnvironment::new(&comment_buffer),
|
||||
add_leading_comments_proxy,
|
||||
);
|
||||
let has_leading_comments_fn_decl =
|
||||
Function::new_typed(wasmer_store, has_leading_comments_proxy);
|
||||
|
||||
let has_leading_comments_fn_decl = Function::new_native(store, has_leading_comments_proxy);
|
||||
let move_leading_comments_fn_decl =
|
||||
Function::new_typed(wasmer_store, move_leading_comments_proxy);
|
||||
|
||||
let move_leading_comments_fn_decl = Function::new_native(store, move_leading_comments_proxy);
|
||||
|
||||
let take_leading_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
let take_leading_comments_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
// take_* doesn't need to share buffer to pass values from plugin to the host - do not
|
||||
// clone buffer here.
|
||||
CommentHostEnvironment::new(&Default::default()),
|
||||
comments_env,
|
||||
take_leading_comments_proxy,
|
||||
);
|
||||
|
||||
let get_leading_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
let get_leading_comments_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
// get_* doesn't need to share buffer to pass values from plugin to the host - do not clone
|
||||
// buffer here.
|
||||
CommentHostEnvironment::new(&Default::default()),
|
||||
comments_env,
|
||||
get_leading_comments_proxy,
|
||||
);
|
||||
|
||||
let add_trailing_comment_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
CommentHostEnvironment::new(&comment_buffer),
|
||||
add_trailing_comment_proxy,
|
||||
);
|
||||
let add_trailing_comment_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, comments_env, add_trailing_comment_proxy);
|
||||
|
||||
let add_trailing_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
CommentHostEnvironment::new(&comment_buffer),
|
||||
add_trailing_comments_proxy,
|
||||
);
|
||||
let add_trailing_comments_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, comments_env, add_trailing_comments_proxy);
|
||||
|
||||
let has_trailing_comments_fn_decl = Function::new_native(store, has_trailing_comments_proxy);
|
||||
let has_trailing_comments_fn_decl =
|
||||
Function::new_typed(wasmer_store, has_trailing_comments_proxy);
|
||||
|
||||
let move_trailing_comments_fn_decl = Function::new_native(store, move_trailing_comments_proxy);
|
||||
let move_trailing_comments_fn_decl =
|
||||
Function::new_typed(wasmer_store, move_trailing_comments_proxy);
|
||||
|
||||
let take_trailing_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
let take_trailing_comments_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
// take_* doesn't need to share buffer to pass values from plugin to the host - do not
|
||||
// clone buffer here.
|
||||
CommentHostEnvironment::new(&Default::default()),
|
||||
comments_env,
|
||||
take_trailing_comments_proxy,
|
||||
);
|
||||
|
||||
let get_trailing_comments_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
let get_trailing_comments_fn_decl = Function::new_typed_with_env(
|
||||
wasmer_store,
|
||||
// get_* doesn't need to share buffer to pass values from plugin to the host - do not clone
|
||||
// buffer here.
|
||||
CommentHostEnvironment::new(&Default::default()),
|
||||
comments_env,
|
||||
get_trailing_comments_proxy,
|
||||
);
|
||||
|
||||
let add_pure_comment_fn_decl = Function::new_native(store, add_pure_comment_proxy);
|
||||
let add_pure_comment_fn_decl = Function::new_typed(wasmer_store, add_pure_comment_proxy);
|
||||
|
||||
// source_map
|
||||
let source_map_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let source_map = Arc::new(Mutex::new(source_map));
|
||||
let lookup_char_pos_source_map_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, lookup_char_pos_proxy);
|
||||
|
||||
let lookup_char_pos_source_map_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
lookup_char_pos_proxy,
|
||||
);
|
||||
let doctest_offset_line_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, doctest_offset_line_proxy);
|
||||
|
||||
let doctest_offset_line_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
doctest_offset_line_proxy,
|
||||
);
|
||||
let merge_spans_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, merge_spans_proxy);
|
||||
|
||||
let merge_spans_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
merge_spans_proxy,
|
||||
);
|
||||
let span_to_string_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, span_to_string_proxy);
|
||||
|
||||
let span_to_string_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
span_to_string_proxy,
|
||||
);
|
||||
let span_to_filename_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, span_to_filename_proxy);
|
||||
|
||||
let span_to_filename_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
span_to_filename_proxy,
|
||||
);
|
||||
let span_to_source_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, span_to_source_proxy);
|
||||
|
||||
let span_to_source_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
span_to_source_proxy,
|
||||
);
|
||||
let span_to_lines_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, span_to_lines_proxy);
|
||||
|
||||
let span_to_lines_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
span_to_lines_proxy,
|
||||
);
|
||||
|
||||
let lookup_byte_offset_fn_decl = Function::new_native_with_env(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
lookup_byte_offset_proxy,
|
||||
);
|
||||
let lookup_byte_offset_fn_decl =
|
||||
Function::new_typed_with_env(wasmer_store, source_map_host_env, lookup_byte_offset_proxy);
|
||||
|
||||
imports! {
|
||||
"env" => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use wasmer::{LazyInit, Memory};
|
||||
use wasmer::{FunctionEnvMut, Memory};
|
||||
|
||||
use crate::memory_interop::copy_bytes_into_host;
|
||||
|
||||
@ -10,17 +10,16 @@ use crate::memory_interop::copy_bytes_into_host;
|
||||
///
|
||||
/// When plugin performs its transform it'll fill in `transform_result` with
|
||||
/// serialized result. Host will reconstruct AST from those value.
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct TransformResultHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
pub transform_result: Arc<Mutex<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl TransformResultHostEnvironment {
|
||||
pub fn new(transform_result: &Arc<Mutex<Vec<u8>>>) -> TransformResultHostEnvironment {
|
||||
TransformResultHostEnvironment {
|
||||
memory: LazyInit::default(),
|
||||
memory: None,
|
||||
transform_result: transform_result.clone(),
|
||||
}
|
||||
}
|
||||
@ -32,11 +31,16 @@ impl TransformResultHostEnvironment {
|
||||
/// this to set its result back to host.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn set_transform_result(
|
||||
env: &TransformResultHostEnvironment,
|
||||
bytes_ptr: u32,
|
||||
bytes_ptr_len: u32,
|
||||
mut env: FunctionEnvMut<TransformResultHostEnvironment>,
|
||||
bytes_ptr: i32,
|
||||
bytes_ptr_len: i32,
|
||||
) {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
(*env.transform_result.lock()) = copy_bytes_into_host(memory, bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
let memory = env
|
||||
.data()
|
||||
.memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
(*env.data_mut().transform_result.lock()) =
|
||||
copy_bytes_into_host(&memory.view(&env), bytes_ptr, bytes_ptr_len);
|
||||
}
|
||||
|
@ -6,20 +6,18 @@ use swc_common::{
|
||||
source_map::{PartialFileLines, PartialLoc},
|
||||
BytePos, SourceMap, SourceMapper, Span, SyntaxContext,
|
||||
};
|
||||
use wasmer::{LazyInit, Memory, NativeFunc};
|
||||
use wasmer::{AsStoreMut, FunctionEnvMut, Memory, TypedFunction};
|
||||
|
||||
use crate::memory_interop::{allocate_return_values_into_guest, write_into_memory_view};
|
||||
|
||||
/// External environment state for imported (declared in host, injected into
|
||||
/// guest) fn for source map proxy.
|
||||
#[derive(wasmer::WasmerEnv, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct SourceMapHostEnvironment {
|
||||
#[wasmer(export)]
|
||||
pub memory: wasmer::LazyInit<Memory>,
|
||||
pub memory: Option<Memory>,
|
||||
/// Attached imported fn `__alloc` to the hostenvironment to allow any other
|
||||
/// imported fn can allocate guest's memory space from host runtime.
|
||||
#[wasmer(export(name = "__alloc"))]
|
||||
pub alloc_guest_memory: LazyInit<NativeFunc<u32, u32>>,
|
||||
pub alloc_guest_memory: Option<TypedFunction<u32, u32>>,
|
||||
pub source_map: Arc<Mutex<Arc<SourceMap>>>,
|
||||
/// A buffer to non-determined size of return value from the host.
|
||||
pub mutable_source_map_buffer: Arc<Mutex<Vec<u8>>>,
|
||||
@ -31,8 +29,8 @@ impl SourceMapHostEnvironment {
|
||||
mutable_source_map_buffer: &Arc<Mutex<Vec<u8>>>,
|
||||
) -> SourceMapHostEnvironment {
|
||||
SourceMapHostEnvironment {
|
||||
memory: LazyInit::default(),
|
||||
alloc_guest_memory: LazyInit::default(),
|
||||
memory: None,
|
||||
alloc_guest_memory: None,
|
||||
source_map: source_map.clone(),
|
||||
mutable_source_map_buffer: mutable_source_map_buffer.clone(),
|
||||
}
|
||||
@ -44,52 +42,54 @@ impl SourceMapHostEnvironment {
|
||||
/// to avoid unnecessary data copying.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn lookup_char_pos_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
should_include_source_file: i32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let original_loc = (env.source_map.lock()).lookup_char_pos(BytePos(byte_pos));
|
||||
let ret = PartialLoc {
|
||||
source_file: if should_include_source_file == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(original_loc.file)
|
||||
},
|
||||
line: original_loc.line,
|
||||
col: original_loc.col.0,
|
||||
col_display: original_loc.col_display,
|
||||
};
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
let original_loc = (env.data().source_map.lock()).lookup_char_pos(BytePos(byte_pos));
|
||||
let ret = PartialLoc {
|
||||
source_file: if should_include_source_file == 0 {
|
||||
None
|
||||
} else {
|
||||
0
|
||||
}
|
||||
Some(original_loc.file)
|
||||
},
|
||||
line: original_loc.line,
|
||||
col: original_loc.col.0,
|
||||
col_display: original_loc.col_display,
|
||||
};
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.data().alloc_guest_memory.clone().as_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn doctest_offset_line_proxy(env: &SourceMapHostEnvironment, orig: u32) -> u32 {
|
||||
(env.source_map.lock()).doctest_offset_line(orig as usize) as u32
|
||||
pub fn doctest_offset_line_proxy(env: FunctionEnvMut<SourceMapHostEnvironment>, orig: u32) -> u32 {
|
||||
(env.data().source_map.lock()).doctest_offset_line(orig as usize) as u32
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn merge_spans_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
lhs_lo: u32,
|
||||
lhs_hi: u32,
|
||||
lhs_ctxt: u32,
|
||||
@ -98,28 +98,34 @@ pub fn merge_spans_proxy(
|
||||
rhs_ctxt: u32,
|
||||
allocated_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let sp_lhs = Span {
|
||||
lo: BytePos(lhs_lo),
|
||||
hi: BytePos(lhs_hi),
|
||||
ctxt: SyntaxContext::from_u32(lhs_ctxt),
|
||||
};
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let sp_rhs = Span {
|
||||
lo: BytePos(rhs_lo),
|
||||
hi: BytePos(rhs_hi),
|
||||
ctxt: SyntaxContext::from_u32(rhs_ctxt),
|
||||
};
|
||||
let sp_lhs = Span {
|
||||
lo: BytePos(lhs_lo),
|
||||
hi: BytePos(lhs_hi),
|
||||
ctxt: SyntaxContext::from_u32(lhs_ctxt),
|
||||
};
|
||||
|
||||
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");
|
||||
write_into_memory_view(memory, &serialized_bytes, |_| allocated_ptr);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let sp_rhs = Span {
|
||||
lo: BytePos(rhs_lo),
|
||||
hi: BytePos(rhs_hi),
|
||||
ctxt: SyntaxContext::from_u32(rhs_ctxt),
|
||||
};
|
||||
|
||||
let ret = (env.data().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");
|
||||
write_into_memory_view(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
&serialized_bytes,
|
||||
|_, _| allocated_ptr,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@ -127,177 +133,192 @@ pub fn merge_spans_proxy(
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn span_to_lines_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
span_lo: u32,
|
||||
span_hi: u32,
|
||||
span_ctxt: u32,
|
||||
should_request_source_file: i32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let ret = (env.source_map.lock())
|
||||
.span_to_lines(span)
|
||||
.map(|lines| PartialFileLines {
|
||||
file: if should_request_source_file == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(lines.file)
|
||||
},
|
||||
lines: lines.lines,
|
||||
});
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let ret = (env.data().source_map.lock())
|
||||
.span_to_lines(span)
|
||||
.map(|lines| PartialFileLines {
|
||||
file: if should_request_source_file == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(lines.file)
|
||||
},
|
||||
lines: lines.lines,
|
||||
});
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn lookup_byte_offset_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
byte_pos: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> 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 memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let byte_pos = BytePos(byte_pos);
|
||||
let ret = (env.data().source_map.lock()).lookup_byte_offset(byte_pos);
|
||||
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn span_to_string_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
span_lo: u32,
|
||||
span_hi: u32,
|
||||
span_ctxt: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_string(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.data().source_map.lock()).span_to_string(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn span_to_filename_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
span_lo: u32,
|
||||
span_hi: u32,
|
||||
span_ctxt: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_filename(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.data().source_map.lock()).span_to_filename(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn span_to_source_proxy(
|
||||
env: &SourceMapHostEnvironment,
|
||||
mut env: FunctionEnvMut<SourceMapHostEnvironment>,
|
||||
span_lo: u32,
|
||||
span_hi: u32,
|
||||
span_ctxt: u32,
|
||||
allocated_ret_ptr: u32,
|
||||
) -> i32 {
|
||||
if let Some(memory) = env.memory_ref() {
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (env.source_map.lock()).span_to_snippet(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
let memory = env.data().memory.clone();
|
||||
let memory = memory
|
||||
.as_ref()
|
||||
.expect("Memory instance should be available, check initialization");
|
||||
|
||||
if let Some(alloc_guest_memory) = env.alloc_guest_memory_ref() {
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
let alloc_guest_memory = env.data().alloc_guest_memory.clone();
|
||||
let alloc_guest_memory = alloc_guest_memory
|
||||
.as_ref()
|
||||
.expect("Alloc guest memory fn should be available, check initialization");
|
||||
|
||||
let span = Span {
|
||||
lo: BytePos(span_lo),
|
||||
hi: BytePos(span_hi),
|
||||
ctxt: SyntaxContext::from_u32(span_ctxt),
|
||||
};
|
||||
let ret = (*env.data().source_map.lock()).span_to_snippet(span);
|
||||
let serialized_loc_bytes =
|
||||
PluginSerializedBytes::try_serialize(&ret).expect("Should be serializable");
|
||||
|
||||
allocate_return_values_into_guest(
|
||||
memory,
|
||||
&mut env.as_store_mut(),
|
||||
alloc_guest_memory,
|
||||
allocated_ret_ptr,
|
||||
&serialized_loc_bytes,
|
||||
);
|
||||
1
|
||||
}
|
||||
|
@ -1,71 +1,184 @@
|
||||
use std::{env, sync::Arc};
|
||||
|
||||
use anyhow::{Context, Error};
|
||||
use anyhow::Error;
|
||||
use parking_lot::Mutex;
|
||||
use swc_common::{plugin::metadata::TransformPluginMetadataContext, SourceMap};
|
||||
use wasmer::{ChainableNamedResolver, Instance};
|
||||
use wasmer_wasi::{is_wasi_module, WasiState};
|
||||
use swc_common::{
|
||||
plugin::{
|
||||
diagnostics::PluginCorePkgDiagnostics, metadata::TransformPluginMetadataContext,
|
||||
serialized::PluginSerializedBytes,
|
||||
},
|
||||
SourceMap,
|
||||
};
|
||||
use wasmer::{FunctionEnv, Instance, Store};
|
||||
use wasmer_wasix::{default_fs_backing, is_wasi_module, WasiEnv, WasiFunctionEnv};
|
||||
|
||||
use crate::imported_fn::build_import_object;
|
||||
use crate::{
|
||||
host_environment::BaseHostEnvironment,
|
||||
imported_fn::{
|
||||
build_import_object, comments::CommentHostEnvironment,
|
||||
diagnostics::DiagnosticContextHostEnvironment,
|
||||
metadata_context::MetadataContextHostEnvironment,
|
||||
set_transform_result::TransformResultHostEnvironment, source_map::SourceMapHostEnvironment,
|
||||
},
|
||||
};
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn load_plugin(
|
||||
store: &mut Store,
|
||||
plugin_path: &std::path::Path,
|
||||
cache: &once_cell::sync::Lazy<crate::cache::PluginModuleCache>,
|
||||
source_map: &Arc<SourceMap>,
|
||||
metadata_context: &Arc<TransformPluginMetadataContext>,
|
||||
plugin_config: Option<serde_json::Value>,
|
||||
transform_result_buffer: &Arc<Mutex<Vec<u8>>>,
|
||||
core_diag_buffer: &Arc<Mutex<Vec<u8>>>,
|
||||
) -> Result<Instance, Error> {
|
||||
let module = cache.load_module(plugin_path)?;
|
||||
) -> Result<
|
||||
(
|
||||
Instance,
|
||||
Arc<Mutex<Vec<u8>>>,
|
||||
PluginCorePkgDiagnostics,
|
||||
Option<WasiFunctionEnv>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
let module = cache.load_module(store, plugin_path);
|
||||
|
||||
let import_object = build_import_object(
|
||||
&module,
|
||||
source_map.clone(),
|
||||
metadata_context.clone(),
|
||||
plugin_config,
|
||||
transform_result_buffer,
|
||||
core_diag_buffer,
|
||||
);
|
||||
match module {
|
||||
Ok(module) => {
|
||||
let context_key_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let metadata_env = FunctionEnv::new(
|
||||
store,
|
||||
MetadataContextHostEnvironment::new(
|
||||
metadata_context,
|
||||
&plugin_config,
|
||||
&context_key_buffer,
|
||||
),
|
||||
);
|
||||
|
||||
// Plugin binary can be either wasm32-wasi or wasm32-unknown-unknown.
|
||||
// Wasi specific env need to be initialized if given module targets wasm32-wasi.
|
||||
// TODO: wasm host native runtime throws 'Memory should be set on `WasiEnv`
|
||||
// first'
|
||||
let instance = if is_wasi_module(&module) {
|
||||
// Create the `WasiEnv`.
|
||||
let mut wasi_env = WasiState::new(
|
||||
plugin_path
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.expect("Plugin path missing file name"),
|
||||
);
|
||||
let transform_result: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(vec![]));
|
||||
let transform_env = FunctionEnv::new(
|
||||
store,
|
||||
TransformResultHostEnvironment::new(&transform_result),
|
||||
);
|
||||
|
||||
// Implicitly enable filesystem access for the wasi plugin to cwd.
|
||||
//
|
||||
// This allows wasi plugin can read arbitary data (i.e node_modules) or produce
|
||||
// output for post process (i.e .lcov coverage data) directly.
|
||||
//
|
||||
// TODO: this is not finalized decision
|
||||
// - should we support this?
|
||||
// - can we limit to allowlisted input / output only?
|
||||
// - should there be a top-level config from .swcrc to manually override this?
|
||||
let wasi_env = if let Ok(cwd) = env::current_dir() {
|
||||
wasi_env.map_dir("/cwd", cwd)?
|
||||
} else {
|
||||
&mut wasi_env
|
||||
};
|
||||
let base_env = FunctionEnv::new(store, BaseHostEnvironment::new());
|
||||
|
||||
let mut wasi_env = wasi_env.finalize()?;
|
||||
let comment_buffer = Arc::new(Mutex::new(vec![]));
|
||||
|
||||
// Generate an `ImportObject` from wasi_env, overwrite into imported_object
|
||||
let wasi_env_import_object = wasi_env.import_object(&module)?;
|
||||
let chained_resolver = import_object.chain_front(wasi_env_import_object);
|
||||
Instance::new(&module, &chained_resolver)
|
||||
} else {
|
||||
Instance::new(&module, &import_object)
|
||||
};
|
||||
let comments_env =
|
||||
FunctionEnv::new(store, CommentHostEnvironment::new(&comment_buffer));
|
||||
|
||||
instance.context("Failed to create plugin instance")
|
||||
let source_map_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let source_map = Arc::new(Mutex::new(source_map.clone()));
|
||||
|
||||
let source_map_host_env = FunctionEnv::new(
|
||||
store,
|
||||
SourceMapHostEnvironment::new(&source_map, &source_map_buffer),
|
||||
);
|
||||
|
||||
let diagnostics_buffer: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(vec![]));
|
||||
let diagnostics_env = FunctionEnv::new(
|
||||
store,
|
||||
DiagnosticContextHostEnvironment::new(&diagnostics_buffer),
|
||||
);
|
||||
|
||||
let mut import_object = build_import_object(
|
||||
store,
|
||||
&metadata_env,
|
||||
&transform_env,
|
||||
&base_env,
|
||||
&comments_env,
|
||||
&source_map_host_env,
|
||||
&diagnostics_env,
|
||||
);
|
||||
|
||||
// Plugin binary can be either wasm32-wasi or wasm32-unknown-unknown.
|
||||
// Wasi specific env need to be initialized if given module targets wasm32-wasi.
|
||||
// TODO: wasm host native runtime throws 'Memory should be set on `WasiEnv`
|
||||
// first'
|
||||
let (instance, wasi_env) = if is_wasi_module(&module) {
|
||||
let file_name = plugin_path
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.expect("Plugin path missing file name");
|
||||
|
||||
let builder = WasiEnv::builder(file_name);
|
||||
|
||||
// Implicitly enable filesystem access for the wasi plugin to cwd.
|
||||
//
|
||||
// This allows wasi plugin can read arbitary data (i.e node_modules) or produce
|
||||
// output for post process (i.e .lcov coverage data) directly.
|
||||
//
|
||||
// TODO: this is not finalized decision
|
||||
// - should we support this?
|
||||
// - can we limit to allowlisted input / output only?
|
||||
// - should there be a top-level config from .swcrc to manually override this?
|
||||
let wasi_env_builder = if let Ok(cwd) = env::current_dir() {
|
||||
builder
|
||||
.fs(default_fs_backing())
|
||||
.map_dirs(vec![("/cwd".to_string(), cwd)].drain(..))?
|
||||
} else {
|
||||
builder
|
||||
};
|
||||
|
||||
//create the `WasiEnv`
|
||||
let mut wasi_env = wasi_env_builder.finalize(store)?;
|
||||
|
||||
// Then, we get the import object related to our WASI,
|
||||
// overwrite into imported_object
|
||||
// and attach it to the Wasm instance.
|
||||
let wasi_env_import_object = wasi_env.import_object(store, &module)?;
|
||||
import_object.extend(&wasi_env_import_object);
|
||||
|
||||
let instance = Instance::new(store, &module, &import_object)?;
|
||||
|
||||
wasi_env.initialize(store, instance.clone())?;
|
||||
|
||||
(instance, Some(wasi_env))
|
||||
} else {
|
||||
(Instance::new(store, &module, &import_object)?, None)
|
||||
};
|
||||
|
||||
// Attach the memory export
|
||||
let memory = instance.exports.get_memory("memory")?;
|
||||
import_object.define("env", "memory", memory.clone());
|
||||
|
||||
let alloc = instance.exports.get_typed_function(store, "__alloc")?;
|
||||
|
||||
// Unlike wasmer@2, have to manually `import` memory / necessary functions from
|
||||
// the guest into env.
|
||||
metadata_env.as_mut(store).memory = Some(memory.clone());
|
||||
metadata_env.as_mut(store).alloc_guest_memory = Some(alloc.clone());
|
||||
|
||||
transform_env.as_mut(store).memory = Some(memory.clone());
|
||||
|
||||
base_env.as_mut(store).memory = Some(memory.clone());
|
||||
|
||||
comments_env.as_mut(store).memory = Some(memory.clone());
|
||||
comments_env.as_mut(store).alloc_guest_memory = Some(alloc.clone());
|
||||
|
||||
source_map_host_env.as_mut(store).memory = Some(memory.clone());
|
||||
source_map_host_env.as_mut(store).alloc_guest_memory = Some(alloc);
|
||||
|
||||
diagnostics_env.as_mut(store).memory = Some(memory.clone());
|
||||
|
||||
// As soon as instance is ready, host calls a fn to read plugin's swc_core pkg
|
||||
// diagnostics as `handshake`. Once read those values will be available across
|
||||
// whole plugin transform execution.
|
||||
|
||||
// IMPORTANT NOTE
|
||||
// Note this is `handshake`, which we expect to success ALL TIME. Do not try to
|
||||
// expand `PluginCorePkgDiagnostics` as it'll cause deserialization failure
|
||||
// until we have forward-compat schema changes.
|
||||
instance
|
||||
.exports
|
||||
.get_typed_function::<(), u32>(store, "__get_transform_plugin_core_pkg_diag")?
|
||||
.call(store)?;
|
||||
|
||||
let diag_result: PluginCorePkgDiagnostics =
|
||||
PluginSerializedBytes::from_slice(&(&(*diagnostics_buffer.lock()))[..])
|
||||
.deserialize()?;
|
||||
|
||||
Ok((instance, transform_result, diag_result, wasi_env))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +1,40 @@
|
||||
use swc_common::plugin::serialized::PluginSerializedBytes;
|
||||
use swc_plugin_proxy::AllocatedBytesPtr;
|
||||
use wasmer::{Array, Memory, NativeFunc, WasmPtr};
|
||||
use wasmer::{Memory, MemoryView, StoreMut, TypedFunction, WasmPtr};
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn copy_bytes_into_host(memory: &Memory, bytes_ptr: u32, bytes_ptr_len: u32) -> Vec<u8> {
|
||||
let ptr: WasmPtr<u8, Array> = WasmPtr::new(bytes_ptr as _);
|
||||
pub fn copy_bytes_into_host(memory: &MemoryView, bytes_ptr: i32, bytes_ptr_len: i32) -> Vec<u8> {
|
||||
let ptr: WasmPtr<u8> = WasmPtr::new(bytes_ptr as _);
|
||||
let derefed_ptr = ptr.deref(memory);
|
||||
let values = ptr.slice(memory, bytes_ptr_len as u32).expect("xxx");
|
||||
|
||||
// Deref & read through plugin's wasm memory space via returned ptr
|
||||
let derefed_ptr = ptr
|
||||
.deref(memory, 0, bytes_ptr_len)
|
||||
.expect("Should able to deref from given ptr");
|
||||
|
||||
derefed_ptr
|
||||
.iter()
|
||||
.enumerate()
|
||||
.take(bytes_ptr_len as usize)
|
||||
.map(|(_size, cell)| cell.get())
|
||||
.collect::<Vec<u8>>()
|
||||
values
|
||||
.read_to_vec()
|
||||
.expect("Should able to read memory from given ptr")
|
||||
}
|
||||
|
||||
/// Locate a view from given memory, write serialized bytes into.
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn write_into_memory_view<F>(
|
||||
memory: &Memory,
|
||||
store: &mut StoreMut,
|
||||
serialized_bytes: &PluginSerializedBytes,
|
||||
get_allocated_ptr: F,
|
||||
) -> (u32, u32)
|
||||
where
|
||||
F: Fn(usize) -> u32,
|
||||
F: Fn(&mut StoreMut, usize) -> u32,
|
||||
{
|
||||
let serialized_len = serialized_bytes.as_ptr().1;
|
||||
|
||||
let ptr_start: u32 = get_allocated_ptr(serialized_len);
|
||||
let ptr_start_size: u32 = ptr_start;
|
||||
let serialized_len_size: u32 = serialized_len.try_into().unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Should be able to convert the value {} to u32",
|
||||
serialized_len
|
||||
)
|
||||
});
|
||||
let ptr_start = get_allocated_ptr(store, serialized_len);
|
||||
let ptr_start_size: u64 = ptr_start as u64;
|
||||
|
||||
// Note: it's important to get a view from memory _after_ alloc completes
|
||||
let view = memory.view::<u8>();
|
||||
|
||||
// Get a subarray for current memoryview starting from ptr address we just
|
||||
// allocated above, perform copying into specified ptr. Wasm's memory layout
|
||||
// is linear and we have atomic guarantee by not having any thread access,
|
||||
// so can safely get subarray from allocated ptr address.
|
||||
//
|
||||
// If we want safer operation instead, refer previous implementation
|
||||
// https://github.com/swc-project/swc/blob/1ef8f3749b6454eb7d40a36a5f9366137fa97928/crates/swc_plugin_runner/src/lib.rs#L56-L61
|
||||
unsafe {
|
||||
view.subarray(ptr_start_size, ptr_start_size + serialized_len_size)
|
||||
.copy_from(serialized_bytes.as_slice());
|
||||
}
|
||||
let view = memory.view(store);
|
||||
// [TODO]: we need wasmer@3 compatible optimization like before
|
||||
// https://github.com/swc-project/swc/blob/f73f96dd94639f8b7edcdb6290653e16bf848db6/crates/swc_plugin_runner/src/memory_interop.rs#L54
|
||||
view.write(ptr_start_size, serialized_bytes.as_slice())
|
||||
.expect("Should able to write into memory view");
|
||||
|
||||
(
|
||||
ptr_start,
|
||||
@ -70,34 +51,38 @@ where
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn allocate_return_values_into_guest(
|
||||
memory: &Memory,
|
||||
alloc_guest_memory: &NativeFunc<u32, u32>,
|
||||
store: &mut StoreMut,
|
||||
alloc_guest_memory: &TypedFunction<u32, u32>,
|
||||
allocated_ret_ptr: u32,
|
||||
serialized_bytes: &PluginSerializedBytes,
|
||||
) {
|
||||
let serialized_bytes_len: usize = serialized_bytes.as_ptr().1;
|
||||
|
||||
// In most cases our host-plugin trampoline works in a way that
|
||||
// plugin pre-allocates
|
||||
// memory before calling host imported fn. But in case of
|
||||
// comments return value is Vec<Comments> which
|
||||
// guest cannot predetermine size to allocate, instead
|
||||
// let host allocate by calling guest's alloc via attached
|
||||
// hostenvironment.
|
||||
let guest_memory_ptr = alloc_guest_memory
|
||||
.call(
|
||||
store,
|
||||
serialized_bytes_len
|
||||
.try_into()
|
||||
.expect("Should be able to convert size"),
|
||||
)
|
||||
.expect("Should able to allocate memory in the plugin");
|
||||
|
||||
let (allocated_ptr, allocated_ptr_len) =
|
||||
write_into_memory_view(memory, serialized_bytes, |_| {
|
||||
// In most cases our host-plugin trampoline works in a way that
|
||||
// plugin pre-allocates
|
||||
// memory before calling host imported fn. But in case of
|
||||
// comments return value is Vec<Comments> which
|
||||
// guest cannot predetermine size to allocate, instead
|
||||
// let host allocate by calling guest's alloc via attached
|
||||
// hostenvironment.
|
||||
alloc_guest_memory
|
||||
.call(
|
||||
serialized_bytes_len
|
||||
.try_into()
|
||||
.expect("Should be able to convert size"),
|
||||
)
|
||||
.expect("Should able to allocate memory in the plugin")
|
||||
});
|
||||
write_into_memory_view(memory, store, serialized_bytes, |s, _| guest_memory_ptr);
|
||||
|
||||
let allocated_bytes = AllocatedBytesPtr(allocated_ptr, allocated_ptr_len);
|
||||
// Retuning (allocated_ptr, len) into caller (plugin)
|
||||
let comment_ptr_serialized =
|
||||
PluginSerializedBytes::try_serialize(&allocated_bytes).expect("Should be serializable");
|
||||
|
||||
write_into_memory_view(memory, &comment_ptr_serialized, |_| allocated_ret_ptr);
|
||||
write_into_memory_view(memory, store, &comment_ptr_serialized, |_, _| {
|
||||
allocated_ret_ptr
|
||||
});
|
||||
}
|
||||
|
@ -13,22 +13,56 @@ use swc_common::{
|
||||
plugin::{diagnostics::PluginCorePkgDiagnostics, metadata::TransformPluginMetadataContext},
|
||||
SourceMap,
|
||||
};
|
||||
use wasmer::Instance;
|
||||
use wasmer::{AsStoreMut, Instance, Store, TypedFunction};
|
||||
use wasmer_wasix::WasiFunctionEnv;
|
||||
|
||||
#[cfg(feature = "__rkyv")]
|
||||
use crate::memory_interop::write_into_memory_view;
|
||||
|
||||
/// Creates an instnace of [Store].
|
||||
///
|
||||
/// This function exists because we need to disable simd.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[allow(unused_mut)]
|
||||
fn new_store() -> Store {
|
||||
// Use empty enumset to disable simd.
|
||||
use enumset::EnumSet;
|
||||
use wasmer::{BaseTunables, CompilerConfig, EngineBuilder, Target, Triple};
|
||||
let mut set = EnumSet::new();
|
||||
|
||||
// [TODO]: Should we use is_x86_feature_detected! macro instead?
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
set.insert(wasmer::CpuFeature::SSE2);
|
||||
let target = Target::new(Triple::host(), set);
|
||||
|
||||
let config = wasmer_compiler_cranelift::Cranelift::default();
|
||||
let mut engine = EngineBuilder::new(Box::new(config) as Box<dyn CompilerConfig>)
|
||||
.set_target(Some(target))
|
||||
.engine();
|
||||
let tunables = BaseTunables::for_target(engine.target());
|
||||
engine.set_tunables(tunables);
|
||||
|
||||
Store::new(engine)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn new_store() -> Store {
|
||||
Store::default()
|
||||
}
|
||||
|
||||
/// A struct encapsule executing a plugin's transform interop to its teardown
|
||||
pub struct TransformExecutor {
|
||||
// Main transform interface plugin exports
|
||||
exported_plugin_transform: wasmer::NativeFunc<(u32, u32, u32, u32), u32>,
|
||||
exported_plugin_transform: TypedFunction<(u32, u32, u32, u32), u32>,
|
||||
// `__free` function automatically exported via swc_plugin sdk to allow deallocation in guest
|
||||
// memory space
|
||||
exported_plugin_free: wasmer::NativeFunc<(u32, u32), u32>,
|
||||
exported_plugin_free: TypedFunction<(u32, u32), u32>,
|
||||
// `__alloc` function automatically exported via swc_plugin sdk to allow allocation in guest
|
||||
// memory space
|
||||
exported_plugin_alloc: wasmer::NativeFunc<u32, u32>,
|
||||
exported_plugin_alloc: TypedFunction<u32, u32>,
|
||||
wasi_env: Option<WasiFunctionEnv>,
|
||||
instance: Instance,
|
||||
store: Store,
|
||||
// Reference to the pointers successfully allocated which'll be freed by Drop.
|
||||
allocated_ptr_vec: Vec<(u32, u32)>,
|
||||
transform_result: Arc<Mutex<Vec<u8>>>,
|
||||
@ -49,54 +83,33 @@ impl TransformExecutor {
|
||||
metadata_context: &Arc<TransformPluginMetadataContext>,
|
||||
plugin_config: Option<serde_json::Value>,
|
||||
) -> Result<TransformExecutor, Error> {
|
||||
let transform_result = Arc::new(Mutex::new(vec![]));
|
||||
let core_diag_buffer = Arc::new(Mutex::new(vec![]));
|
||||
let mut store = new_store();
|
||||
|
||||
let instance = crate::load_plugin::load_plugin(
|
||||
path,
|
||||
cache,
|
||||
source_map,
|
||||
metadata_context,
|
||||
plugin_config,
|
||||
&transform_result,
|
||||
&core_diag_buffer,
|
||||
)?;
|
||||
let (instance, transform_result, diagnostics_buffer, wasi_env) =
|
||||
crate::load_plugin::load_plugin(
|
||||
&mut store,
|
||||
path,
|
||||
cache,
|
||||
source_map,
|
||||
metadata_context,
|
||||
plugin_config,
|
||||
)?;
|
||||
|
||||
// As soon as instance is ready, host calls a fn to read plugin's swc_core pkg
|
||||
// diagnostics as `handshake`. Once read those values will be available across
|
||||
// whole plugin transform execution.
|
||||
|
||||
// IMPORTANT NOTE
|
||||
// Note this is `handshake`, which we expect to success ALL TIME. Do not try to
|
||||
// expand `PluginCorePkgDiagnostics` as it'll cause deserialization failure
|
||||
// until we have forward-compat schema changes.
|
||||
instance
|
||||
.exports
|
||||
.get_native_function::<(), i32>("__get_transform_plugin_core_pkg_diag")?
|
||||
.call()?;
|
||||
|
||||
let diag_result: PluginCorePkgDiagnostics =
|
||||
PluginSerializedBytes::from_slice(&(&(*core_diag_buffer.lock()))[..]).deserialize()?;
|
||||
|
||||
let tracker = TransformExecutor {
|
||||
let executor = TransformExecutor {
|
||||
exported_plugin_transform: instance
|
||||
.exports
|
||||
.get_native_function::<(u32, u32, u32, u32), u32>(
|
||||
"__transform_plugin_process_impl",
|
||||
)?,
|
||||
exported_plugin_free: instance
|
||||
.exports
|
||||
.get_native_function::<(u32, u32), u32>("__free")?,
|
||||
exported_plugin_alloc: instance
|
||||
.exports
|
||||
.get_native_function::<u32, u32>("__alloc")?,
|
||||
.get_typed_function(&store, "__transform_plugin_process_impl")?,
|
||||
exported_plugin_free: instance.exports.get_typed_function(&store, "__free")?,
|
||||
exported_plugin_alloc: instance.exports.get_typed_function(&store, "__alloc")?,
|
||||
instance,
|
||||
store,
|
||||
wasi_env,
|
||||
allocated_ptr_vec: Vec::with_capacity(3),
|
||||
transform_result,
|
||||
plugin_core_diag: diag_result,
|
||||
plugin_core_diag: diagnostics_buffer,
|
||||
};
|
||||
|
||||
Ok(tracker)
|
||||
Ok(executor)
|
||||
}
|
||||
|
||||
/// Copy host's serialized bytes into guest (plugin)'s allocated memory.
|
||||
@ -108,11 +121,22 @@ impl TransformExecutor {
|
||||
) -> Result<(u32, u32), Error> {
|
||||
let memory = self.instance.exports.get_memory("memory")?;
|
||||
|
||||
let ptr = write_into_memory_view(memory, serialized_bytes, |serialized_len| {
|
||||
self.exported_plugin_alloc
|
||||
.call(serialized_len.try_into().expect(""))
|
||||
.expect("")
|
||||
});
|
||||
let ptr = write_into_memory_view(
|
||||
memory,
|
||||
&mut self.store.as_store_mut(),
|
||||
serialized_bytes,
|
||||
|s, serialized_len| {
|
||||
self.exported_plugin_alloc
|
||||
.call(s, serialized_len.try_into().expect("booo"))
|
||||
.expect(
|
||||
format!(
|
||||
"Should able to allocate memory for the size of {}",
|
||||
serialized_len
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
self.allocated_ptr_vec.push(ptr);
|
||||
Ok(ptr)
|
||||
@ -154,7 +178,7 @@ impl TransformExecutor {
|
||||
* current runtime.
|
||||
*/
|
||||
#[allow(unreachable_code)]
|
||||
pub fn is_transform_schema_compatible(&self) -> Result<bool, Error> {
|
||||
pub fn is_transform_schema_compatible(&mut self) -> Result<bool, Error> {
|
||||
#[cfg(any(
|
||||
feature = "plugin_transform_schema_v1",
|
||||
feature = "plugin_transform_schema_vtest"
|
||||
@ -191,6 +215,7 @@ impl TransformExecutor {
|
||||
let guest_program_ptr = self.write_bytes_into_guest(program)?;
|
||||
|
||||
let result = self.exported_plugin_transform.call(
|
||||
&mut self.store,
|
||||
guest_program_ptr.0,
|
||||
guest_program_ptr.1,
|
||||
unresolved_mark.as_u32(),
|
||||
@ -205,8 +230,12 @@ impl Drop for TransformExecutor {
|
||||
fn drop(&mut self) {
|
||||
for ptr in self.allocated_ptr_vec.iter() {
|
||||
self.exported_plugin_free
|
||||
.call(ptr.0, ptr.1)
|
||||
.call(&mut self.store, ptr.0, ptr.1)
|
||||
.expect("Failed to free memory allocated in the plugin");
|
||||
}
|
||||
|
||||
if let Some(wasi_env) = &self.wasi_env {
|
||||
wasi_env.cleanup(&mut self.store, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +84,6 @@ fn invoke(input: PathBuf) -> Result<(), Error> {
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
info!("Creating cache");
|
||||
|
||||
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
|
||||
&path,
|
||||
&PLUGIN_MODULE_CACHE,
|
||||
@ -146,7 +144,7 @@ fn invoke(input: PathBuf) -> Result<(), Error> {
|
||||
)),
|
||||
Some(json!({ "pluginConfig": "testValue" })),
|
||||
)
|
||||
.expect("Should load plugin");
|
||||
.expect("Should load first plugin");
|
||||
|
||||
serialized_program = plugin_transform_executor
|
||||
.transform(&serialized_program, Mark::new(), false)
|
||||
@ -164,7 +162,7 @@ fn invoke(input: PathBuf) -> Result<(), Error> {
|
||||
)),
|
||||
Some(json!({ "pluginConfig": "testValue" })),
|
||||
)
|
||||
.expect("Should load plugin");
|
||||
.expect("Should load second plugin");
|
||||
|
||||
serialized_program = plugin_transform_executor
|
||||
.transform(&serialized_program, Mark::new(), false)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "swc_noop_plugin"
|
||||
name = "swc_noop_plugin"
|
||||
publish = false
|
||||
version = "0.1.0"
|
||||
|
||||
@ -11,4 +11,6 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
serde = "1"
|
||||
swc_core = {path = "../../../../swc_core", features = ["ecma_plugin_transform"]}
|
||||
swc_core = { path = "../../../../swc_core", features = [
|
||||
"ecma_plugin_transform",
|
||||
] }
|
||||
|
@ -4,6 +4,6 @@ use swc_core::{
|
||||
};
|
||||
|
||||
#[plugin_transform]
|
||||
pub fn process(program: Program, metadata: TransformPluginProgramMetadata) -> Program {
|
||||
pub fn process(program: Program, _metadata: TransformPluginProgramMetadata) -> Program {
|
||||
program
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ allow = [
|
||||
"Zlib",
|
||||
"MPL-2.0",
|
||||
"0BSD",
|
||||
"LicenseRef-ring", #ring
|
||||
"Unicode-DFS-2016", #unicode-ident
|
||||
]
|
||||
# List of explictly disallowed licenses
|
||||
@ -102,7 +103,7 @@ default = "deny"
|
||||
confidence-threshold = 0.8
|
||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||
# aren't accepted for every possible crate as with the normal allow list
|
||||
exceptions = []
|
||||
exceptions = [{ allow = ["BUSL-1.1"], name = "webc" }]
|
||||
|
||||
[[licenses.clarify]]
|
||||
# The name of the crate the clarification applies to
|
||||
@ -118,6 +119,11 @@ exceptions = []
|
||||
# depending on the rest of your configuration
|
||||
license-files = [{ path = "COPYRIGHT", hash = 972598577 }]
|
||||
|
||||
[[licenses.clarify]]
|
||||
expression = "LicenseRef-ring"
|
||||
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
|
||||
name = "ring"
|
||||
|
||||
# Some crates don't have (easily) machine readable licensing information,
|
||||
# adding a clarification entry for it allows you to manually specify the
|
||||
# licensing information
|
||||
|
@ -61,7 +61,9 @@ const inferBinaryName = () => {
|
||||
);
|
||||
};
|
||||
|
||||
describe("Published plugins", () => {
|
||||
// [TODO]: It is expected to have a breaking changes to the plugin,
|
||||
// disabling the test for now.
|
||||
describe.skip("Published plugins", () => {
|
||||
const packageName = platformPackagesMap[platform][arch];
|
||||
|
||||
if (!!packageName) {
|
||||
|
Loading…
Reference in New Issue
Block a user