Skip to content

Commit

Permalink
stash
Browse files Browse the repository at this point in the history
  • Loading branch information
bhelx committed Dec 28, 2023
1 parent 3cabf94 commit 86c5092
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 149 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ members = [
]

[workspace.package]
version = "1.0.0-rc3"
version = "1.0.0-rc4"
edition = "2021"
authors = ["The Extism Authors"]
license = "BSD-Clause-3"
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ clean-wasi-sdk:
test: compile-examples
@extism call examples/simple_js.wasm greet --wasi --input="Benjamin"
@extism call examples/bundled.wasm greet --wasi --input="Benjamin"
@pip install -r examples/host_funcs/requirements.txt
@python examples/host_funcs/host.py examples/host_funcs.wasm

compile-examples:
./target/release/extism-js examples/simple_js/script.js -i examples/simple_js/script.d.ts -o examples/simple_js.wasm
cd examples/bundled && npm install && npm run build && cd ../..
./target/release/extism-js examples/host_funcs/script.js -i examples/host_funcs/script.d.ts -o examples/host_funcs.wasm
78 changes: 48 additions & 30 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
mod interface_parser;
mod opt;
mod options;
mod shim;
mod shims;
mod ts_parser;

use crate::interface_parser::parse_interface_file;
use crate::options::Options;
use crate::ts_parser::parse_interface_file;
use anyhow::{bail, Result};
use shim::create_shims;
use shims::generate_wasm_shims;
use std::env;
use std::fs::remove_dir_all;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::process::Stdio;
Expand All @@ -31,39 +30,50 @@ fn main() -> Result<()> {
return Ok(());
}

// We need to parse the interface.d.ts file
let interface_path = PathBuf::from(&opts.interface_file);
if !interface_path.exists() {
bail!(
"Could not find interface file {}. Set to a valid d.ts file with the -i flag",
&interface_path.to_str().unwrap()
);
}

let plugin_interface = parse_interface_file(&interface_path)?;

// Copy in the user's js code from stdin
let mut input_file = fs::File::open(&opts.input_js)?;
let mut user_code: Vec<u8> = vec![];
input_file.read_to_end(&mut user_code)?;

let mut contents = "Host.__hostFunctions = ['myHostFunc1', 'myHostFunc2'].sort();\n"
// If we have imports, we need to inject some state needed for host function support
let names = &plugin_interface
.imports
.functions
.iter()
.map(|s| format!("'{}'", &s.name))
.collect::<Vec<String>>()
.join(",");
let mut contents = format!("Host.__hostFunctions = [{}].sort();\n", names)
.as_bytes()
.to_owned();

contents.append(&mut user_code);

// Create a tmp dir to hold all the library objects
// This can go away once we do all the wasm-merge stuff in process
let tmp_dir = TempDir::new()?;
let core_path = tmp_dir.path().join("core.wasm");
let export_shim_path = tmp_dir.path().join("export-shim.wasm");
let import_shim_path = tmp_dir.path().join("import-shim.wasm");
let linked_shim_path = tmp_dir.path().join("linked.wasm");

// let tmp_dir = "/tmp/derp";
// let core_path = PathBuf::from("/tmp/derp/core.wasm");
// let export_shim_path = PathBuf::from("/tmp/derp/export-shim.wasm");
// let import_shim_path = PathBuf::from("/tmp/derp/import-shim.wasm");
// let linked_shim_path = PathBuf::from("/tmp/derp/linked.wasm");

// First wizen the core module
let self_cmd = env::args().next().expect("Expected a command argument");
//let tmp_dir = TempDir::new()?;
// let core_path = tmp_dir.path().join("core.wasm");
// let export_shim_path = tmp_dir.path().join("export-shim.wasm");
// let import_shim_path = tmp_dir.path().join("import-shim.wasm");
// let linked_shim_path = tmp_dir.path().join("linked.wasm");

let tmp_dir = "/tmp/derp";
let core_path = PathBuf::from("/tmp/derp/core.wasm");
let export_shim_path = PathBuf::from("/tmp/derp/export-shim.wasm");
let import_shim_path = PathBuf::from("/tmp/derp/import-shim.wasm");
let linked_shim_path = PathBuf::from("/tmp/derp/linked.wasm");

{
env::set_var("EXTISM_WIZEN", "1");
let mut command = Command::new(self_cmd)
Expand All @@ -83,8 +93,16 @@ fn main() -> Result<()> {
}
}

create_shims(&plugin_interface, &export_shim_path, &import_shim_path)?;
// Create our shim files given our parsed TS module object
// We have a shim file for exports and one optional one for imports
generate_wasm_shims(
plugin_interface.exports,
&export_shim_path,
plugin_interface.imports,
&import_shim_path,
)?;

// Merge the export shim with the core module
let mut command = Command::new("wasm-merge")
.arg(&core_path)
.arg("coremod")
Expand All @@ -98,14 +116,16 @@ fn main() -> Result<()> {
bail!("wasm-merge failed. Couldn't merge export shim");
}

if !&import_shim_path.exists() {
fs::copy(&linked_shim_path, &opts.output)?;
//remove_dir_all(tmp_dir)?;
return Ok(());
}

println!("merge imports now to {:#?}", &opts.output.to_str());
// // If there is no import shim, then there are no imports
// // and we can copy this intermediate wasm module as the output and return.
// // There is a probably a better way to signal this than just checking
// // for the existence of the file.
// if !&import_shim_path.exists() {
// fs::copy(&linked_shim_path, &opts.output)?;
// return Ok(());
// }

