first version of uw8-tool pack command

This commit is contained in:
2021-11-04 23:55:08 +01:00
parent 348657163d
commit 31cc63a93b
8 changed files with 842 additions and 9 deletions

3
uw8-tool/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/target/
*.wasm
*.uw8

7
uw8-tool/Cargo.lock generated
View File

@@ -14,11 +14,18 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]]
name = "uw8-tool"
version = "0.1.0"
dependencies = [
"anyhow",
"pico-args",
"wasm-encoder",
"wasmparser",
]

View File

@@ -9,3 +9,4 @@ edition = "2021"
wasmparser = "0.81"
wasm-encoder = "0.8"
anyhow = "1"
pico-args = "0.4"

View File

@@ -10,13 +10,13 @@ use std::io::prelude::*;
pub struct BaseModule {
pub types: Vec<FunctionType>,
pub function_imports: Vec<(&'static str, &'static str, u32)>,
pub function_imports: Vec<(&'static str, String, u32)>,
pub functions: Vec<u32>,
pub exports: Vec<(&'static str, u32)>,
pub memory: u32
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FunctionType {
pub params: Vec<ValType>,
pub result: Option<ValType>
@@ -58,6 +58,10 @@ impl BaseModule {
add_function(&mut functions, &type_map, "math", "pow", &[F32, F32], Some(F32));
add_function(&mut functions, &type_map, "math", "log", &[F32], Some(F32));
for i in functions.len()..64 {
add_function(&mut functions, &type_map, "uw8", &format!("reserved{}", i), &[], None);
}
let first_function = functions.len() as u32;
Ok(BaseModule {
@@ -85,7 +89,7 @@ impl BaseModule {
let mut imports = ImportSection::new();
for (module, name, type_) in &m.function_imports {
imports.import(*module, Some(*name), EntityType::Function(*type_));
imports.import(*module, Some(name.as_str()), EntityType::Function(*type_));
}
imports.import("env", Some("memory"), MemoryType {
@@ -139,8 +143,8 @@ impl BaseModule {
}
}
fn add_function(functions: &mut Vec<(&'static str, &'static str, u32)>, type_map: &HashMap<FunctionType, u32>, module: &'static str, name: &'static str, params: &[ValType], result: Option<ValType>) {
functions.push((module, name, lookup_type(type_map, params, result)));
fn add_function(functions: &mut Vec<(&'static str, String, u32)>, type_map: &HashMap<FunctionType, u32>, module: &'static str, name: &str, params: &[ValType], result: Option<ValType>) {
functions.push((module, name.to_string(), lookup_type(type_map, params, result)));
}
fn lookup_type(type_map: &HashMap<FunctionType, u32>, params: &[ValType], result: Option<ValType>) -> u32 {

View File

@@ -1,9 +1,45 @@
mod base_module;
mod pack;
use std::path::PathBuf;
use base_module::BaseModule;
use anyhow::Result;
use base_module::BaseModule;
use pico_args::Arguments;
fn main() -> Result<()> {
let mut args = Arguments::from_env();
if let Some(cmd) = args.subcommand()? {
match cmd.as_str() {
"make-base" => {
let version: u32 = args.free_from_str()?;
BaseModule::for_format_version(version)?
.write_to_file(format!("base{}.wasm", version))?;
}
"pack" => {
let version: u32 = args.opt_value_from_str(["-v", "--version"])?.unwrap_or(1);
let source: PathBuf = args.free_from_str()?;
let dest: PathBuf = args.free_from_str()?;
pack::pack(&source, &dest, version)?;
}
_ => {
eprintln!("Unknown subcommand '{}'", cmd);
print_help();
}
}
} else {
print_help();
}
BaseModule::for_format_version(1)?.write_to_file("base.wasm")?;
Ok(())
}
fn print_help() {
println!(
"Usage:
uw8-tool make-base <version>
uw8-tool pack <wasm file> <uw8 file>"
);
}

777
uw8-tool/src/pack.rs Normal file
View File

@@ -0,0 +1,777 @@
use crate::base_module::{self, BaseModule, FunctionType};
use anyhow::{anyhow, bail, Result};
use enc::ValType;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path};
use wasm_encoder as enc;
use wasmparser::{
ExportSectionReader, ExternalKind, FunctionBody, FunctionSectionReader, ImportSectionEntryType,
ImportSectionReader, TypeSectionReader,
};
pub fn pack(source: &Path, dest: &Path, version: u32) -> Result<()> {
let base = BaseModule::for_format_version(version)?;
let mut source_data = vec![];
File::open(source)?.read_to_end(&mut source_data)?;
let parsed_module = dbg!(ParsedModule::parse(&source_data)?);
let result = parsed_module.pack(&base)?;
/*
let module = enc::Module::new();
let mut context = Context {
base,
module,
type_mapping: HashMap::new(),
function_mapping: HashMap::new(),
next_function_index: 0,
};
for payload in wasmparser::Parser::new(0).parse_all(&source_data) {
let payload = payload?;
use wasmparser::Payload::*;
let _copy = match payload {
Version { .. } => false,
TypeSection(reader) => process_type_section(&mut context, reader)?,
ImportSection(reader) => process_import_section(&mut context, reader)?,
_ => true,
};
}
*/
let mut dest_data = vec![version as u8];
dest_data.extend_from_slice(&result[8..]);
File::create(dest)?.write_all(&dest_data)?;
Ok(())
}
struct Context {
base: BaseModule,
module: enc::Module,
type_mapping: HashMap<u32, u32>,
function_mapping: HashMap<u32, u32>,
next_function_index: u32,
}
fn process_type_section(
context: &mut Context,
mut reader: wasmparser::TypeSectionReader,
) -> Result<bool> {
use wasmparser::TypeDef;
let base_function_types: HashMap<base_module::FunctionType, u32> = context
.base
.types
.iter()
.enumerate()
.map(|(i, t)| (t.clone(), i as u32))
.collect();
for src_index in 0..reader.get_count() {
match reader.read()? {
TypeDef::Func(fnc) => {
let params: Vec<ValType> = to_val_type_vec(&fnc.params)?;
if fnc.returns.len() > 1 {
bail!("Multi-value not yet supported, sorry.");
}
let result = to_val_type_vec(&fnc.returns)?.into_iter().next();
let func_type = base_module::FunctionType { params, result };
if let Some(index) = base_function_types.get(&func_type) {
context.type_mapping.insert(src_index, *index);
} else {
bail!("Function type not found in base: {:?}", func_type);
}
}
TypeDef::Instance(_) | TypeDef::Module(_) => {
bail!("Instance and module types are not supported")
}
}
}
Ok(false)
}
fn process_import_section(
context: &mut Context,
mut reader: wasmparser::ImportSectionReader,
) -> Result<bool> {
let mut found_memory = false;
let function_import_map: HashMap<(String, String), (u32, u32)> = context
.base
.function_imports
.iter()
.enumerate()
.map(|(index, (module, name, type_))| {
((module.to_string(), name.clone()), (*type_, index as u32))
})
.collect();
for _ in 0..reader.get_count() {
let import = reader.read()?;
if let Some(field) = import.field {
match import.ty {
ImportSectionEntryType::Memory(ref mem) => {
if import.module != "env" || field != "memory" {
bail!("Wrong import name for memory: {}.{}", import.module, field);
}
if mem.memory64 || mem.shared {
bail!("Bad memory options");
}
if mem.initial > context.base.memory as u64
|| mem.maximum.unwrap_or(0) > context.base.memory as u64
{
bail!("Import memory too large");
}
found_memory = true;
}
ImportSectionEntryType::Function(type_) => {
if let Some((base_type, base_index)) =
function_import_map.get(&(import.module.to_string(), field.to_string()))
{
if let Some(type_) = context.type_mapping.get(&type_) {
if type_ == base_type {
context
.function_mapping
.insert(context.next_function_index, *base_index);
context.next_function_index += 1;
} else {
bail!("Import function {}.{} has wrong type", import.module, field);
}
} else {
bail!("Malformed input (Type {} does not exist)", type_);
}
} else {
bail!(
"Import function {}.{} does not exist in base",
import.module,
field
);
}
}
_ => bail!("Unsupported import type {:?}", import.ty),
}
} else {
bail!("Found import without field: {}", import.module);
}
}
if !found_memory {
bail!("No memory import found");
}
Ok(false)
}
fn to_val_type(type_: &wasmparser::Type) -> Result<ValType> {
use wasmparser::Type::*;
Ok(match *type_ {
I32 => ValType::I32,
I64 => ValType::I64,
F32 => ValType::F32,
F64 => ValType::F64,
_ => bail!("Type {:?} isn't a value type", type_),
})
}
fn to_val_type_vec(types: &[wasmparser::Type]) -> Result<Vec<ValType>> {
types.into_iter().map(to_val_type).collect()
}
#[derive(Debug)]
struct ParsedModule<'a> {
data: &'a [u8],
types: Section<Vec<base_module::FunctionType>>,
imports: Section<ImportSection>,
functions: Section<Vec<u32>>,
exports: Section<Vec<(String, u32)>>,
function_bodies: Vec<wasmparser::FunctionBody<'a>>,
}
impl<'a> ParsedModule<'a> {
fn parse(data: &'a [u8]) -> Result<ParsedModule<'a>> {
let mut parser = wasmparser::Parser::new(0);
let mut type_section = None;
let mut import_section = None;
let mut function_section = None;
let mut export_section = None;
let mut function_bodies = Vec::new();
let mut offset = 0;
loop {
let (consumed, payload) = if let wasmparser::Chunk::Parsed { consumed, payload } =
parser.parse(&data[offset..], true)?
{
(consumed, payload)
} else {
unreachable!();
};
use wasmparser::Payload;
let range = offset..(offset + consumed);
match payload {
Payload::Version { .. } => (),
Payload::TypeSection(reader) => {
type_section = Some(Section::new(range, read_type_section(reader)?));
}
Payload::ImportSection(reader) => {
import_section = Some(Section::new(range, ImportSection::parse(reader)?));
}
Payload::FunctionSection(reader) => {
function_section = Some(Section::new(range, read_function_section(reader)?));
}
Payload::ExportSection(reader) => {
export_section = Some(Section::new(range, read_export_section(reader)?));
}
Payload::CodeSectionStart { .. } => (),
Payload::CodeSectionEntry(body) => function_bodies.push(body),
Payload::CustomSection { .. } => (),
Payload::End => break,
other => bail!("Unsupported section: {:?}", other),
}
dbg!(consumed);
offset += consumed;
}
Ok(ParsedModule {
data,
types: type_section.ok_or_else(|| anyhow!("No type section found"))?,
imports: import_section.ok_or_else(|| anyhow!("No import section found"))?,
functions: function_section.ok_or_else(|| anyhow!("No function section found"))?,
exports: export_section.ok_or_else(|| anyhow!("No export section found"))?,
function_bodies,
})
}
fn pack(self, base: &BaseModule) -> Result<Vec<u8>> {
let mut module = enc::Module::new();
let mut type_map = HashMap::new();
let mut uses_base_types = true;
{
let base_type_map: HashMap<FunctionType, u32> = base
.types
.iter()
.enumerate()
.map(|(idx, type_)| (type_.clone(), idx as u32))
.collect();
for (idx, type_) in self.types.data.iter().enumerate() {
if let Some(base_idx) = base_type_map.get(type_) {
type_map.insert(idx as u32, *base_idx);
} else {
println!("Type {:?} not found in base", type_);
uses_base_types = false;
}
}
if !uses_base_types {
type_map = (0..self.types.data.len() as u32).map(|i| (i, i)).collect();
copy_section(&mut module, &self.data[self.types.range.clone()])?;
}
}
let mut function_map = HashMap::new();
let mut function_count = 0;
if uses_base_types {
if self.imports.data.memory > base.memory {
bail!(
"Trying to import more memory than base ({})",
self.imports.data.memory
);
}
let base_import_map: HashMap<(String, String), (u32, u32)> = base
.function_imports
.iter()
.enumerate()
.map(|(idx, (module, field, type_))| {
((module.to_string(), field.clone()), (*type_, idx as u32))
})
.collect();
for (idx, fnc) in self.imports.data.functions.iter().enumerate() {
if let Some((base_type, base_idx)) =
base_import_map.get(&(fnc.module.clone(), fnc.field.clone()))
{
if type_map.get(&fnc.type_) == Some(base_type) {
function_map.insert(idx as u32, *base_idx);
} else {
bail!(
"Import function {}.{} has incompatible type",
fnc.module,
fnc.field
);
}
} else {
bail!(
"Import function {}.{} not found in base",
fnc.module,
fnc.field
);
}
}
function_count += base.function_imports.len();
} else {
function_map = (0..self.imports.data.functions.len() as u32)
.map(|i| (i, i))
.collect();
copy_section(&mut module, &self.data[self.imports.range.clone()])?;
function_count += self.imports.data.functions.len();
}
// TODO: re-order functions to put tic first
for i in 0..self.functions.data.len() as u32 {
function_map.insert(
self.imports.data.functions.len() as u32 + i,
function_count as u32,
);
function_count += 1;
}
if self.functions.data.len() != base.functions.len()
|| self
.functions
.data
.iter()
.zip(base.functions.iter())
.any(|(a, b)| type_map.get(a) != Some(b))
{
let mut function_section = enc::FunctionSection::new();
for type_ in &self.functions.data {
function_section.function(
*type_map
.get(type_)
.ok_or_else(|| anyhow!("Type index out of range: {}", type_))?,
);
}
module.section(&function_section);
}
{
let mut base_exports = base.exports.clone();
base_exports.sort();
let mut my_exports: Vec<(String, u32)> = self
.exports
.data
.iter()
.map(|(name, func)| (name.clone(), *function_map.get(func).unwrap()))
.collect();
my_exports.sort();
if base_exports
.iter()
.zip(my_exports.iter())
.any(|((n1, t1), (n2, t2))| n1 != n2 && t1 != t2)
{
let mut export_section = enc::ExportSection::new();
for (name, fnc) in my_exports {
export_section.export(&name, enc::Export::Function(fnc));
}
}
}
{
let mut code_section = enc::CodeSection::new();
for function in &self.function_bodies {
code_section.function(&remap_function(function, &type_map, &function_map)?);
}
module.section(&code_section);
}
Ok(module.finish())
}
}
fn copy_section(module: &mut wasm_encoder::Module, data: &[u8]) -> Result<()> {
let mut reader = wasmparser::BinaryReader::new(data);
let id = reader.read_u8()? as u8;
let size = reader.read_var_u32()?;
let data = &data[reader.current_position()..];
assert!(data.len() == size as usize);
module.section(&wasm_encoder::RawSection {
id,
data: &data[reader.current_position()..],
});
Ok(())
}
fn read_type_section(reader: TypeSectionReader) -> Result<Vec<base_module::FunctionType>> {
let mut function_types = vec![];
for type_def in reader {
match type_def? {
wasmparser::TypeDef::Func(fnc) => {
if fnc.returns.len() > 1 {
bail!("Multi-value not supported");
}
let params = to_val_type_vec(&fnc.params)?;
let result = to_val_type_vec(&fnc.returns)?.into_iter().next();
function_types.push(FunctionType { params, result });
}
t => bail!("Unsupported type def {:?}", t),
}
}
Ok(function_types)
}
#[derive(Debug)]
struct Section<T> {
range: std::ops::Range<usize>,
data: T,
}
impl<T> Section<T> {
fn new(range: std::ops::Range<usize>, data: T) -> Section<T> {
Section { range, data }
}
}
#[derive(Debug)]
struct ImportSection {
memory: u32,
functions: Vec<FunctionImport>,
}
impl ImportSection {
fn parse(reader: ImportSectionReader) -> Result<ImportSection> {
let mut memory = 0;
let mut functions = vec![];
for import in reader {
let import = import?;
if let Some(field) = import.field {
match import.ty {
ImportSectionEntryType::Function(type_) => {
functions.push(FunctionImport {
module: import.module.to_string(),
field: field.to_string(),
type_,
});
}
ImportSectionEntryType::Memory(mem) => {
if import.module != "env" || field != "memory" {
bail!(
"Wrong name of memory import {}.{}, should be env.memory",
import.module,
field
);
}
if mem.memory64 || mem.shared {
bail!("Wrong memory import options: {:?}", import.ty);
}
memory = mem.maximum.unwrap_or(mem.initial) as u32;
}
_ => bail!("Unsupported import item {:?}", import.ty),
}
} else {
bail!(
"Found import without field, only module '{}'",
import.module
);
}
}
if memory == 0 {
bail!("No memory import found");
}
Ok(ImportSection { memory, functions })
}
}
#[derive(Debug)]
struct FunctionImport {
module: String,
field: String,
type_: u32,
}
fn read_function_section(reader: FunctionSectionReader) -> Result<Vec<u32>> {
let mut functions = vec![];
for func_type in reader {
functions.push(func_type?);
}
Ok(functions)
}
fn read_export_section(reader: ExportSectionReader) -> Result<Vec<(String, u32)>> {
let mut function_exports = Vec::new();
for export in reader {
let export = export?;
match export.kind {
ExternalKind::Function => {
function_exports.push((export.field.to_string(), export.index));
}
_ => bail!("Only function exports supported, found {:?}", export.kind),
}
}
Ok(function_exports)
}
fn remap_function(
reader: &FunctionBody,
type_map: &HashMap<u32, u32>,
function_map: &HashMap<u32, u32>,
) -> Result<enc::Function> {
let mut locals = Vec::new();
for local in reader.get_locals_reader()? {
let (count, type_) = local?;
locals.push((count, to_val_type(&type_)?));
}
let mut function = enc::Function::new(locals);
let block_type = |ty: wasmparser::TypeOrFuncType| -> Result<enc::BlockType> {
Ok(match ty {
wasmparser::TypeOrFuncType::Type(wasmparser::Type::EmptyBlockType) => {
enc::BlockType::Empty
}
wasmparser::TypeOrFuncType::Type(ty) => enc::BlockType::Result(to_val_type(&ty)?),
wasmparser::TypeOrFuncType::FuncType(ty) => enc::BlockType::FunctionType(
*type_map
.get(&ty)
.ok_or_else(|| anyhow!("Function type index out of range: {}", ty))?,
),
})
};
fn mem(m: wasmparser::MemoryImmediate) -> enc::MemArg {
enc::MemArg {
offset: m.offset,
align: m.align as u32,
memory_index: m.memory,
}
}
use enc::Instruction as En;
use wasmparser::Operator as De;
for op in reader.get_operators_reader()? {
function.instruction(&match op? {
De::Unreachable => En::Unreachable,
De::Nop => En::Nop,
De::Block { ty } => En::Block(block_type(ty)?),
De::Loop { ty } => En::Loop(block_type(ty)?),
De::If { ty } => En::If(block_type(ty)?),
De::Else => En::Else,
De::Try { .. } | De::Catch { .. } | De::Throw { .. } | De::Rethrow { .. } => todo!(),
De::End => En::End,
De::Br { relative_depth } => En::Br(relative_depth),
De::BrIf { relative_depth } => En::BrIf(relative_depth),
De::BrTable { .. } => todo!(),
De::Return => En::Return,
De::Call { function_index } => En::Call(
dbg!(*function_map
.get(&function_index)
.ok_or_else(|| anyhow!("Function index out of range: {}", function_index))?,
)),
De::CallIndirect { .. }
| De::ReturnCall { .. }
| De::ReturnCallIndirect { .. }
| De::Delegate { .. }
| De::CatchAll => todo!(),
De::Drop => En::Drop,
De::Select => En::Select,
De::TypedSelect { .. } => todo!(),
De::LocalGet { local_index } => En::LocalGet(local_index),
De::LocalSet { local_index } => En::LocalSet(local_index),
De::LocalTee { local_index } => En::LocalTee(local_index),
De::GlobalGet { global_index } => En::GlobalGet(global_index),
De::GlobalSet { global_index } => En::GlobalSet(global_index),
De::I32Load { memarg } => En::I32Load(mem(memarg)),
De::I64Load { memarg } => En::I64Load(mem(memarg)),
De::F32Load { memarg } => En::F32Load(mem(memarg)),
De::F64Load { memarg } => En::F64Load(mem(memarg)),
De::I32Load8S { memarg } => En::I32Load8_S(mem(memarg)),
De::I32Load8U { memarg } => En::I32Load8_U(mem(memarg)),
De::I32Load16S { memarg } => En::I32Load16_S(mem(memarg)),
De::I32Load16U { memarg } => En::I32Load16_U(mem(memarg)),
De::I64Load8S { memarg } => En::I64Load8_S(mem(memarg)),
De::I64Load8U { memarg } => En::I64Load8_U(mem(memarg)),
De::I64Load16S { memarg } => En::I64Load16_S(mem(memarg)),
De::I64Load16U { memarg } => En::I64Load16_U(mem(memarg)),
De::I64Load32S { memarg } => En::I64Load32_S(mem(memarg)),
De::I64Load32U { memarg } => En::I64Load32_U(mem(memarg)),
De::I32Store { memarg } => En::I32Store(mem(memarg)),
De::I64Store { memarg } => En::I64Store(mem(memarg)),
De::F32Store { memarg } => En::F32Store(mem(memarg)),
De::F64Store { memarg } => En::F64Store(mem(memarg)),
De::I32Store8 { memarg } => En::I32Store8(mem(memarg)),
De::I32Store16 { memarg } => En::I32Store16(mem(memarg)),
De::I64Store8 { memarg } => En::I64Store8(mem(memarg)),
De::I64Store16 { memarg } => En::I64Store16(mem(memarg)),
De::I64Store32 { memarg } => En::I64Store32(mem(memarg)),
De::MemorySize { mem, mem_byte: _ } => En::MemorySize(mem),
De::MemoryGrow { mem, mem_byte: _ } => En::MemoryGrow(mem),
De::I32Const { value } => En::I32Const(value),
De::I64Const { value } => En::I64Const(value),
De::F32Const { value } => En::F32Const(f32::from_bits(value.bits())),
De::F64Const { value } => En::F64Const(f64::from_bits(value.bits())),
De::RefNull { .. } | De::RefIsNull { .. } | De::RefFunc { .. } => todo!(),
De::I32Eqz => En::I32Eqz,
De::I32Eq => En::I32Eq,
De::I32Ne => En::I32Neq,
De::I32LtS => En::I32LtS,
De::I32LtU => En::I32LtU,
De::I32GtS => En::I32GtS,
De::I32GtU => En::I32GtU,
De::I32LeS => En::I32LeS,
De::I32LeU => En::I32LeU,
De::I32GeS => En::I32GeS,
De::I32GeU => En::I32GeU,
De::I64Eqz => En::I64Eqz,
De::I64Eq => En::I64Eq,
De::I64Ne => En::I64Neq,
De::I64LtS => En::I64LtS,
De::I64LtU => En::I64LtU,
De::I64GtS => En::I64GtS,
De::I64GtU => En::I64GtU,
De::I64LeS => En::I64LeS,
De::I64LeU => En::I64LeU,
De::I64GeS => En::I64GeS,
De::I64GeU => En::I64GeU,
De::F32Eq => En::F32Eq,
De::F32Ne => En::F32Neq,
De::F32Lt => En::F32Lt,
De::F32Gt => En::F32Gt,
De::F32Le => En::F32Le,
De::F32Ge => En::F32Ge,
De::F64Eq => En::F64Eq,
De::F64Ne => En::F64Neq,
De::F64Lt => En::F64Lt,
De::F64Gt => En::F64Gt,
De::F64Le => En::F64Le,
De::F64Ge => En::F64Ge,
De::I32Clz => En::I32Clz,
De::I32Ctz => En::I32Ctz,
De::I32Popcnt => En::I32Popcnt,
De::I32Add => En::I32Add,
De::I32Sub => En::I32Sub,
De::I32Mul => En::I32Mul,
De::I32DivS => En::I32DivS,
De::I32DivU => En::I32DivU,
De::I32RemS => En::I32RemS,
De::I32RemU => En::I32RemU,
De::I32And => En::I32And,
De::I32Or => En::I32Or,
De::I32Xor => En::I32Xor,
De::I32Shl => En::I32Shl,
De::I32ShrS => En::I32ShrS,
De::I32ShrU => En::I32ShrU,
De::I32Rotl => En::I32Rotl,
De::I32Rotr => En::I32Rotr,
De::I64Clz => En::I64Clz,
De::I64Ctz => En::I64Ctz,
De::I64Popcnt => En::I64Popcnt,
De::I64Add => En::I64Add,
De::I64Sub => En::I64Sub,
De::I64Mul => En::I64Mul,
De::I64DivS => En::I64DivS,
De::I64DivU => En::I64DivU,
De::I64RemS => En::I64RemS,
De::I64RemU => En::I64RemU,
De::I64And => En::I64And,
De::I64Or => En::I64Or,
De::I64Xor => En::I64Xor,
De::I64Shl => En::I64Shl,
De::I64ShrS => En::I64ShrS,
De::I64ShrU => En::I64ShrU,
De::I64Rotl => En::I64Rotl,
De::I64Rotr => En::I64Rotr,
De::F32Abs => En::F32Abs,
De::F32Neg => En::F32Neg,
De::F32Ceil => En::F32Ceil,
De::F32Floor => En::F32Floor,
De::F32Trunc => En::F32Trunc,
De::F32Nearest => En::F32Nearest,
De::F32Sqrt => En::F32Sqrt,
De::F32Add => En::F32Add,
De::F32Sub => En::F32Sub,
De::F32Mul => En::F32Mul,
De::F32Div => En::F32Div,
De::F32Min => En::F32Min,
De::F32Max => En::F32Max,
De::F32Copysign => En::F32Copysign,
De::F64Abs => En::F64Abs,
De::F64Neg => En::F64Neg,
De::F64Ceil => En::F64Ceil,
De::F64Floor => En::F64Floor,
De::F64Trunc => En::F64Trunc,
De::F64Nearest => En::F64Nearest,
De::F64Sqrt => En::F64Sqrt,
De::F64Add => En::F64Add,
De::F64Sub => En::F64Sub,
De::F64Mul => En::F64Mul,
De::F64Div => En::F64Div,
De::F64Min => En::F64Min,
De::F64Max => En::F64Max,
De::F64Copysign => En::F64Copysign,
De::I32WrapI64 => En::I32WrapI64,
De::I32TruncF32S => En::I32TruncF32S,
De::I32TruncF32U => En::I32TruncF32U,
De::I32TruncF64S => En::I32TruncF64S,
De::I32TruncF64U => En::I32TruncF64U,
De::I64ExtendI32S => En::I64ExtendI32S,
De::I64ExtendI32U => En::I64ExtendI32U,
De::I64TruncF32S => En::I64TruncF32S,
De::I64TruncF32U => En::I64TruncF32U,
De::I64TruncF64S => En::I64TruncF64S,
De::I64TruncF64U => En::I64TruncF64U,
De::F32ConvertI32S => En::F32ConvertI32S,
De::F32ConvertI32U => En::F32ConvertI32U,
De::F32ConvertI64S => En::F32ConvertI64S,
De::F32ConvertI64U => En::F32ConvertI64U,
De::F32DemoteF64 => En::F32DemoteF64,
De::F64ConvertI32S => En::F64ConvertI32S,
De::F64ConvertI32U => En::F64ConvertI32U,
De::F64ConvertI64S => En::F64ConvertI64S,
De::F64ConvertI64U => En::F64ConvertI64U,
De::F64PromoteF32 => En::F64PromoteF32,
De::I32ReinterpretF32 => En::I32ReinterpretF32,
De::I64ReinterpretF64 => En::I64ReinterpretF64,
De::F32ReinterpretI32 => En::F32ReinterpretI32,
De::F64ReinterpretI64 => En::F64ReinterpretI64,
De::I32Extend8S => En::I32Extend8S,
De::I32Extend16S => En::I32Extend16S,
De::I64Extend8S => En::I64Extend8S,
De::I64Extend16S => En::I64Extend16S,
De::I64Extend32S => En::I64Extend32S,
De::I32TruncSatF32S => En::I32TruncSatF32S,
De::I32TruncSatF32U => En::I32TruncSatF32U,
De::I32TruncSatF64S => En::I32TruncSatF64S,
De::I32TruncSatF64U => En::I32TruncSatF64U,
De::I64TruncSatF32S => En::I64TruncSatF32S,
De::I64TruncSatF32U => En::I64TruncSatF32U,
De::I64TruncSatF64S => En::I64TruncSatF64S,
De::I64TruncSatF64U => En::I64TruncSatF64U,
other => bail!("Unsupported instruction {:?}", other),
});
}
Ok(function)
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
import loaderUrl from "data-url:../../platform/loader.wasm";
import baseUrl from "data-url:../../platform/base.wasm";
import baseUrl from "data-url:../../uw8-tool/base1.wasm";
async function loadWasm(url, imports) {
let wasm_module = await (await fetch(url)).arrayBuffer();
@@ -82,13 +82,18 @@ async function runModule(data) {
env: {
memory: new WebAssembly.Memory({ initial: 4, maximum: 4 }),
},
math: {}
math: {},
uw8: {}
};
for(let n of ['acos','asin','atan','atan2','cos','exp','log','sin','tan']) {
for(let n of ['acos','asin','atan','atan2','cos','exp','log','sin','tan','pow']) {
importObject.math[n] = Math[n];
}
for(let i = 9; i < 64; ++i) {
importObject.uw8['reserved' + i] = () => {};
}
let instance = new WebAssembly.Instance(await WebAssembly.compile(data), importObject);
let buffer = imageData.data;