Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wasm) Set up a minimal working example.
- Loading branch information
0 parents
commit 4051d04
Showing
13 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target/ | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "php-ext-wasm" | ||
version = "0.1.0" | ||
authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"] | ||
|
||
[lib] | ||
crate-type = ["dylib", "staticlib"] | ||
|
||
[dependencies] | ||
wasmi = "^0.4.2" | ||
|
||
[build-dependencies] | ||
cbindgen = "^0.6.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# PHP `ext-wasm` | ||
|
||
This is only experimental right now. | ||
|
||
The goal of the project is to be able to run WebAssembly binaries from | ||
PHP directly. So much fun coming! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
extern crate cbindgen; | ||
|
||
use std::env; | ||
|
||
fn main() { | ||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||
|
||
cbindgen::generate(crate_dir) | ||
.expect("Unable to generate C bindings.") | ||
.write_to_file("headers/php-ext-wasm.h"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
header = """ | ||
/* | ||
php-ext-wasm | ||
Warning, this file is autogenerated by `cbindgen`. | ||
Do not modify this manually. | ||
*/""" | ||
tab_width = 4 | ||
language = "C" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
compile-toy: | ||
cd tests && \ | ||
rustc --target wasm32-unknown-unknown -O --crate-type=cdylib toy.rs -o toy.raw.wasm && \ | ||
wasm-gc toy.raw.wasm toy.wasm && \ | ||
rm toy.raw.wasm | ||
|
||
c: | ||
clang \ | ||
-Wall \ | ||
-o test-c \ | ||
test.c \ | ||
-L target/release/ \ | ||
-l php_ext_wasm \ | ||
-l System \ | ||
-l pthread \ | ||
-l c \ | ||
-l m | ||
|
||
# Local Variables: | ||
# mode: makefile | ||
# End: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
extern crate wasmi; | ||
|
||
use wasmi::{ | ||
Error, | ||
ImportsBuilder, | ||
Module, | ||
ModuleInstance, | ||
ModuleRef, | ||
NopExternals, | ||
RuntimeValue, | ||
}; | ||
use std::fs::File; | ||
use std::io::{self, Read}; | ||
use std::path::PathBuf; | ||
|
||
pub fn read_wasm_binary(path: &PathBuf) -> io::Result<Vec<u8>> { | ||
let mut file = File::open(path)?; | ||
let mut buffer = Vec::new(); | ||
|
||
file.read_to_end(&mut buffer).unwrap(); | ||
|
||
Ok(buffer) | ||
} | ||
|
||
pub struct WASMInstance { | ||
pub file_path: String, | ||
instance: ModuleRef, | ||
} | ||
|
||
impl WASMInstance { | ||
pub fn new(path: &PathBuf, wasm_binary: Vec<u8>) -> Result<Self, Error> { | ||
let module = Module::from_buffer(&wasm_binary)?; | ||
|
||
Ok( | ||
WASMInstance { | ||
file_path: path.to_string_lossy().into_owned(), | ||
instance: ModuleInstance::new(&module, &ImportsBuilder::default())?.assert_no_start(), | ||
} | ||
) | ||
} | ||
|
||
pub fn invoke(&self, function_name: &str, arguments: &[RuntimeValue]) -> Option<RuntimeValue> { | ||
self.instance.invoke_export(function_name, arguments, &mut NopExternals).expect("foo") | ||
} | ||
} | ||
|
||
pub mod ffi { | ||
use super::WASMInstance; | ||
use wasmi::{ | ||
RuntimeValue, | ||
nan_preserving_float::{F32, F64}, | ||
}; | ||
use std::{ | ||
ffi::CStr, | ||
os::raw::c_char, | ||
path::PathBuf, | ||
str, | ||
ptr | ||
}; | ||
|
||
macro_rules! check_and_deref { | ||
($variable:ident) => { | ||
{ | ||
assert!(!$variable.is_null()); | ||
|
||
unsafe { &*$variable } | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! check_and_deref_mut { | ||
($variable:ident) => { | ||
{ | ||
assert!(!$variable.is_null()); | ||
|
||
unsafe { &mut *$variable } | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! check_and_deref_to_pathbuf { | ||
($variable:ident) => { | ||
{ | ||
assert!(!$variable.is_null()); | ||
|
||
PathBuf::from( | ||
unsafe { | ||
String::from_utf8_unchecked( | ||
CStr::from_ptr($variable).to_bytes().to_vec() | ||
) | ||
} | ||
) | ||
} | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_read_binary(file_path: *const c_char) -> *const Vec<u8> { | ||
Box::into_raw( | ||
Box::new( | ||
super::read_wasm_binary(&check_and_deref_to_pathbuf!(file_path)).unwrap_or_else(|_| vec![]) | ||
) | ||
) | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_new_instance(file_path: *const c_char, wasm_binary: *const Vec<u8>) -> *mut WASMInstance { | ||
let file_path = check_and_deref_to_pathbuf!(file_path); | ||
let wasm_binary = check_and_deref!(wasm_binary).to_vec(); | ||
|
||
match super::WASMInstance::new(&file_path, wasm_binary) { | ||
Ok(wasm_instance) => Box::into_raw(Box::new(wasm_instance)), | ||
Err(_) => ptr::null_mut(), | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_function( | ||
wasm_instance: *const WASMInstance, | ||
function_name: *const c_char, | ||
arguments: *const Vec<RuntimeValue> | ||
) { | ||
let wasm_instance = check_and_deref!(wasm_instance); | ||
let function_name = unsafe { | ||
assert!(!function_name.is_null()); | ||
str::from_utf8_unchecked(CStr::from_ptr(function_name).to_bytes()) | ||
}; | ||
let arguments = check_and_deref!(arguments).as_slice(); | ||
|
||
println!("{:?}", wasm_instance.invoke(function_name, arguments)); | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_arguments_builder() -> *mut Vec<RuntimeValue> { | ||
Box::into_raw(Box::new(Vec::new())) | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_arguments_builder_add_i32(arguments: *mut Vec<RuntimeValue>, argument: i32) { | ||
check_and_deref_mut!(arguments).push(RuntimeValue::I32(argument)); | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_arguments_builder_add_i64(arguments: *mut Vec<RuntimeValue>, argument: i64) { | ||
check_and_deref_mut!(arguments).push(RuntimeValue::I64(argument)); | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_arguments_builder_add_f32(arguments: *mut Vec<RuntimeValue>, argument: f32) { | ||
check_and_deref_mut!(arguments).push(RuntimeValue::F32(F32::from_float(argument))); | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn wasm_invoke_arguments_builder_add_f64(arguments: *mut Vec<RuntimeValue>, argument: f64) { | ||
check_and_deref_mut!(arguments).push(RuntimeValue::F64(F64::from_float(argument))); | ||
} | ||
} | ||
|
||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn case_invoke() { | ||
let file_path = PathBuf::from("./tests/toy.wasm"); | ||
let wasm_binary = read_wasm_binary(&file_path).unwrap(); | ||
let wasm_instance = WASMInstance::new(&file_path, wasm_binary).unwrap(); | ||
let result = wasm_instance.invoke("sum", &[1.into(), 2.into()]); | ||
|
||
assert_eq!(Some(3.into()), result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include "headers/php-ext-wasm.h" | ||
|
||
int main(int argc, char **argv) { | ||
const Vec_u8 *wasm_binary = wasm_read_binary("./tests/toy.wasm"); | ||
|
||
WASMInstance *wasm_instance = wasm_new_instance("./tests/toy.wasm", wasm_binary); | ||
|
||
if (NULL == wasm_instance) { | ||
printf("Cannot instanciate the WASM binary."); | ||
|
||
return 1; | ||
} | ||
|
||
Vec_RuntimeValue *arguments = wasm_invoke_arguments_builder(); | ||
wasm_invoke_arguments_builder_add_i32(arguments, 1); | ||
wasm_invoke_arguments_builder_add_i32(arguments, 2); | ||
|
||
wasm_invoke_function(wasm_instance, "sum", arguments); | ||
} | ||
|
||
/* | ||
* Local variables: | ||
* tab-width: 4 | ||
* c-basic-offset: 4 | ||
* End: | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env node | ||
|
||
const fs = require('fs'); | ||
|
||
WebAssembly | ||
.instantiate(fs.readFileSync('toy.wasm'), {}) | ||
.then(result => result.instance.exports.sum(1, 2)) | ||
.then(console.log); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#[no_mangle] | ||
pub extern "C" fn sum(x: i32, y: i32) -> i32 { | ||
x + y | ||
} |
Binary file not shown.