// Merge the import shim with the core+export (linked) module
let mut command = Command::new("wasm-merge")
.arg(&linked_shim_path)
.arg("coremod")
Expand All @@ -121,7 +141,5 @@ fn main() -> Result<()> {
bail!("wasm-merge failed. Couldn't merge import shim.");
}

//remove_dir_all(tmp_dir)?;

Ok(())
}
120 changes: 60 additions & 60 deletions crates/cli/src/shim.rs → crates/cli/src/shims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ use wasm_encoder::{
};
use wasm_encoder::{ImportSection, Module as WasmModule};

use crate::interface_parser::{Interface, PluginInterface};
use crate::ts_parser::Interface;

/// Generates the wasm shim for the exports
fn generate_wasm_shims(
pub fn generate_wasm_shims(
exports: Interface,
export_path: &PathBuf,
imports: Option<Interface>,
imports: Interface,
import_path: &PathBuf,
) -> Result<()> {
let mut export_mod = WasmModule::new();
Expand Down Expand Up @@ -89,21 +89,18 @@ fn generate_wasm_shims(
let mut file = File::create(export_path)?;
file.write_all(wasm_bytes.as_ref())?;

if imports.is_none() {
return Ok(());
}

let imports = imports.unwrap();

// Now do the imports
let mut import_mod = WasmModule::new();

// Encode the type section.
let mut types = TypeSection::new();

// for all other host funcs (TODO fix)
let params = vec![ValType::I64];
let results = vec![ValType::I64];
types.function(params, results);
if !imports.functions.is_empty() {
let params = vec![ValType::I64];
let results = vec![ValType::I64];
types.function(params, results);
}

// for __invokeHostFunc
let params = vec![ValType::I32, ValType::I64];
Expand All @@ -112,34 +109,39 @@ fn generate_wasm_shims(
import_mod.section(&types);

// Encode the import section
let mut import_sec = ImportSection::new();

for i in imports.functions.iter() {
import_sec.import(
"extism:host/user",
i.name.as_str(),
wasm_encoder::EntityType::Function(0),
);
if !imports.functions.is_empty() {
let mut import_sec = ImportSection::new();

for i in imports.functions.iter() {
import_sec.import(
"extism:host/user",
i.name.as_str(),
wasm_encoder::EntityType::Function(0),
);
}
import_mod.section(&import_sec);
}
import_mod.section(&import_sec);

// Encode the function section.
let func_type = if imports.functions.is_empty() { 0 } else { 1 };
let mut functions = FunctionSection::new();
functions.function(1);
functions.function(func_type);
import_mod.section(&functions);

// encode tables pointing to imports
let mut tables = TableSection::new();
let table_type = TableType {
element_type: wasm_encoder::RefType {
nullable: true,
heap_type: HeapType::Func,
},
minimum: 2,
maximum: None,
};
tables.table(table_type);
import_mod.section(&tables);
if !imports.functions.is_empty() {
// encode tables pointing to imports
let mut tables = TableSection::new();
let table_type = TableType {
element_type: wasm_encoder::RefType {
nullable: true,
heap_type: HeapType::Func,
},
minimum: imports.functions.len() as u32,
maximum: None,
};
tables.table(table_type);
import_mod.section(&tables);
}

// Encode the export section.
let mut export_sec = ExportSection::new();
Expand All @@ -150,23 +152,35 @@ fn generate_wasm_shims(
);
import_mod.section(&export_sec);

// Encode the element section.
let mut elements = ElementSection::new();
let func_elems = Elements::Functions(&[0, 1]);
let offset = ConstExpr::i32_const(0);
elements.active(None, &offset, func_elems);
import_mod.section(&elements);
if !imports.functions.is_empty() {
// Encode the element section.
let mut elements = ElementSection::new();
let func_elems = Elements::Functions(&[0, 1]);
let offset = ConstExpr::i32_const(0);
elements.active(None, &offset, func_elems);
import_mod.section(&elements);
}

// Encode the code section.
let mut codes = CodeSection::new();
let locals = vec![];
let mut f = Function::new(locals);
// we will essentially call the eval function
// in the core module here, similar to https://github.com/extism/js-pdk/blob/eaf17366624d48219cbd97a51e85569cffd12086/crates/cli/src/main.rs#L118
f.instruction(&Instruction::LocalGet(1));
f.instruction(&Instruction::LocalGet(0));
f.instruction(&Instruction::CallIndirect { ty: 0, table: 0 });
f.instruction(&Instruction::End);
if imports.functions.is_empty() {
// make it a no-op
f.instruction(&Instruction::LocalGet(1));
f.instruction(&Instruction::LocalGet(0));
f.instruction(&Instruction::Drop);
f.instruction(&Instruction::Drop);
f.instruction(&Instruction::I64Const(-1));
f.instruction(&Instruction::End);
} else {
// we will essentially call the eval function
// in the core module here, similar to https://github.com/extism/js-pdk/blob/eaf17366624d48219cbd97a51e85569cffd12086/crates/cli/src/main.rs#L118
f.instruction(&Instruction::LocalGet(1));
f.instruction(&Instruction::LocalGet(0));
f.instruction(&Instruction::CallIndirect { ty: 0, table: 0 });
f.instruction(&Instruction::End);
}
codes.function(&f);
import_mod.section(&codes);

Expand All @@ -176,17 +190,3 @@ fn generate_wasm_shims(

Ok(())
}

pub fn create_shims(
plugin_interface: &PluginInterface,
export_path: &PathBuf,
import_path: &PathBuf,
) -> Result<()> {
generate_wasm_shims(
plugin_interface.exports.clone(),
export_path,
plugin_interface.imports.clone(),
import_path,
)?;
Ok(())
}
Loading

0 comments on commit 86c5092

Please sign in to comment.