minor fixes
This commit is contained in:
parent
e462e0aaf1
commit
853bf477cc
2
.cargo/config
Normal file
2
.cargo/config
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target-dir = "build"
|
3
.travis-run-jshint.sh
Executable file
3
.travis-run-jshint.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
make jshint
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
make jshint rustfmt clang-tidy
|
|
@ -3,7 +3,7 @@ name = "v86oxide"
|
|||
version = "0.1.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.6.2"
|
||||
|
||||
[lib]
|
||||
|
@ -18,4 +18,3 @@ panic = "abort"
|
|||
lto = true
|
||||
incremental = false
|
||||
panic = "abort"
|
||||
|
||||
|
|
3
Makefile
3
Makefile
|
@ -106,7 +106,6 @@ CC_FLAGS=\
|
|||
|
||||
CARGO_FLAGS=\
|
||||
--target wasm32-unknown-unknown \
|
||||
--target-dir build/ \
|
||||
-- -Clink-args="--import-memory"
|
||||
|
||||
CORE_FILES=const.js config.js io.js main.js lib.js coverage.js ide.js pci.js floppy.js \
|
||||
|
@ -319,7 +318,7 @@ devices-test: all-debug
|
|||
./tests/devices/virtio_9p.js
|
||||
|
||||
rust-test:
|
||||
env RUST_BACKTRACE=full RUST_TEST_THREADS=1 cargo test --target-dir build -- --nocapture
|
||||
env RUST_BACKTRACE=full RUST_TEST_THREADS=1 cargo test -- --nocapture
|
||||
./tests/rust/verify-wasmgen-dummy-output.js
|
||||
|
||||
covreport:
|
||||
|
|
|
@ -14,4 +14,3 @@ RUN \
|
|||
rustup toolchain install nightly && \
|
||||
rustup target add wasm32-unknown-unknown --toolchain nightly && \
|
||||
rustup component add rustfmt-preview --toolchain nightly
|
||||
|
||||
|
|
|
@ -9,4 +9,3 @@ mod dbg;
|
|||
mod util;
|
||||
|
||||
pub mod wasmgen;
|
||||
|
||||
|
|
|
@ -165,6 +165,7 @@ pub fn _log_to_js_console<T: ToString>(s: T) {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::util::*;
|
||||
use quickcheck::TestResult;
|
||||
|
||||
#[test]
|
||||
fn packed_strs() {
|
||||
|
@ -176,10 +177,13 @@ mod tests {
|
|||
}
|
||||
|
||||
quickcheck! {
|
||||
fn prop(xs: Vec<u8>) -> bool {
|
||||
if xs.len() > 24 || xs.contains(&0) { return true; }
|
||||
let xs = String::from_utf8(xs).expect("get string");
|
||||
xs == unpack_str(pack_str(&xs))
|
||||
fn prop(xs: Vec<u8>) -> TestResult {
|
||||
if xs.len() > 24 || xs.contains(&0) { return TestResult::discard(); }
|
||||
let xs = match String::from_utf8(xs) {
|
||||
Ok(x) => x,
|
||||
Err(_) => { return TestResult::discard(); },
|
||||
};
|
||||
TestResult::from_bool(xs == unpack_str(pack_str(&xs)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use wasmgen::module_init::get_module;
|
|||
|
||||
#[no_mangle]
|
||||
pub fn wg_get_code_section() -> *mut Vec<u8> {
|
||||
&mut get_module().cs
|
||||
&mut get_module().code_section
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -63,7 +63,7 @@ mod tests {
|
|||
fn c_api_test() {
|
||||
wg_setup();
|
||||
let m = get_module();
|
||||
let cs = &mut get_module().cs;
|
||||
let cs = &mut get_module().code_section;
|
||||
let instruction_body = &mut get_module().instruction_body;
|
||||
|
||||
wg_call_fn(cs, m.get_fn_idx(pack_str("foo"), FN0_TYPE_INDEX));
|
||||
|
@ -85,7 +85,7 @@ mod tests {
|
|||
dbg_log!("op_ptr: {:?}, op_len: {:?}", op_ptr, op_len);
|
||||
|
||||
let mut f = File::create("build/wg_dummy_output.wasm").expect("creating wg_dummy_output.wasm");
|
||||
f.write_all(&get_module().op).expect("write wg_dummy_output.wasm");
|
||||
f.write_all(&get_module().output).expect("write wg_dummy_output.wasm");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ pub fn get_module<'a>() -> &'a mut WasmBuilder {
|
|||
}
|
||||
|
||||
pub struct WasmBuilder {
|
||||
pub op: Vec<u8>,
|
||||
pub cs: Vec<u8>,
|
||||
pub output: Vec<u8>,
|
||||
pub code_section: Vec<u8>,
|
||||
pub instruction_body: Vec<u8>,
|
||||
|
||||
idx_import_table_size: usize, // for rewriting once finished
|
||||
|
@ -63,8 +63,8 @@ pub struct WasmBuilder {
|
|||
impl WasmBuilder {
|
||||
pub fn new() -> Self {
|
||||
WasmBuilder {
|
||||
op: Vec::with_capacity(256),
|
||||
cs: Vec::with_capacity(256),
|
||||
output: Vec::with_capacity(256),
|
||||
code_section: Vec::with_capacity(256),
|
||||
instruction_body: Vec::with_capacity(256),
|
||||
|
||||
idx_import_table_size: 0,
|
||||
|
@ -79,23 +79,23 @@ impl WasmBuilder {
|
|||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.op.extend("\0asm".as_bytes());
|
||||
self.output.extend("\0asm".as_bytes());
|
||||
|
||||
// wasm version in leb128, 4 bytes
|
||||
self.op.push(op::WASM_VERSION); self.op.push(0); self.op.push(0); self.op.push(0);
|
||||
self.output.push(op::WASM_VERSION); self.output.push(0); self.output.push(0); self.output.push(0);
|
||||
|
||||
self.write_type_section();
|
||||
self.write_import_section_preamble();
|
||||
|
||||
// store state of current pointers etc. so we can reset them later
|
||||
self.initial_static_size = self.op.len();
|
||||
self.initial_static_size = self.output.len();
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.op.drain(self.initial_static_size..);
|
||||
self.output.drain(self.initial_static_size..);
|
||||
self.set_import_table_size(2);
|
||||
self.set_import_count(0);
|
||||
self.cs.clear();
|
||||
self.code_section.clear();
|
||||
self.instruction_body.clear();
|
||||
}
|
||||
|
||||
|
@ -105,96 +105,96 @@ impl WasmBuilder {
|
|||
self.write_export_section();
|
||||
|
||||
// write code section preamble
|
||||
self.op.push(op::SC_CODE);
|
||||
self.output.push(op::SC_CODE);
|
||||
|
||||
let idx_code_section_size = self.op.len(); // we will write to this location later
|
||||
self.op.push(0); self.op.push(0); // write temp val for now using 4 bytes
|
||||
self.op.push(0); self.op.push(0);
|
||||
let idx_code_section_size = self.output.len(); // we will write to this location later
|
||||
self.output.push(0); self.output.push(0); // write temp val for now using 4 bytes
|
||||
self.output.push(0); self.output.push(0);
|
||||
|
||||
self.op.push(1); // number of function bodies: just 1
|
||||
self.output.push(1); // number of function bodies: just 1
|
||||
|
||||
// same as above but for body size of the function
|
||||
let idx_fn_body_size = self.op.len();
|
||||
self.op.push(0); self.op.push(0);
|
||||
self.op.push(0); self.op.push(0);
|
||||
let idx_fn_body_size = self.output.len();
|
||||
self.output.push(0); self.output.push(0);
|
||||
self.output.push(0); self.output.push(0);
|
||||
|
||||
self.op.push(1); // count of local blocks
|
||||
self.output.push(1); // count of local blocks
|
||||
dbg_assert!(no_of_locals_i32 < 128);
|
||||
self.op.push(no_of_locals_i32); self.op.push(op::TYPE_I32);
|
||||
self.output.push(no_of_locals_i32); self.output.push(op::TYPE_I32);
|
||||
|
||||
self.op.append(&mut self.cs);
|
||||
self.output.append(&mut self.code_section);
|
||||
|
||||
self.op.push(op::OP_END);
|
||||
self.output.push(op::OP_END);
|
||||
|
||||
// write the actual sizes to the pointer locations stored above. We subtract 4 from the actual
|
||||
// value because the ptr itself points to four bytes
|
||||
let fn_body_size = (self.op.len() - idx_fn_body_size - 4) as u32;
|
||||
write_fixed_leb32_at_idx(&mut self.op, idx_fn_body_size, fn_body_size);
|
||||
let fn_body_size = (self.output.len() - idx_fn_body_size - 4) as u32;
|
||||
write_fixed_leb32_at_idx(&mut self.output, idx_fn_body_size, fn_body_size);
|
||||
|
||||
let code_section_size = (self.op.len() - idx_code_section_size - 4) as u32;
|
||||
write_fixed_leb32_at_idx(&mut self.op, idx_code_section_size, code_section_size);
|
||||
let code_section_size = (self.output.len() - idx_code_section_size - 4) as u32;
|
||||
write_fixed_leb32_at_idx(&mut self.output, idx_code_section_size, code_section_size);
|
||||
|
||||
self.op.len()
|
||||
self.output.len()
|
||||
}
|
||||
|
||||
pub fn write_type_section(&mut self) {
|
||||
self.op.push(op::SC_TYPE);
|
||||
self.output.push(op::SC_TYPE);
|
||||
|
||||
let idx_section_size = self.op.len();
|
||||
self.op.push(0);
|
||||
let idx_section_size = self.output.len();
|
||||
self.output.push(0);
|
||||
|
||||
self.op.push(NR_FN_TYPE_INDEXES); // number of type descriptors
|
||||
self.output.push(NR_FN_TYPE_INDEXES); // number of type descriptors
|
||||
|
||||
// FN0
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(0); // no args
|
||||
self.op.push(0); // no return val
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(0); // no args
|
||||
self.output.push(0); // no return val
|
||||
|
||||
// FN1
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(1);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(0);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(1);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(0);
|
||||
|
||||
// FN2
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(2);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(0);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(2);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(0);
|
||||
|
||||
// FN3
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(3);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(0);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(3);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(0);
|
||||
|
||||
// FN0_RET
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(0);
|
||||
self.op.push(1);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(0);
|
||||
self.output.push(1);
|
||||
self.output.push(op::TYPE_I32);
|
||||
|
||||
// FN1_RET
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(1);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(1);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(1);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(1);
|
||||
self.output.push(op::TYPE_I32);
|
||||
|
||||
// FN2_RET
|
||||
self.op.push(op::TYPE_FUNC);
|
||||
self.op.push(2);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.op.push(1);
|
||||
self.op.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_FUNC);
|
||||
self.output.push(2);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(op::TYPE_I32);
|
||||
self.output.push(1);
|
||||
self.output.push(op::TYPE_I32);
|
||||
|
||||
let new_len = self.op.len();
|
||||
let new_len = self.output.len();
|
||||
let size = (new_len - 1) - idx_section_size;
|
||||
self.op[idx_section_size] = size.safe_to_u8();
|
||||
self.output[idx_section_size] = size.safe_to_u8();
|
||||
}
|
||||
|
||||
/// Goes over the import block to find index of an import entry by function name
|
||||
|
@ -204,9 +204,9 @@ impl WasmBuilder {
|
|||
for i in 0..self.import_count {
|
||||
offset += 1; // skip length of module name
|
||||
offset += 1; // skip module name itself
|
||||
let len = self.op[offset] as usize;
|
||||
let len = self.output[offset] as usize;
|
||||
offset += 1;
|
||||
let name = self.op.get(offset..(offset + len)).expect("get function name");
|
||||
let name = self.output.get(offset..(offset + len)).expect("get function name");
|
||||
if name == fn_name.as_bytes() {
|
||||
return Some(i);
|
||||
}
|
||||
|
@ -221,39 +221,39 @@ impl WasmBuilder {
|
|||
dbg_assert!(count < 0x4000);
|
||||
self.import_count = count;
|
||||
let idx_import_count = self.idx_import_count;
|
||||
write_fixed_leb16_at_idx(&mut self.op, idx_import_count, count);
|
||||
write_fixed_leb16_at_idx(&mut self.output, idx_import_count, count);
|
||||
}
|
||||
|
||||
pub fn set_import_table_size(&mut self, size: usize) {
|
||||
dbg_assert!(size < 0x4000);
|
||||
self.import_table_size = size;
|
||||
let idx_import_table_size = self.idx_import_table_size;
|
||||
write_fixed_leb16_at_idx(&mut self.op, idx_import_table_size, size.safe_to_u16());
|
||||
write_fixed_leb16_at_idx(&mut self.output, idx_import_table_size, size.safe_to_u16());
|
||||
}
|
||||
|
||||
pub fn write_import_section_preamble(&mut self) {
|
||||
self.op.push(op::SC_IMPORT);
|
||||
self.output.push(op::SC_IMPORT);
|
||||
|
||||
self.idx_import_table_size = self.op.len();
|
||||
self.op.push(1 | 0b10000000); self.op.push(2); // 2 in 2 byte leb
|
||||
self.idx_import_table_size = self.output.len();
|
||||
self.output.push(1 | 0b10000000); self.output.push(2); // 2 in 2 byte leb
|
||||
|
||||
self.idx_import_count = self.op.len();
|
||||
self.op.push(1 | 0b10000000); self.op.push(0); // 0 in 2 byte leb
|
||||
self.idx_import_count = self.output.len();
|
||||
self.output.push(1 | 0b10000000); self.output.push(0); // 0 in 2 byte leb
|
||||
|
||||
// here after starts the actual list of imports
|
||||
self.idx_import_entries = self.op.len();
|
||||
self.idx_import_entries = self.output.len();
|
||||
}
|
||||
|
||||
pub fn write_memory_import(&mut self) {
|
||||
self.op.push(1);
|
||||
self.op.push('e' as u8);
|
||||
self.op.push(1);
|
||||
self.op.push('m' as u8);
|
||||
self.output.push(1);
|
||||
self.output.push('e' as u8);
|
||||
self.output.push(1);
|
||||
self.output.push('m' as u8);
|
||||
|
||||
self.op.push(op::EXT_MEMORY);
|
||||
self.output.push(op::EXT_MEMORY);
|
||||
|
||||
self.op.push(0); // memory flag, 0 for no maximum memory limit present
|
||||
write_leb_u32(&mut self.op, 256); // initial memory length of 256 pages, takes 2 bytes in leb128
|
||||
self.output.push(0); // memory flag, 0 for no maximum memory limit present
|
||||
write_leb_u32(&mut self.output, 256); // initial memory length of 256 pages, takes 2 bytes in leb128
|
||||
|
||||
let new_import_count = self.import_count + 1;
|
||||
self.set_import_count(new_import_count);
|
||||
|
@ -263,13 +263,13 @@ impl WasmBuilder {
|
|||
}
|
||||
|
||||
pub fn write_import_entry(&mut self, fn_name: PackedStr, type_index: u8) -> u16 {
|
||||
self.op.push(1); // length of module name
|
||||
self.op.push('e' as u8); // module name
|
||||
self.output.push(1); // length of module name
|
||||
self.output.push('e' as u8); // module name
|
||||
let fn_name = unpack_str(fn_name);
|
||||
self.op.push(fn_name.len().safe_to_u8());
|
||||
self.op.extend(fn_name.as_bytes());
|
||||
self.op.push(op::EXT_FUNCTION);
|
||||
self.op.push(type_index);
|
||||
self.output.push(fn_name.len().safe_to_u8());
|
||||
self.output.extend(fn_name.as_bytes());
|
||||
self.output.push(op::EXT_FUNCTION);
|
||||
self.output.push(type_index);
|
||||
|
||||
let new_import_count = self.import_count + 1;
|
||||
self.set_import_count(new_import_count);
|
||||
|
@ -281,29 +281,29 @@ impl WasmBuilder {
|
|||
}
|
||||
|
||||
pub fn write_function_section(&mut self, count: u8) {
|
||||
self.op.push(op::SC_FUNCTION);
|
||||
self.op.push(1 + count); // length of this section
|
||||
self.op.push(count); // count of signature indices
|
||||
self.output.push(op::SC_FUNCTION);
|
||||
self.output.push(1 + count); // length of this section
|
||||
self.output.push(count); // count of signature indices
|
||||
for _ in 0..count {
|
||||
self.op.push(FN1_TYPE_INDEX);
|
||||
self.output.push(FN1_TYPE_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_export_section(&mut self) {
|
||||
self.op.push(op::SC_EXPORT);
|
||||
self.op.push(1 + 1 + 1 + 1 + 2); // size of this section
|
||||
self.op.push(1); // count of table: just one function exported
|
||||
self.output.push(op::SC_EXPORT);
|
||||
self.output.push(1 + 1 + 1 + 1 + 2); // size of this section
|
||||
self.output.push(1); // count of table: just one function exported
|
||||
|
||||
self.op.push(1); // length of exported function name
|
||||
self.op.push('f' as u8); // function name
|
||||
self.op.push(op::EXT_FUNCTION);
|
||||
self.output.push(1); // length of exported function name
|
||||
self.output.push('f' as u8); // function name
|
||||
self.output.push(op::EXT_FUNCTION);
|
||||
|
||||
// index of the exported function
|
||||
// function space starts with imports. index of last import is import count - 1
|
||||
// the last import however is a memory, so we subtract one from that
|
||||
let next_op_idx = self.op.len();
|
||||
self.op.push(0); self.op.push(0); // add 2 bytes for writing 16 byte val
|
||||
write_fixed_leb16_at_idx(&mut self.op, next_op_idx, self.import_count - 1);
|
||||
let next_op_idx = self.output.len();
|
||||
self.output.push(0); self.output.push(0); // add 2 bytes for writing 16 byte val
|
||||
write_fixed_leb16_at_idx(&mut self.output, next_op_idx, self.import_count - 1);
|
||||
}
|
||||
|
||||
pub fn get_fn_idx(&mut self, fn_name: PackedStr, type_index: u8) -> u16 {
|
||||
|
@ -319,15 +319,15 @@ impl WasmBuilder {
|
|||
}
|
||||
|
||||
pub fn get_op_ptr(&self) -> *const u8 {
|
||||
self.op.as_ptr()
|
||||
self.output.as_ptr()
|
||||
}
|
||||
|
||||
pub fn get_op_len(&self) -> usize {
|
||||
self.op.len()
|
||||
self.output.len()
|
||||
}
|
||||
|
||||
pub fn commit_instruction_body_cs(&mut self) {
|
||||
self.cs.append(&mut self.instruction_body);
|
||||
self.code_section.append(&mut self.instruction_body);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
process.on("unhandledRejection", exn => { throw exn; });
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const DUMMY_MODULE_PATH = path.resolve(__dirname, '../../build/wg_dummy_output.wasm');
|
||||
const DUMMY_MODULE_PATH = path.resolve(__dirname, "../../build/wg_dummy_output.wasm");
|
||||
const dummy_module = fs.readFileSync(DUMMY_MODULE_PATH);
|
||||
|
||||
const wm = new WebAssembly.Module(dummy_module);
|
||||
|
@ -26,9 +26,8 @@ function foo(arg) {
|
|||
foo_recd_arg = arg;
|
||||
}
|
||||
|
||||
const i = new WebAssembly.Instance(wm, { 'e': { m: mem, baz, foo } });
|
||||
const i = new WebAssembly.Instance(wm, { "e": { m: mem, baz, foo } });
|
||||
i.exports.f();
|
||||
|
||||
console.assert(baz_recd_arg === 2, `baz returned: "${baz_recd_arg}"`);
|
||||
console.assert(foo_recd_arg === 456, `foo returned: "${foo_recd_arg}"`);
|
||||
|
||||
|
|
Loading…
Reference in a new issue