Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transcoding support #79

Merged
merged 3 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ js-component-bindgen = { path = "./crates/js-component-bindgen" }
wit-component = { workspace = true }

[build-dependencies]
anyhow = "1.0.71"
anyhow = { workspace = true }
js-component-bindgen = { path = "./crates/js-component-bindgen" }
wit-component = { workspace = true }

Expand Down
Binary file added adapter.wasm
Binary file not shown.
4 changes: 4 additions & 0 deletions bin/self_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ fn main() -> Result<()> {
encoder = encoder.adapter("wasi_snapshot_preview1", &adapter)?;

let adapted_component = encoder.encode()?;
fs::create_dir_all(PathBuf::from("./obj"))?;
let mut component_path = PathBuf::from("./obj").join(&name);
component_path.set_extension("component.wasm");
fs::write(component_path, &adapted_component)?;

let import_map = HashMap::from([
(
Expand Down
8 changes: 4 additions & 4 deletions crates/js-component-bindgen/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ pub fn render_intrinsics(
}
"),

Intrinsic::DataView => output.push_str("
let dv = new DataView(new ArrayBuffer());
const dataView = mem => dv.buffer === mem.buffer ? dv : dv = new DataView(mem.buffer);
"),
Intrinsic::DataView => output.push_str("
let dv = new DataView(new ArrayBuffer());
const dataView = mem => dv.buffer === mem.buffer ? dv : dv = new DataView(mem.buffer);
"),

Intrinsic::FetchCompile => if !no_nodejs_compat {
output.push_str("
Expand Down
54 changes: 44 additions & 10 deletions crates/js-component-bindgen/src/transpile_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ use wasmtime_environ::{
GlobalInitializer, InstantiateModule, LoweredIndex, RuntimeImportIndex,
RuntimeInstanceIndex, StaticModuleIndex, Trampoline, TrampolineIndex,
},
fact::{FixedEncoding, Transcode},
EntityIndex, PrimaryMap,
};
use wasmtime_environ::{EntityIndex, PrimaryMap};
use wit_bindgen_core::abi::{self, LiftLower};
use wit_component::StringEncoding;
use wit_parser::abi::AbiVariant;
Expand Down Expand Up @@ -431,6 +432,7 @@ impl<'a> Instantiator<'a, '_> {
}

fn trampoline(&mut self, i: TrampolineIndex, trampoline: &'a Trampoline) {
let i = i.as_u32();
match trampoline {
// these are hoisted before initialization
Trampoline::LowerImport { .. } => {}
Expand All @@ -446,15 +448,48 @@ impl<'a> Instantiator<'a, '_> {
// for now since it can't be tested and additionally JS doesn't
// support multi-memory which transcoders rely on anyway.
Trampoline::Transcoder {
op: _,
from: _,
from64: _,
to: _,
to64: _,
} => unimplemented!(),
op,
from,
from64,
to,
to64,
} => {
if *from64 || *to64 {
unimplemented!("memory 64 transcoder");
}
let from = from.as_u32();
let to = to.as_u32();
match op {
Transcode::Copy(FixedEncoding::Utf8) => {
uwriteln!(
self.src.js,
"function trampoline{i} (from_ptr, len, to_ptr) {{
new Uint8Array(memory{to}.buffer, to_ptr, len).set(new Uint8Array(memory{from}.buffer, from_ptr, len));
}}
"
);
}
Transcode::Copy(FixedEncoding::Utf16) => unimplemented!("utf16 copier"),
Transcode::Copy(FixedEncoding::Latin1) => unimplemented!("latin1 copier"),
Transcode::Latin1ToUtf16 => unimplemented!("latin to utf16 transcoder"),
Transcode::Latin1ToUtf8 => unimplemented!("latin to utf8 transcoder"),
Transcode::Utf16ToCompactProbablyUtf16 => {
unimplemented!("utf16 to compact wtf16 transcoder")
}
Transcode::Utf16ToCompactUtf16 => {
unimplemented!("utf16 to compact utf16 transcoder")
}
Transcode::Utf16ToLatin1 => unimplemented!("utf16 to latin1 transcoder"),
Transcode::Utf16ToUtf8 => unimplemented!("utf16 to utf8 transcoder"),
Transcode::Utf8ToCompactUtf16 => {
unimplemented!("utf8 to compact utf16 transcoder")
}
Transcode::Utf8ToLatin1 => unimplemented!("utf8 to latin1 transcoder"),
Transcode::Utf8ToUtf16 => unimplemented!("utf8 to utf16 transcoder"),
};
}

Trampoline::ResourceNew(resource) => {
let i = i.as_u32();
self.ensure_resource_table(*resource);
let rid = resource.as_u32();
uwrite!(
Expand All @@ -468,7 +503,6 @@ impl<'a> Instantiator<'a, '_> {
);
}
Trampoline::ResourceRep(resource) => {
let i = i.as_u32();
self.ensure_resource_table(*resource);
let rid = resource.as_u32();
uwrite!(
Expand All @@ -484,7 +518,6 @@ impl<'a> Instantiator<'a, '_> {
);
}
Trampoline::ResourceDrop(resource) => {
let i = i.as_u32();
self.ensure_resource_table(*resource);
let rid = resource.as_u32();
let resource = &self.types[*resource];
Expand Down Expand Up @@ -585,6 +618,7 @@ impl<'a> Instantiator<'a, '_> {
prev.is_none(),
"unsupported duplicate import of `{module}::{name}`"
);
assert!(prev.is_none());
}
let mut imports = String::new();
if !import_obj.is_empty() {
Expand Down
12 changes: 11 additions & 1 deletion test/cli.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { deepStrictEqual, ok, strictEqual } from 'node:assert';
import { readFile, rm } from 'node:fs/promises';
import { readFile, rm, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'url';
import { exec, jcoPath } from './helpers.js';
import { tmpdir } from 'node:os';
Expand All @@ -18,6 +18,16 @@ export async function cliTest (fixtures) {
catch {}
}

test('Transcoding', async () => {
const outDir = fileURLToPath(new URL(`./output/env-allow`, import.meta.url));
const { stderr } = await exec(jcoPath, 'transpile', `test/fixtures/env-allow.composed.wasm`, '-o', outDir);
strictEqual(stderr, '');
await writeFile(`${outDir}/package.json`, JSON.stringify({ type: 'module' }));
const source = await readFile(`${outDir}/env-allow.composed.js`);
const m = await import(`${outDir}/env-allow.composed.js`);
deepStrictEqual(m.testGetEnv(), [['CUSTOM', 'VAL']]);
});

test('Transpile', async () => {
try {
const name = 'flavorful';
Expand Down
Binary file added test/fixtures/env-allow.composed.wasm
Binary file not shown.
Binary file added test/fixtures/virt.wasm
Binary file not shown.
6 changes: 6 additions & 0 deletions update-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ cd ..
./src/jco.js componentize test/fixtures/component-gen/import-fn.js --wit test/fixtures/component-gen/import-fn.wit -o test/fixtures/components/import-fn.component.wasm

rm -rf wit-bindgen

## wasi virt to generate composition case
git clone https://github.com/bytecodealliance/wasi-virt
cd wasi-virt
cargo test
cp tests/generated/env-allow.composed.wasm ../test/fixtures/