mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 22:25:40 +00:00
Merge pull request #20 from WAFoundation/feature/add-emscripten-compatible-apis
Add emscripten compatible apis
This commit is contained in:
commit
cf22c6f1b1
7
Makefile
7
Makefile
@ -1,3 +1,8 @@
|
||||
ifeq (test, $(firstword $(MAKECMDGOALS)))
|
||||
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
|
||||
$(eval $(runargs):;@true)
|
||||
endif
|
||||
|
||||
.PHONY: spectests clean build install
|
||||
|
||||
# This will re-generate the Rust test files based on spectests/*.wast
|
||||
@ -14,7 +19,7 @@ install:
|
||||
cargo install --path .
|
||||
|
||||
test:
|
||||
cargo test -- --test-threads=1
|
||||
cargo test -- --test-threads=1 $(runargs)
|
||||
|
||||
release:
|
||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||
|
31
examples/em_abort.wat
Normal file
31
examples/em_abort.wat
Normal file
@ -0,0 +1,31 @@
|
||||
(module
|
||||
(type $t1 (func (param i32 i32) (result i32)))
|
||||
(type $t2 (func (param i32)))
|
||||
(type $t3 (func ))
|
||||
(func $printf (import "env" "printf") (type $t1))
|
||||
(func $abort (import "env" "abort") (type $t2))
|
||||
(func $_abort (import "env" "_abort") (type $t3))
|
||||
(func $abort_on_cannot_grow_memory (import "env" "abortOnCannotGrowMemory") (type $t3))
|
||||
(memory 1)
|
||||
(data (i32.const 0) ">>> First\00")
|
||||
(data (i32.const 24) ">>> Second\00")
|
||||
(data (i32.const 48) "Aborting abruptly!\00")
|
||||
(func $main (export "main")
|
||||
;; print ">>> First"
|
||||
(call $printf (i32.const 0) (i32.const 0))
|
||||
(drop)
|
||||
|
||||
;; aborts
|
||||
(call $_abort) ;; ()
|
||||
|
||||
;; aborts
|
||||
(call $abort_on_cannot_grow_memory) ;; ()
|
||||
|
||||
;; aborts
|
||||
(call $abort (i32.const 48)) ;; (message: u32)
|
||||
|
||||
;; print ">>> Second"
|
||||
(call $printf (i32.const 24) (i32.const 0))
|
||||
(drop)
|
||||
)
|
||||
)
|
27
examples/em_exit.wat
Normal file
27
examples/em_exit.wat
Normal file
@ -0,0 +1,27 @@
|
||||
(module
|
||||
(type $t1 (func (param i32)))
|
||||
(func $putchar (import "env" "putchar") (type $t1))
|
||||
(func $sys_exit (import "env" "___syscall1") (type $t1))
|
||||
(memory 1)
|
||||
(func $main (export "main")
|
||||
;; print "Hello"
|
||||
(call $putchar (i32.const 72))
|
||||
(call $putchar (i32.const 101))
|
||||
(call $putchar (i32.const 108))
|
||||
(call $putchar (i32.const 108))
|
||||
(call $putchar (i32.const 111))
|
||||
(call $putchar (i32.const 32))
|
||||
|
||||
;; exit abruptly
|
||||
(call $sys_exit (i32.const 255)) ;; (status: c_int) -> c_int
|
||||
|
||||
;; print " World!"
|
||||
(call $putchar (i32.const 87))
|
||||
(call $putchar (i32.const 111))
|
||||
(call $putchar (i32.const 114))
|
||||
(call $putchar (i32.const 108))
|
||||
(call $putchar (i32.const 100))
|
||||
(call $putchar (i32.const 33))
|
||||
(call $putchar (i32.const 10))
|
||||
)
|
||||
)
|
43
examples/em_read_file.wat
Normal file
43
examples/em_read_file.wat
Normal file
@ -0,0 +1,43 @@
|
||||
(module
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32 i32) (result i32)))
|
||||
(type $t3 (func (param i32) (result i32)))
|
||||
(type $t4 (func (param i32 i32) (result i32)))
|
||||
(func $putchar (import "env" "putchar") (type $t1))
|
||||
(func $printf (import "env" "printf") (type $t4))
|
||||
(func $sys_open (import "env" "___syscall5") (type $t2))
|
||||
(func $sys_read (import "env" "___syscall3") (type $t2))
|
||||
(func $sys_close (import "env" "___syscall6") (type $t3))
|
||||
(memory 1)
|
||||
(data $filename (i32.const 0) "/Users/xxxx/Desktop/hello.txt\00")
|
||||
(func $main (export "main")
|
||||
;; declare variables
|
||||
(local $string_buf_addr i32)
|
||||
(local $string_buf_len i32)
|
||||
(local $file_access_flag i32)
|
||||
(local $file_permission_flag i32)
|
||||
(local $file_descriptor i32)
|
||||
|
||||
;; set variables
|
||||
(set_local $string_buf_addr (i32.const 72)) ;; string_buf_addr at offset 72
|
||||
(set_local $string_buf_len (i32.const 10)) ;; string_buf_len is 5
|
||||
(set_local $file_access_flag (i32.const 02)) ;; file_access_flag has O_RDWR permission
|
||||
(set_local $file_permission_flag (i32.const 700)) ;; file_permission_flag has S_IRWXU permission
|
||||
|
||||
;; open file
|
||||
(call $sys_open (i32.const 0) (get_local $file_access_flag) (get_local $file_permission_flag)) ;; (path: u32, flags: c_int, mode: c_int) -> c_int
|
||||
(set_local $file_descriptor) ;; set file_descriptor to the value returned by sys_open
|
||||
|
||||
;; read file content
|
||||
(call $sys_read (get_local $file_descriptor) (get_local $string_buf_addr) (get_local $string_buf_len)) ;; (fd: c_int, buf: u32, count: size_t) -> ssize_t
|
||||
(drop) ;; ignoring errors
|
||||
|
||||
;; close file
|
||||
(call $sys_close (get_local $file_descriptor)) ;; (fd: c_int) -> c_int
|
||||
(drop) ;; ignoring errors
|
||||
|
||||
;; print file content
|
||||
(call $printf (get_local $string_buf_addr) (i32.const 0))
|
||||
(drop) ;; ignoring errors
|
||||
)
|
||||
)
|
513
src/apis/emscripten/README.md
Normal file
513
src/apis/emscripten/README.md
Normal file
@ -0,0 +1,513 @@
|
||||
## HOST APIS
|
||||
|
||||
#### EMSCRIPTEN APIS
|
||||
|
||||
###### PROCESS
|
||||
|
||||
- **\_abort** ✅ [:top:](#host-apis)
|
||||
```rust
|
||||
fn _abort()
|
||||
```
|
||||
- **abort** ✅ 🔥 [:top:](#host-apis)
|
||||
```rust
|
||||
fn abort(message: u32, instance: &mut Instance)
|
||||
```
|
||||
- **abort_on_cannot_grow_memory** ✅ [:top:](#host-apis)
|
||||
```rust
|
||||
fn abort_on_cannot_grow_memory()
|
||||
```
|
||||
|
||||
###### TIMING
|
||||
|
||||
- **\_clock_gettime** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
|
||||
###### ENVIRONMENT
|
||||
|
||||
- **\_getenv** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
|
||||
###### THREAD
|
||||
|
||||
- **\_pthread_getspecific** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **\_pthread_key_create** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **\_pthread_setspecific** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **\_unsetenv** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **\_\_\_lock** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **\_\_\_unlock** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
|
||||
###### MEMORY
|
||||
|
||||
- **\_emscripten_memcpy_big** ✅ 🔥 [:top:](#host-apis)
|
||||
```rust
|
||||
fn _emscripten_memcpy_big(dest: u32, src: u32, len: u32, instance: &mut Instance) -> u32
|
||||
```
|
||||
- **enlarge_memory** ✅ [:top:](#host-apis)
|
||||
```rust
|
||||
fn enlarge_memory()
|
||||
```
|
||||
- **get_total_memory** ✅ [:top:](#host-apis)
|
||||
```rust
|
||||
fn get_total_memory(instance: &mut Instance) -> u32
|
||||
```
|
||||
|
||||
###### TIMING
|
||||
|
||||
- **\_clock_gettime** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
|
||||
###### STATUS
|
||||
|
||||
- **\_\_\_set_err_no** [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### EMSCRIPTEN SYSCALLS
|
||||
|
||||
- **access** (\_\_\_syscall33) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **acct** (\_\_\_syscall51) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **chdir** (\_\_\_syscall12) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **chmod** (\_\_\_syscall15) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **chown** (\_\_\_syscall212) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **clock_nanosleep** (\_\_\_syscall265) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **close** (\_\_\_syscall6) ✅ ❗️ [:top:](#host-apis)
|
||||
```rust
|
||||
fn close(fd: c_int) -> c_int
|
||||
```
|
||||
- **dup** (\_\_\_syscall330) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **dup** (\_\_\_syscall41) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **dup** (\_\_\_syscall63) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **exit** (\_\_\_syscall1) ✅ [:top:](#host-apis)
|
||||
```rust
|
||||
fn exit(status: c_int)
|
||||
```
|
||||
- **faccessat** (\_\_\_syscall307) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fadvise** (\_\_\_syscall272) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fallocate** (\_\_\_syscall324) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fchdir** (\_\_\_syscall133) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fchmod** (\_\_\_syscall94) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fchmodat** (\_\_\_syscall306) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fchown** (\_\_\_syscall207) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fchownat** (\_\_\_syscall298) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fcntl** (\_\_\_syscall221) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fdatasync** (\_\_\_syscall148) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fstat** (\_\_\_syscall197) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fstatat** (\_\_\_syscall300) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fstatfs** (\_\_\_syscall269) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **fsync** (\_\_\_syscall118) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **ftruncate** (\_\_\_syscall194) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **futimesat** (\_\_\_syscall299) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getcwd** (\_\_\_syscall183) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getdents** (\_\_\_syscall220) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getgid** (\_\_\_syscall202) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getgroups** (\_\_\_syscall205) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getpgid** (\_\_\_syscall132) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getpgrp** (\_\_\_syscall65) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getpid** (\_\_\_syscall20) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getppid** (\_\_\_syscall64) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getpriority** (\_\_\_syscall96) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getresgid** (\_\_\_syscall211) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getrusage** (\_\_\_syscall77) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **getsid** (\_\_\_syscall147) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **ioctl** (\_\_\_syscall54) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **lchown** (\_\_\_syscall198) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **link** (\_\_\_syscall9) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **linkat** (\_\_\_syscall303) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **llseek** (\_\_\_syscall140) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **lstat** (\_\_\_syscall196) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **madvise** (\_\_\_syscall219) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mincore** (\_\_\_syscall218) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mkdir** (\_\_\_syscall39) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mkdirat** (\_\_\_syscall296) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mknod** (\_\_\_syscall14) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mknodat** (\_\_\_syscall297) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mmap** (\_\_\_syscall192) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mprotect** (\_\_\_syscall125) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **mremap** (\_\_\_syscall163) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **msync** (\_\_\_syscall144) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **munlockall** (\_\_\_syscall153) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **munmap** (\_\_\_syscall91) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **newselect** (\_\_\_syscall142) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **nice** (\_\_\_syscall34) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **open** (\_\_\_syscall5) ✅ ❗️ 🔥 [:top:](#host-apis)
|
||||
```rust
|
||||
fn open(path: u32, flags: c_int, mode: c_int, instance: &mut Instance) -> c_int
|
||||
```
|
||||
- **openat** (\_\_\_syscall295) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pause** (\_\_\_syscall29) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pipe** (\_\_\_syscall331) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pipe** (\_\_\_syscall42) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **poll** (\_\_\_syscall168) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pread** (\_\_\_syscall180) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **preadv** (\_\_\_syscall333) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **prlimit** (\_\_\_syscall340) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pselect** (\_\_\_syscall308) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pwrite** (\_\_\_syscall181) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **pwritev** (\_\_\_syscall334) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **read** (\_\_\_syscall3) ✅ ❗️ [:top:](#host-apis)
|
||||
```rust
|
||||
fn read(fd: c_int, buf: u32, count: size_t, instance: &mut Instance) -> ssize_t
|
||||
```
|
||||
- **readlink** (\_\_\_syscall85) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **readlinkat** (\_\_\_syscall305) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **readv** (\_\_\_syscall145) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **recvmmsg** (\_\_\_syscall337) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **rename** (\_\_\_syscall38) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **renameat** (\_\_\_syscall302) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **rmdir** (\_\_\_syscall40) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **rt_sigqueueinfo** (\_\_\_syscall178) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **sendmmsg** (\_\_\_syscall345) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setdomainname** (\_\_\_syscall121) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setgid** (\_\_\_syscall214) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setitimer** (\_\_\_syscall104) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setpgid** (\_\_\_syscall57) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setpriority** (\_\_\_syscall97) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setresgid** (\_\_\_syscall210) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setrlimit** (\_\_\_syscall75) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **setsid** (\_\_\_syscall66) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **socketcall** (\_\_\_syscall102) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **stat** (\_\_\_syscall195) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **statfs** (\_\_\_syscall268) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **symlink** (\_\_\_syscall83) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **symlinkat** (\_\_\_syscall304) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **sync** (\_\_\_syscall36) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **truncate** (\_\_\_syscall193) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **ugetrlimit** (\_\_\_syscall191) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **umask** (\_\_\_syscall60) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **uname** (\_\_\_syscall122) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **unlink** (\_\_\_syscall10) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **unlinkat** (\_\_\_syscall301) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **utimensat** (\_\_\_syscall320) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **wait** (\_\_\_syscall114) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **write** (\_\_\_syscall4) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
||||
- **writev** (\_\_\_syscall146) [:top:](#host-apis)
|
||||
```rust
|
||||
|
||||
```
|
22
src/apis/emscripten/env.rs
Normal file
22
src/apis/emscripten/env.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use super::super::host;
|
||||
/// NOTE: These syscalls only support wasm_32 for now because they take u32 offset
|
||||
use libc::{c_int};
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use crate::webassembly::Instance;
|
||||
|
||||
/// emscripten: _getenv
|
||||
pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::_getenv {}", name_ptr);
|
||||
let name = unsafe {
|
||||
let memory_name_ptr = instance.memory_offset_addr(0, name_ptr as usize) as *const c_char;
|
||||
CStr::from_ptr(memory_name_ptr).to_str().unwrap()
|
||||
};
|
||||
match host::get_env(name, instance) {
|
||||
Ok(_) => {
|
||||
unimplemented!();
|
||||
}
|
||||
Err(_) => 0,
|
||||
}
|
||||
}
|
@ -2,7 +2,12 @@ use libc::printf as _printf;
|
||||
|
||||
use crate::webassembly::Instance;
|
||||
|
||||
/// putchar
|
||||
pub use libc::putchar;
|
||||
|
||||
/// printf
|
||||
pub extern "C" fn printf(memory_offset: i32, extra: i32, instance: &Instance) -> i32 {
|
||||
debug!("emscripten::printf");
|
||||
let mem = &instance.memories[0];
|
||||
return unsafe {
|
||||
let base_memory_offset = mem.mmap.as_ptr().offset(memory_offset as isize) as *const i8;
|
31
src/apis/emscripten/memory.rs
Normal file
31
src/apis/emscripten/memory.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use libc::{c_void, memcpy, size_t};
|
||||
|
||||
use crate::webassembly::Instance;
|
||||
|
||||
/// emscripten: _emscripten_memcpy_big
|
||||
pub extern "C" fn _emscripten_memcpy_big(
|
||||
dest: u32,
|
||||
src: u32,
|
||||
len: u32,
|
||||
instance: &mut Instance,
|
||||
) -> u32 {
|
||||
debug!("emscripten::_emscripten_memcpy_big");
|
||||
let dest_addr = instance.memory_offset_addr(0, dest as usize) as *mut c_void;
|
||||
let src_addr = instance.memory_offset_addr(0, src as usize) as *mut c_void;
|
||||
unsafe {
|
||||
memcpy(dest_addr, src_addr, len as size_t);
|
||||
}
|
||||
dest
|
||||
}
|
||||
|
||||
/// emscripten: getTotalMemory
|
||||
pub extern "C" fn get_total_memory(instance: &mut Instance) -> u32 {
|
||||
debug!("emscripten::get_total_memory");
|
||||
instance.memories[0].current_size()
|
||||
}
|
||||
|
||||
/// emscripten: enlargeMemory
|
||||
pub extern "C" fn enlarge_memory(_instance: &mut Instance) {
|
||||
debug!("emscripten::enlarge_memory");
|
||||
// instance.memories[0].grow(100);
|
||||
}
|
118
src/apis/emscripten/mod.rs
Normal file
118
src/apis/emscripten/mod.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use crate::webassembly::{ImportObject, ImportValue};
|
||||
|
||||
// EMSCRIPTEN APIS
|
||||
mod env;
|
||||
mod io;
|
||||
mod memory;
|
||||
mod process;
|
||||
mod syscalls;
|
||||
mod utils;
|
||||
|
||||
// SYSCALLS
|
||||
pub use self::utils::is_emscripten_module;
|
||||
|
||||
pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
||||
let mut import_object = ImportObject::new();
|
||||
import_object.set("env", "printf", ImportValue::Func(io::printf as *const u8));
|
||||
import_object.set(
|
||||
"env",
|
||||
"putchar",
|
||||
ImportValue::Func(io::putchar as *const u8),
|
||||
);
|
||||
// Emscripten Env
|
||||
import_object.set(
|
||||
"env",
|
||||
"_getenv",
|
||||
ImportValue::Func(env::_getenv as *const u8),
|
||||
);
|
||||
// Emscripten syscalls
|
||||
import_object.set(
|
||||
"env",
|
||||
"___syscall3",
|
||||
ImportValue::Func(syscalls::___syscall3 as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"___syscall4",
|
||||
ImportValue::Func(syscalls::___syscall4 as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"___syscall5",
|
||||
ImportValue::Func(syscalls::___syscall5 as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"___syscall54",
|
||||
ImportValue::Func(syscalls::___syscall54 as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"___syscall122",
|
||||
ImportValue::Func(syscalls::___syscall122 as *const u8),
|
||||
);
|
||||
// Emscripten other APIs
|
||||
import_object.set(
|
||||
"env",
|
||||
"abort",
|
||||
ImportValue::Func(process::em_abort as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"_abort",
|
||||
ImportValue::Func(process::_abort as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"abortOnCannotGrowMemory",
|
||||
ImportValue::Func(process::abort_on_cannot_grow_memory as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"_emscripten_memcpy_big",
|
||||
ImportValue::Func(memory::_emscripten_memcpy_big as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"enlargeMemory",
|
||||
ImportValue::Func(memory::enlarge_memory as *const u8),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"getTotalMemory",
|
||||
ImportValue::Func(memory::get_total_memory as *const u8),
|
||||
);
|
||||
import_object
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::generate_emscripten_env;
|
||||
use crate::webassembly::{instantiate, Export, Instance};
|
||||
|
||||
#[test]
|
||||
fn test_putchar() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
let func_index = match result_object.module.info.exports.get("main") {
|
||||
Some(&Export::Function(index)) => index,
|
||||
_ => panic!("Function not found"),
|
||||
};
|
||||
let main: fn(&Instance) = get_instance_function!(result_object.instance, func_index);
|
||||
main(&result_object.instance);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_print() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/printf.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
let func_index = match result_object.module.info.exports.get("main") {
|
||||
Some(&Export::Function(index)) => index,
|
||||
_ => panic!("Function not found"),
|
||||
};
|
||||
let main: fn(&Instance) = get_instance_function!(result_object.instance, func_index);
|
||||
main(&result_object.instance);
|
||||
}
|
||||
}
|
44
src/apis/emscripten/process.rs
Normal file
44
src/apis/emscripten/process.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use libc::{
|
||||
// size_t,
|
||||
// ssize_t,
|
||||
abort,
|
||||
// c_int,
|
||||
// c_void,
|
||||
c_char,
|
||||
};
|
||||
|
||||
use crate::webassembly::Instance;
|
||||
use std::ffi::CStr;
|
||||
|
||||
extern "C" fn abort_with_message(message: &str) {
|
||||
debug!("emscripten::abort_with_message");
|
||||
println!("{}", message);
|
||||
_abort();
|
||||
}
|
||||
|
||||
/// emscripten: _abort
|
||||
pub extern "C" fn _abort() {
|
||||
debug!("emscripten::_abort");
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/// emscripten: abort
|
||||
pub extern "C" fn em_abort(message: u32, instance: &mut Instance) {
|
||||
debug!("emscripten::em_abort");
|
||||
let message_addr = instance.memory_offset_addr(0, message as usize) as *mut c_char;
|
||||
unsafe {
|
||||
let message = CStr::from_ptr(message_addr)
|
||||
.to_str()
|
||||
.unwrap_or("Unexpected abort");
|
||||
|
||||
abort_with_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// emscripten: abortOnCannotGrowMemory
|
||||
pub extern "C" fn abort_on_cannot_grow_memory() {
|
||||
debug!("emscripten::abort_on_cannot_grow_memory");
|
||||
abort_with_message("Cannot enlarge memory arrays!");
|
||||
}
|
61
src/apis/emscripten/syscalls.rs
Normal file
61
src/apis/emscripten/syscalls.rs
Normal file
@ -0,0 +1,61 @@
|
||||
/// NOTE: These syscalls only support wasm_32 for now because they take u32 offset
|
||||
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
|
||||
use libc::{c_int, c_void, ssize_t, write};
|
||||
|
||||
use crate::webassembly::Instance;
|
||||
|
||||
// A macro to retrieve variadic arguments given a varargs offset
|
||||
macro_rules! vararg {
|
||||
($name:ident, $type:ident, $instance:ident, $varargs:ident) => (
|
||||
let ($name, $varargs) = unsafe {
|
||||
use std::ptr;
|
||||
let ptr = $instance.memory_offset_addr(0, $varargs as usize);
|
||||
let ret = ptr::read(ptr as *const $type);
|
||||
(ret, $varargs + 4)
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
/// sys_read
|
||||
pub extern "C" fn ___syscall3(_which: c_int, _varargs: c_int, _instance: &mut Instance) -> ssize_t {
|
||||
debug!("emscripten::___syscall3");
|
||||
0
|
||||
}
|
||||
|
||||
/// sys_write
|
||||
pub extern "C" fn ___syscall4(_which: c_int, varargs: c_int, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::___syscall4");
|
||||
vararg!(fd, i32, instance, varargs);
|
||||
vararg!(buf_ptr, u32, instance, varargs);
|
||||
vararg!(count, u32, instance, varargs);
|
||||
debug!("fd: {}, buf_ptr: {}, count: {}", fd, buf_ptr, count);
|
||||
let buf = instance.memory_offset_addr(0, buf_ptr as usize) as *const c_void;
|
||||
unsafe { write(fd, buf, count as usize) as i32 }
|
||||
}
|
||||
|
||||
/// sys_open
|
||||
pub extern "C" fn ___syscall5(_which: c_int, varargs: c_int, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::___syscall5");
|
||||
vararg!(pathname, u32, instance, varargs);
|
||||
vararg!(flags, u32, instance, varargs);
|
||||
vararg!(mode, u32, instance, varargs);
|
||||
debug!("pathname: {}, flags: {}, mode: {}", pathname, flags, mode);
|
||||
-2
|
||||
}
|
||||
|
||||
// sys_ioctl
|
||||
pub extern "C" fn ___syscall54(_which: c_int, varargs: c_int, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::___syscall54");
|
||||
vararg!(stream, u32, instance, varargs);
|
||||
vararg!(op, u32, instance, varargs);
|
||||
debug!("stream: {}, op: {}", stream, op);
|
||||
0
|
||||
}
|
||||
|
||||
// sys_newuname
|
||||
pub extern "C" fn ___syscall122(_which: c_int, varargs: c_int, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::___syscall122");
|
||||
vararg!(buf, u32, instance, varargs);
|
||||
debug!("buf: {}", buf);
|
||||
0
|
||||
}
|
9
src/apis/emscripten/tests/is_emscripten_false.wast
Normal file
9
src/apis/emscripten/tests/is_emscripten_false.wast
Normal file
@ -0,0 +1,9 @@
|
||||
(module
|
||||
(table 0 anyfunc)
|
||||
(memory $0 1)
|
||||
(export "memory" (memory $0))
|
||||
(export "main" (func $main))
|
||||
(func $main (; 1 ;) (result i32)
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
17
src/apis/emscripten/tests/is_emscripten_true.wast
Normal file
17
src/apis/emscripten/tests/is_emscripten_true.wast
Normal file
@ -0,0 +1,17 @@
|
||||
(module
|
||||
(type $FUNCSIG$ii (func (param i32) (result i32)))
|
||||
(import "env" "puts" (func $puts (param i32) (result i32)))
|
||||
(table 0 anyfunc)
|
||||
(memory $0 1)
|
||||
(data (i32.const 16) "hello, world!\00")
|
||||
(export "memory" (memory $0))
|
||||
(export "main" (func $main))
|
||||
(func $main (; 1 ;) (result i32)
|
||||
(drop
|
||||
(call $puts
|
||||
(i32.const 16)
|
||||
)
|
||||
)
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
34
src/apis/emscripten/utils.rs
Normal file
34
src/apis/emscripten/utils.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use crate::webassembly::module::Module;
|
||||
|
||||
/// We check if a provided module is an Emscripten generated one
|
||||
pub fn is_emscripten_module(module: &Module) -> bool {
|
||||
for (module, _field) in &module.info.imported_funcs {
|
||||
if module == "env" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::generate_emscripten_env;
|
||||
use super::is_emscripten_module;
|
||||
use crate::webassembly::instantiate;
|
||||
|
||||
#[test]
|
||||
fn should_detect_emscripten_files() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/is_emscripten_true.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
assert!(is_emscripten_module(&result_object.module));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_detect_non_emscripten_files() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/is_emscripten_false.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
assert!(!is_emscripten_module(&result_object.module));
|
||||
}
|
||||
}
|
4
src/apis/host/mod.rs
Normal file
4
src/apis/host/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod posix;
|
||||
|
||||
// TODO: Make portable
|
||||
pub use self::posix::*;
|
7
src/apis/host/posix/env.rs
Normal file
7
src/apis/host/posix/env.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use crate::webassembly::Instance;
|
||||
use std::env;
|
||||
|
||||
pub extern "C" fn get_env(name: &str, _instance: &mut Instance) -> Result<String, env::VarError> {
|
||||
debug!("host::get_env({:?})", name);
|
||||
env::var(name)
|
||||
}
|
5
src/apis/host/posix/mod.rs
Normal file
5
src/apis/host/posix/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod env;
|
||||
pub mod syscalls;
|
||||
|
||||
pub use self::env::*;
|
||||
pub use self::syscalls::*;
|
48
src/apis/host/posix/syscalls.rs
Normal file
48
src/apis/host/posix/syscalls.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// NOTE: These syscalls only support wasm_32 for now because they take u32 offset
|
||||
|
||||
// use libc::{
|
||||
// c_int,
|
||||
// c_void,
|
||||
// size_t,
|
||||
// ssize_t,
|
||||
// exit,
|
||||
// read,
|
||||
// write,
|
||||
// open,
|
||||
// close,
|
||||
// };
|
||||
|
||||
// use crate::webassembly::{Instance};
|
||||
|
||||
// /// emscripten: ___syscall1
|
||||
// pub extern "C" fn sys_exit(status: c_int, _instance: &mut Instance) {
|
||||
// debug!("host::sys_exit");
|
||||
// unsafe { exit(status); }
|
||||
// }
|
||||
|
||||
// /// emscripten: ___syscall3
|
||||
// pub extern "C" fn sys_read(fd: c_int, buf: *mut c_void, count: size_t, instance: &mut Instance) -> ssize_t {
|
||||
// debug!("host::sys_read");
|
||||
// let buf_addr = instance.memory_offset_addr(0, buf as usize) as *mut c_void;
|
||||
// unsafe { read(fd, buf_addr, count) }
|
||||
// }
|
||||
|
||||
// /// emscripten: ___syscall4
|
||||
// pub extern "C" fn sys_write(which: c_int, mode: c_int, instance: &mut Instance) -> c_int {
|
||||
// debug!("host::sys_write({}, {})", which, mode);
|
||||
// // unsafe { write(which, mode) };
|
||||
// 0
|
||||
// }
|
||||
// /// emscripten: ___syscall5
|
||||
// pub extern "C" fn sys_open(path: u32, flags: c_int, mode: c_int, instance: &mut Instance) -> c_int {
|
||||
// debug!("host::sys_open({}, {}, {})", path, flags, mode);
|
||||
// // let path_addr = instance.memory_offset_addr(0, path as usize) as *const i8;
|
||||
// // unsafe { open(path_addr, flags, mode) };
|
||||
// -2
|
||||
// }
|
||||
|
||||
// /// emscripten: ___syscall6
|
||||
// pub extern "C" fn sys_close(fd: c_int, _instance: &mut Instance) -> c_int {
|
||||
// debug!("host::sys_close");
|
||||
// unsafe { close(fd) }
|
||||
// }
|
4
src/apis/mod.rs
Normal file
4
src/apis/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod emscripten;
|
||||
pub mod host;
|
||||
|
||||
pub use self::emscripten::{generate_emscripten_env, is_emscripten_module};
|
@ -11,17 +11,13 @@ impl<T> UncheckedSlice<T> {
|
||||
#[inline]
|
||||
pub fn get_unchecked(&self, index: usize) -> &T {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
unsafe {
|
||||
&*ptr.add(index)
|
||||
}
|
||||
unsafe { &*ptr.add(index) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
unsafe {
|
||||
&mut *(ptr.add(index) as *mut _)
|
||||
}
|
||||
unsafe { &mut *(ptr.add(index) as *mut _) }
|
||||
}
|
||||
|
||||
pub unsafe fn dangling() -> UncheckedSlice<T> {
|
||||
|
@ -1,7 +0,0 @@
|
||||
use crate::webassembly::Instance;
|
||||
use std::process;
|
||||
|
||||
pub extern "C" fn abort(_code: i32, _instance: &Instance) {
|
||||
process::abort();
|
||||
// abort!("Aborted")
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
use crate::webassembly::{ImportObject, ImportValue};
|
||||
|
||||
mod abort;
|
||||
mod printf;
|
||||
mod putchar;
|
||||
|
||||
pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
||||
let mut import_object = ImportObject::new();
|
||||
import_object.set("env", "printf", ImportValue::Func(printf::printf as *const u8));
|
||||
import_object.set("env", "putchar", ImportValue::Func(putchar::putchar as *const u8));
|
||||
import_object.set("env", "abort", ImportValue::Func(abort::abort as *const u8));
|
||||
import_object.set("env", "_abort", ImportValue::Func(abort::abort as *const u8));
|
||||
import_object
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::generate_emscripten_env;
|
||||
use crate::webassembly::{instantiate, Export, Instance};
|
||||
|
||||
#[test]
|
||||
fn test_putchar() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
let func_index = match result_object.module.info.exports.get("main") {
|
||||
Some(&Export::Function(index)) => index,
|
||||
_ => panic!("Function not found"),
|
||||
};
|
||||
let main: fn(&Instance) = get_instance_function!(result_object.instance, func_index);
|
||||
main(&result_object.instance);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_print() {
|
||||
let wasm_bytes = include_wast2wasm_bytes!("tests/printf.wast");
|
||||
let import_object = generate_emscripten_env();
|
||||
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||
let func_index = match result_object.module.info.exports.get("main") {
|
||||
Some(&Export::Function(index)) => index,
|
||||
_ => panic!("Function not found"),
|
||||
};
|
||||
let main: fn(&Instance) = get_instance_function!(result_object.instance, func_index);
|
||||
main(&result_object.instance);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
pub use libc::putchar;
|
@ -1,3 +0,0 @@
|
||||
pub mod emscripten;
|
||||
|
||||
pub use self::emscripten::generate_emscripten_env;
|
36
src/main.rs
36
src/main.rs
@ -25,8 +25,8 @@ use structopt::StructOpt;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub mod apis;
|
||||
pub mod common;
|
||||
pub mod linkers;
|
||||
pub mod sighandler;
|
||||
#[cfg(test)]
|
||||
mod spectests;
|
||||
@ -71,22 +71,34 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
|
||||
wasm_binary = wabt::wat2wasm(wasm_binary)
|
||||
.map_err(|err| format!("Can't convert from wast to wasm: {:?}", err))?;
|
||||
}
|
||||
|
||||
let import_object = linkers::generate_emscripten_env();
|
||||
// TODO: We should instantiate after compilation, so we provide the
|
||||
// emscripten environment conditionally based on the module
|
||||
let import_object = apis::generate_emscripten_env();
|
||||
let webassembly::ResultObject { module, instance } =
|
||||
webassembly::instantiate(wasm_binary, import_object)
|
||||
.map_err(|err| format!("Can't instantiate the WebAssembly module: {}", err))?;
|
||||
|
||||
// webassembly::utils::print_instance_offsets(&instance);
|
||||
|
||||
let func_index = instance
|
||||
.start_func
|
||||
.unwrap_or_else(|| match module.info.exports.get("main").or(module.info.exports.get("_main")) {
|
||||
if apis::is_emscripten_module(&module) {
|
||||
let func_index = match module.info.exports.get("_main") {
|
||||
Some(&webassembly::Export::Function(index)) => index,
|
||||
_ => panic!("Main function not found"),
|
||||
});
|
||||
let main: fn(&webassembly::Instance) = get_instance_function!(instance, func_index);
|
||||
main(&instance);
|
||||
_ => panic!("_main emscripten function not found"),
|
||||
};
|
||||
let main: extern "C" fn(u32, u32, &webassembly::Instance) =
|
||||
get_instance_function!(instance, func_index);
|
||||
main(0, 0, &instance);
|
||||
} else {
|
||||
let func_index =
|
||||
instance
|
||||
.start_func
|
||||
.unwrap_or_else(|| match module.info.exports.get("main") {
|
||||
Some(&webassembly::Export::Function(index)) => index,
|
||||
_ => panic!("Main function not found"),
|
||||
});
|
||||
let main: extern "C" fn(&webassembly::Instance) =
|
||||
get_instance_function!(instance, func_index);
|
||||
main(&instance);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,10 @@
|
||||
//! or webassembly::Memory objects.
|
||||
// Code inspired from: https://stackoverflow.com/a/45795699/1072990
|
||||
// Adapted to the Webassembly use case
|
||||
use crate::webassembly::LinearMemory;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use crate::webassembly::LinearMemory;
|
||||
|
||||
// We introduced the Pair and BorrowedPair types. We can't use (A, B)
|
||||
// directly due to the orphan rule E0210. This is fine since the map
|
||||
@ -75,8 +75,7 @@ impl<A: Eq + Hash, B: Eq + Hash> ImportObject<A, B> {
|
||||
}
|
||||
|
||||
pub fn get(&self, a: &A, b: &B) -> Option<&ImportValue> {
|
||||
self.map
|
||||
.get(&BorrowedPair(a, b) as &KeyPair<A, B>)
|
||||
self.map.get(&BorrowedPair(a, b) as &KeyPair<A, B>)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, a: A, b: B, v: ImportValue) {
|
||||
@ -127,6 +126,9 @@ mod tests {
|
||||
fn x() {}
|
||||
let mut import_object = ImportObject::new();
|
||||
import_object.set("abc", "def", ImportValue::Func(x as *const u8));
|
||||
assert_eq!(*import_object.get(&"abc", &"def").unwrap(), ImportValue::Func(x as *const u8));
|
||||
assert_eq!(
|
||||
*import_object.get(&"abc", &"def").unwrap(),
|
||||
ImportValue::Func(x as *const u8)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,28 +6,28 @@
|
||||
//! synchronously instantiate a given webassembly::Module object. However, the
|
||||
//! primary way to get an Instance is through the asynchronous
|
||||
//! webassembly::instantiate_streaming() function.
|
||||
use cranelift_codegen::ir::{LibCall, Function};
|
||||
use cranelift_codegen::{binemit, Context};
|
||||
use cranelift_codegen::ir::{Function, LibCall};
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::{binemit, Context};
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::{FuncIndex, GlobalInit};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use region;
|
||||
use std::iter::FromIterator;
|
||||
use std::iter::Iterator;
|
||||
use std::mem::size_of;
|
||||
use std::ptr::write_unaligned;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
use std::iter::FromIterator;
|
||||
use std::mem::size_of;
|
||||
|
||||
use super::super::common::slice::{BoundedSlice, UncheckedSlice};
|
||||
use super::errors::ErrorKind;
|
||||
use super::import_object::{ImportObject, ImportValue};
|
||||
use super::math_intrinsics;
|
||||
use super::memory::LinearMemory;
|
||||
use super::module::{Export, ImportableExportable, Module};
|
||||
use super::relocation::{Reloc, RelocSink, RelocationType};
|
||||
use super::math_intrinsics;
|
||||
|
||||
type TablesSlice = UncheckedSlice<BoundedSlice<usize>>;
|
||||
type MemoriesSlice = UncheckedSlice<BoundedSlice<u8>>;
|
||||
@ -114,7 +114,6 @@ pub struct DataPointers {
|
||||
|
||||
// Pointer to globals
|
||||
pub globals: GlobalsSlice,
|
||||
|
||||
}
|
||||
|
||||
pub struct InstanceOptions {
|
||||
@ -125,7 +124,7 @@ pub struct InstanceOptions {
|
||||
pub isa: Box<TargetIsa>,
|
||||
}
|
||||
|
||||
extern fn mock_fn() -> i32 {
|
||||
extern "C" fn mock_fn() -> i32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -135,7 +134,10 @@ struct CompiledFunction {
|
||||
trap_sink: binemit::NullTrapSink,
|
||||
}
|
||||
|
||||
fn compile_function(isa: &TargetIsa, function_body: &Function) -> Result<CompiledFunction, ErrorKind> {
|
||||
fn compile_function(
|
||||
isa: &TargetIsa,
|
||||
function_body: &Function,
|
||||
) -> Result<CompiledFunction, ErrorKind> {
|
||||
let mut func_context = Context::for_function(function_body.to_owned());
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
@ -152,7 +154,7 @@ fn compile_function(isa: &TargetIsa, function_body: &Function) -> Result<Compile
|
||||
Ok(CompiledFunction {
|
||||
code_buf,
|
||||
reloc_sink,
|
||||
trap_sink
|
||||
trap_sink,
|
||||
})
|
||||
}
|
||||
|
||||
@ -191,23 +193,24 @@ impl Instance {
|
||||
// We walk through the imported functions and set the relocations
|
||||
// for each of this functions to be an empty vector (as is defined outside of wasm)
|
||||
for (module, field) in module.info.imported_funcs.iter() {
|
||||
let imported = import_object
|
||||
.get(&module.as_str(), &field.as_str());
|
||||
let imported = import_object.get(&module.as_str(), &field.as_str());
|
||||
let function: &*const u8 = match imported {
|
||||
Some(ImportValue::Func(f)) => f,
|
||||
None => {
|
||||
if options.mock_missing_imports {
|
||||
debug!("The import {}.{} is not provided, therefore will be mocked.", module, field);
|
||||
debug!(
|
||||
"The import {}.{} is not provided, therefore will be mocked.",
|
||||
module, field
|
||||
);
|
||||
&(mock_fn as *const u8)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return Err(ErrorKind::LinkError(format!(
|
||||
"Imported function {}.{} was not provided in the import_functions",
|
||||
module, field
|
||||
)));
|
||||
}
|
||||
},
|
||||
other => panic!("Expected function import, received {:?}", other)
|
||||
}
|
||||
other => panic!("Expected function import, received {:?}", other),
|
||||
};
|
||||
// println!("GET FUNC {:?}", function);
|
||||
import_functions.push(*function);
|
||||
@ -218,15 +221,20 @@ impl Instance {
|
||||
// Compile the functions (from cranelift IR to machine code)
|
||||
let values: Vec<&Function> = Vec::from_iter(module.info.function_bodies.values());
|
||||
// let isa: &TargetIsa = &*options.isa;
|
||||
let compiled_funcs: Vec<CompiledFunction> = values.par_iter().map(|function_body| -> CompiledFunction {
|
||||
// let r = *Arc::from_raw(isa_ptr);
|
||||
compile_function(&*options.isa, function_body).unwrap()
|
||||
// unimplemented!()
|
||||
}).collect();
|
||||
let compiled_funcs: Vec<CompiledFunction> = values
|
||||
.par_iter()
|
||||
.map(|function_body| -> CompiledFunction {
|
||||
// let r = *Arc::from_raw(isa_ptr);
|
||||
compile_function(&*options.isa, function_body).unwrap()
|
||||
// unimplemented!()
|
||||
}).collect();
|
||||
|
||||
for compiled_func in compiled_funcs.into_iter() {
|
||||
let CompiledFunction {code_buf, reloc_sink, ..} = compiled_func;
|
||||
|
||||
let CompiledFunction {
|
||||
code_buf,
|
||||
reloc_sink,
|
||||
..
|
||||
} = compiled_func;
|
||||
|
||||
// let func_offset = code_buf;
|
||||
protect_codebuf(&code_buf).unwrap();
|
||||
@ -322,33 +330,39 @@ impl Instance {
|
||||
};
|
||||
|
||||
for (i, global) in module.info.globals.iter().enumerate() {
|
||||
let ImportableExportable {entity, import_name, ..} = global;
|
||||
let ImportableExportable {
|
||||
entity,
|
||||
import_name,
|
||||
..
|
||||
} = global;
|
||||
let value: i64 = match entity.initializer {
|
||||
GlobalInit::I32Const(n) => n as _,
|
||||
GlobalInit::I64Const(n) => n,
|
||||
GlobalInit::F32Const(f) => f as _, // unsafe { mem::transmute(f as f64) },
|
||||
GlobalInit::F64Const(f) => f as _, // unsafe { mem::transmute(f) },
|
||||
GlobalInit::GlobalRef(global_index) => {
|
||||
globals_data[global_index.index()]
|
||||
}
|
||||
GlobalInit::GlobalRef(global_index) => globals_data[global_index.index()],
|
||||
GlobalInit::Import() => {
|
||||
let (module_name, field_name) = import_name.as_ref().expect("Expected a import name for the global import");
|
||||
let imported = import_object.get(&module_name.as_str(), &field_name.as_str());
|
||||
let (module_name, field_name) = import_name
|
||||
.as_ref()
|
||||
.expect("Expected a import name for the global import");
|
||||
let imported =
|
||||
import_object.get(&module_name.as_str(), &field_name.as_str());
|
||||
match imported {
|
||||
Some(ImportValue::Global(value)) => {
|
||||
*value
|
||||
},
|
||||
Some(ImportValue::Global(value)) => *value,
|
||||
None => {
|
||||
if options.mock_missing_globals {
|
||||
0
|
||||
} else {
|
||||
panic!(
|
||||
"Imported global value was not provided ({}.{})",
|
||||
module_name, field_name
|
||||
)
|
||||
}
|
||||
else {
|
||||
panic!("Imported global value was not provided ({}.{})", module_name, field_name)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
panic!("Expected global import, but received {:?} ({}.{})", imported, module_name, field_name)
|
||||
}
|
||||
_ => panic!(
|
||||
"Expected global import, but received {:?} ({}.{})",
|
||||
imported, module_name, field_name
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -367,27 +381,29 @@ impl Instance {
|
||||
for table in &module.info.tables {
|
||||
let table: Vec<usize> = match table.import_name.as_ref() {
|
||||
Some((module_name, field_name)) => {
|
||||
let imported = import_object.get(&module_name.as_str(), &field_name.as_str());
|
||||
let imported =
|
||||
import_object.get(&module_name.as_str(), &field_name.as_str());
|
||||
match imported {
|
||||
Some(ImportValue::Table(t)) => {
|
||||
t.to_vec()
|
||||
},
|
||||
Some(ImportValue::Table(t)) => t.to_vec(),
|
||||
None => {
|
||||
if options.mock_missing_tables {
|
||||
let len = table.entity.size;
|
||||
let mut v = Vec::with_capacity(len);
|
||||
v.resize(len, 0);
|
||||
v
|
||||
} else {
|
||||
panic!(
|
||||
"Imported table value was not provided ({}.{})",
|
||||
module_name, field_name
|
||||
)
|
||||
}
|
||||
else {
|
||||
panic!("Imported table value was not provided ({}.{})", module_name, field_name)
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
panic!("Expected global table, but received {:?} ({}.{})", imported, module_name, field_name)
|
||||
}
|
||||
_ => panic!(
|
||||
"Expected global table, but received {:?} ({}.{})",
|
||||
imported, module_name, field_name
|
||||
),
|
||||
}
|
||||
},
|
||||
}
|
||||
None => {
|
||||
let len = table.entity.size;
|
||||
let mut v = Vec::with_capacity(len);
|
||||
@ -401,10 +417,8 @@ impl Instance {
|
||||
// instantiate tables
|
||||
for table_element in &module.info.table_elements {
|
||||
let base = match table_element.base {
|
||||
Some(global_index) => {
|
||||
globals_data[global_index.index()] as usize
|
||||
},
|
||||
None => 0
|
||||
Some(global_index) => globals_data[global_index.index()] as usize,
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let table = &mut tables[table_element.table_index.index()];
|
||||
@ -415,7 +429,6 @@ impl Instance {
|
||||
|
||||
// let func_index = *elem_index - module.info.imported_funcs.len() as u32;
|
||||
// let func_addr = functions[func_index.index()].as_ptr();
|
||||
println!("TABLE LENGTH: {}", table.len());
|
||||
let func_addr = get_function_addr(&func_index, &import_functions, &functions);
|
||||
table[base + table_element.offset + i] = func_addr as _;
|
||||
}
|
||||
@ -431,10 +444,8 @@ impl Instance {
|
||||
// Get memories in module
|
||||
for memory in &module.info.memories {
|
||||
let memory = memory.entity;
|
||||
let v = LinearMemory::new(
|
||||
memory.pages_count as u32,
|
||||
memory.maximum.map(|m| m as u32),
|
||||
);
|
||||
let v =
|
||||
LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32));
|
||||
memories.push(v);
|
||||
}
|
||||
|
||||
@ -459,10 +470,14 @@ impl Instance {
|
||||
// TODO: Refactor repetitive code
|
||||
let tables_pointer: Vec<BoundedSlice<usize>> =
|
||||
tables.iter().map(|table| table[..].into()).collect();
|
||||
let memories_pointer: Vec<BoundedSlice<u8>> =
|
||||
memories.iter().map(
|
||||
|mem| BoundedSlice::new(&mem[..], mem.current as usize * LinearMemory::WASM_PAGE_SIZE),
|
||||
).collect();
|
||||
let memories_pointer: Vec<BoundedSlice<u8>> = memories
|
||||
.iter()
|
||||
.map(|mem| {
|
||||
BoundedSlice::new(
|
||||
&mem[..],
|
||||
mem.current as usize * LinearMemory::WASM_PAGE_SIZE,
|
||||
)
|
||||
}).collect();
|
||||
let globals_pointer: GlobalsSlice = globals[..].into();
|
||||
|
||||
let data_pointers = DataPointers {
|
||||
@ -517,6 +532,11 @@ impl Instance {
|
||||
.as_ref()[address..address + len]
|
||||
}
|
||||
|
||||
pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const usize {
|
||||
let mem = &self.memories[index];
|
||||
unsafe { mem.mmap.as_ptr().offset(offset as isize) as *const usize }
|
||||
}
|
||||
|
||||
// Shows the value of a global variable.
|
||||
// pub fn inspect_global(&self, global_index: GlobalIndex, ty: ir::Type) -> &[u8] {
|
||||
// let offset = global_index * 8;
|
||||
@ -529,6 +549,7 @@ impl Instance {
|
||||
// }
|
||||
}
|
||||
|
||||
// TODO: Needs to be moved to more appropriate place
|
||||
extern "C" fn grow_memory(size: u32, memory_index: u32, instance: &mut Instance) -> i32 {
|
||||
// TODO: Support for only one LinearMemory for now.
|
||||
debug_assert_eq!(
|
||||
@ -543,9 +564,13 @@ extern "C" fn grow_memory(size: u32, memory_index: u32, instance: &mut Instance)
|
||||
|
||||
if old_mem_size != -1 {
|
||||
// Get new memory bytes
|
||||
let new_mem_bytes = (old_mem_size as usize + size as usize) * LinearMemory::WASM_PAGE_SIZE;
|
||||
let new_mem_bytes = (old_mem_size as usize + size as usize) * LinearMemory::WASM_PAGE_SIZE;
|
||||
// Update data_pointer
|
||||
instance.data_pointers.memories.get_unchecked_mut(memory_index as usize).len = new_mem_bytes;
|
||||
instance
|
||||
.data_pointers
|
||||
.memories
|
||||
.get_unchecked_mut(memory_index as usize)
|
||||
.len = new_mem_bytes;
|
||||
}
|
||||
|
||||
old_mem_size
|
||||
|
@ -65,6 +65,11 @@ impl LinearMemory {
|
||||
self.current
|
||||
}
|
||||
|
||||
/// Returns the maximum number of wasm pages allowed.
|
||||
pub fn maximum_size(&self) -> u32 {
|
||||
self.maximum.unwrap_or(65536)
|
||||
}
|
||||
|
||||
/// Grow memory by the specified amount of pages.
|
||||
///
|
||||
/// Returns `None` if memory can't be grown by the specified amount
|
||||
@ -127,8 +132,7 @@ impl fmt::Debug for LinearMemory {
|
||||
// Not comparing based on memory content. That would be inefficient.
|
||||
impl PartialEq for LinearMemory {
|
||||
fn eq(&self, other: &LinearMemory) -> bool {
|
||||
self.current == other.current &&
|
||||
self.maximum == other.maximum
|
||||
self.current == other.current && self.maximum == other.maximum
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,18 @@
|
||||
pub mod errors;
|
||||
pub mod import_object;
|
||||
pub mod instance;
|
||||
pub mod math_intrinsics;
|
||||
pub mod memory;
|
||||
pub mod module;
|
||||
pub mod relocation;
|
||||
pub mod utils;
|
||||
pub mod math_intrinsics;
|
||||
|
||||
use cranelift_codegen::{isa, settings};
|
||||
use std::panic;
|
||||
use std::str::FromStr;
|
||||
use target_lexicon;
|
||||
use wasmparser;
|
||||
use wasmparser::WasmDecoder;
|
||||
use cranelift_codegen::{isa, settings};
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
|
||||
pub use self::errors::{Error, ErrorKind};
|
||||
pub use self::import_object::{ImportObject, ImportValue};
|
||||
@ -60,7 +59,7 @@ pub fn instantiate(
|
||||
mock_missing_imports: true,
|
||||
mock_missing_globals: true,
|
||||
mock_missing_tables: true,
|
||||
isa: isa
|
||||
isa: isa,
|
||||
},
|
||||
)?;
|
||||
debug!("webassembly - instance created");
|
||||
|
@ -15,27 +15,14 @@ use cranelift_codegen::isa::{CallConv, TargetFrontendConfig};
|
||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||
|
||||
use cranelift_wasm::{
|
||||
translate_module,
|
||||
ReturnMode,
|
||||
DefinedFuncIndex,
|
||||
FuncEnvironment as FuncEnvironmentTrait,
|
||||
FuncIndex,
|
||||
FuncTranslator,
|
||||
Global,
|
||||
GlobalIndex,
|
||||
GlobalVariable,
|
||||
Memory,
|
||||
MemoryIndex,
|
||||
ModuleEnvironment,
|
||||
SignatureIndex,
|
||||
Table,
|
||||
TableIndex,
|
||||
WasmResult,
|
||||
translate_module, DefinedFuncIndex, FuncEnvironment as FuncEnvironmentTrait, FuncIndex,
|
||||
FuncTranslator, Global, GlobalIndex, GlobalVariable, Memory, MemoryIndex, ModuleEnvironment,
|
||||
ReturnMode, SignatureIndex, Table, TableIndex, WasmResult,
|
||||
};
|
||||
|
||||
use super::errors::ErrorKind;
|
||||
use super::memory::LinearMemory;
|
||||
use super::instance::Instance;
|
||||
use super::memory::LinearMemory;
|
||||
|
||||
/// Get the integer type used for representing pointers on this platform.
|
||||
fn native_pointer_type() -> ir::Type {
|
||||
@ -56,10 +43,10 @@ pub fn native_pointer_size() -> i32 {
|
||||
}
|
||||
|
||||
/// Convert a TlsData offset into a `Offset32` for a global decl.
|
||||
fn offset32(offset: usize) -> ir::immediates::Offset32 {
|
||||
assert!(offset <= i32::max_value() as usize);
|
||||
(offset as i32).into()
|
||||
}
|
||||
// fn offset32(offset: usize) -> ir::immediates::Offset32 {
|
||||
// assert!(offset <= i32::max_value() as usize);
|
||||
// (offset as i32).into()
|
||||
// }
|
||||
|
||||
/// Convert a usize offset into a `Imm64` for an iadd_imm.
|
||||
fn imm64(offset: usize) -> ir::immediates::Imm64 {
|
||||
@ -89,7 +76,7 @@ impl<T> ImportableExportable<T> {
|
||||
Self {
|
||||
entity,
|
||||
export_names: Vec::new(),
|
||||
import_name: import_name
|
||||
import_name: import_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,7 +232,6 @@ pub struct Module {
|
||||
// return_mode: ReturnMode,
|
||||
}
|
||||
|
||||
|
||||
impl Module {
|
||||
/// Instantiate a Module given WASM bytecode
|
||||
pub fn from_bytes(
|
||||
@ -365,7 +351,11 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
// however the 32-bit wasmer may be running on 64-bit arch, which means ptr_size here will
|
||||
// be 8 bytes. That will definitely gove the wrong offset values
|
||||
fn make_table(&mut self, func: &mut ir::Function, table_index: TableIndex) -> ir::Table {
|
||||
assert_eq!(table_index.index(), 0, "Only one WebAssembly memory supported");
|
||||
assert_eq!(
|
||||
table_index.index(),
|
||||
0,
|
||||
"Only one WebAssembly memory supported"
|
||||
);
|
||||
let instance = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_size = native_pointer_size();
|
||||
// Load value at (instance + TABLES_OFFSET)
|
||||
@ -415,7 +405,11 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
// however the 32-bit wasmer may be running on 64-bit arch, which means ptr_size here will
|
||||
// be 8 bytes. That will definitely gove the wrong offset values
|
||||
fn make_heap(&mut self, func: &mut ir::Function, memory_index: MemoryIndex) -> ir::Heap {
|
||||
debug_assert_eq!(memory_index.index(), 0, "Only one WebAssembly memory supported");
|
||||
debug_assert_eq!(
|
||||
memory_index.index(),
|
||||
0,
|
||||
"Only one WebAssembly memory supported"
|
||||
);
|
||||
let instance = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_size = native_pointer_size();
|
||||
|
||||
@ -438,7 +432,7 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
base,
|
||||
offset: Offset32::new(memory_data_offset),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: true
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
// Load value at the (base + memory_data_offset)
|
||||
@ -455,16 +449,18 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
base: heap_base,
|
||||
min_size: 0.into(),
|
||||
guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as i64).into(),
|
||||
style: ir::HeapStyle::Dynamic {
|
||||
bound_gv,
|
||||
},
|
||||
index_type: I32
|
||||
style: ir::HeapStyle::Dynamic { bound_gv },
|
||||
index_type: I32,
|
||||
});
|
||||
|
||||
heap
|
||||
}
|
||||
|
||||
fn make_global(&mut self, func: &mut ir::Function, global_index: GlobalIndex) -> GlobalVariable {
|
||||
fn make_global(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
global_index: GlobalIndex,
|
||||
) -> GlobalVariable {
|
||||
let ptr_size = native_pointer_size();
|
||||
|
||||
let instance = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
@ -525,7 +521,6 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("Missing vmctx parameter");
|
||||
|
||||
|
||||
// The `callee` value is an index into a table of function pointers.
|
||||
// Apparently, that table is stored at absolute address 0 in this dummy environment.
|
||||
// TODO: Generate bounds checking code.
|
||||
@ -541,9 +536,7 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
// let entry_size = native_pointer_size() as i64 * 2;
|
||||
// let callee_scaled = pos.ins().imul_imm(callee_offset, entry_size);
|
||||
|
||||
let entry_addr = pos
|
||||
.ins()
|
||||
.table_addr(ptr, table, callee_offset, 0);
|
||||
let entry_addr = pos.ins().table_addr(ptr, table, callee_offset, 0);
|
||||
|
||||
let mut mflags = ir::MemFlags::new();
|
||||
mflags.set_notrap();
|
||||
@ -597,7 +590,11 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
_heap: ir::Heap,
|
||||
val: ir::Value,
|
||||
) -> WasmResult<ir::Value> {
|
||||
debug_assert_eq!(memory_index.index(), 0, "non-default memories not supported yet");
|
||||
debug_assert_eq!(
|
||||
memory_index.index(),
|
||||
0,
|
||||
"non-default memories not supported yet"
|
||||
);
|
||||
let grow_mem_func = self.mod_info.grow_memory_extfunc.unwrap_or_else(|| {
|
||||
let sig_ref = pos.func.import_signature(Signature {
|
||||
call_conv: CallConv::SystemV,
|
||||
@ -624,7 +621,9 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
let memory_index_value = pos.ins().iconst(I32, imm64(memory_index.index()));
|
||||
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
|
||||
|
||||
let call_inst = pos.ins().call(grow_mem_func, &[val, memory_index_value, vmctx]);
|
||||
let call_inst = pos
|
||||
.ins()
|
||||
.call(grow_mem_func, &[val, memory_index_value, vmctx]);
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
|
||||
@ -634,7 +633,11 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
memory_index: MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
) -> WasmResult<ir::Value> {
|
||||
debug_assert_eq!(memory_index.index(), 0, "non-default memories not supported yet");
|
||||
debug_assert_eq!(
|
||||
memory_index.index(),
|
||||
0,
|
||||
"non-default memories not supported yet"
|
||||
);
|
||||
let cur_mem_func = self.mod_info.current_memory_extfunc.unwrap_or_else(|| {
|
||||
let sig_ref = pos.func.import_signature(Signature {
|
||||
call_conv: CallConv::SystemV,
|
||||
@ -712,7 +715,9 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
||||
self.info.imported_funcs.len(),
|
||||
"Imported functions must be declared first"
|
||||
);
|
||||
self.info.functions.push(ImportableExportable::new(sig_index, None));
|
||||
self.info
|
||||
.functions
|
||||
.push(ImportableExportable::new(sig_index, None));
|
||||
self.info
|
||||
.imported_funcs
|
||||
.push((String::from(module), String::from(field)));
|
||||
@ -723,7 +728,9 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
||||
}
|
||||
|
||||
fn declare_func_type(&mut self, sig_index: SignatureIndex) {
|
||||
self.info.functions.push(ImportableExportable::new(sig_index, None));
|
||||
self.info
|
||||
.functions
|
||||
.push(ImportableExportable::new(sig_index, None));
|
||||
}
|
||||
|
||||
fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex {
|
||||
@ -731,16 +738,16 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
||||
}
|
||||
|
||||
fn declare_global(&mut self, global: Global) {
|
||||
self.info.globals.push(ImportableExportable::new(global, None));
|
||||
self.info
|
||||
.globals
|
||||
.push(ImportableExportable::new(global, None));
|
||||
}
|
||||
|
||||
fn declare_global_import(
|
||||
&mut self,
|
||||
global: Global,
|
||||
module: &'data str,
|
||||
field: &'data str,
|
||||
) {
|
||||
self.info.globals.push(ImportableExportable::new(global, Some((String::from(module), String::from(field)))));
|
||||
fn declare_global_import(&mut self, global: Global, module: &'data str, field: &'data str) {
|
||||
self.info.globals.push(ImportableExportable::new(
|
||||
global,
|
||||
Some((String::from(module), String::from(field))),
|
||||
));
|
||||
}
|
||||
|
||||
fn get_global(&self, global_index: GlobalIndex) -> &Global {
|
||||
@ -748,16 +755,16 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
||||
}
|
||||
|
||||
fn declare_table(&mut self, table: Table) {
|
||||
self.info.tables.push(ImportableExportable::new(table, None));
|
||||
self.info
|
||||
.tables
|
||||
.push(ImportableExportable::new(table, None));
|
||||
}
|
||||
|
||||
fn declare_table_import(
|
||||
&mut self,
|
||||
table: Table,
|
||||
module: &'data str,
|
||||
field: &'data str,
|
||||
) {
|
||||
self.info.tables.push(ImportableExportable::new(table, Some((String::from(module), String::from(field)))));
|
||||
fn declare_table_import(&mut self, table: Table, module: &'data str, field: &'data str) {
|
||||
self.info.tables.push(ImportableExportable::new(
|
||||
table,
|
||||
Some((String::from(module), String::from(field))),
|
||||
));
|
||||
}
|
||||
|
||||
fn declare_table_elements(
|
||||
@ -776,16 +783,16 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
||||
}
|
||||
|
||||
fn declare_memory(&mut self, memory: Memory) {
|
||||
self.info.memories.push(ImportableExportable::new(memory, None));
|
||||
self.info
|
||||
.memories
|
||||
.push(ImportableExportable::new(memory, None));
|
||||
}
|
||||
|
||||
fn declare_memory_import(
|
||||
&mut self,
|
||||
memory: Memory,
|
||||
module: &'data str,
|
||||
field: &'data str,
|
||||
) {
|
||||
self.info.memories.push(ImportableExportable::new(memory, Some((String::from(module), String::from(field)))));
|
||||
fn declare_memory_import(&mut self, memory: Memory, module: &'data str, field: &'data str) {
|
||||
self.info.memories.push(ImportableExportable::new(
|
||||
memory,
|
||||
Some((String::from(module), String::from(field))),
|
||||
));
|
||||
}
|
||||
|
||||
fn declare_data_initialization(
|
||||
|
@ -11,12 +11,10 @@ pub fn print_instance_offsets(instance: &Instance) {
|
||||
let instance_address = instance as *const _ as usize;
|
||||
let data_ptr = &instance.data_pointers;
|
||||
|
||||
let tables_pointer_address_ptr: *const usize =
|
||||
unsafe { transmute(&data_ptr.tables) };
|
||||
let tables_pointer_address_ptr: *const usize = unsafe { transmute(&data_ptr.tables) };
|
||||
let tables_pointer_address = tables_pointer_address_ptr as usize;
|
||||
|
||||
let memories_pointer_address_ptr: *const usize =
|
||||
unsafe { transmute(&data_ptr.memories) };
|
||||
let memories_pointer_address_ptr: *const usize = unsafe { transmute(&data_ptr.memories) };
|
||||
let memories_pointer_address = memories_pointer_address_ptr as usize;
|
||||
|
||||
let memories_pointer_address_ptr_0: *const usize =
|
||||
@ -31,8 +29,7 @@ pub fn print_instance_offsets(instance: &Instance) {
|
||||
unsafe { transmute(&data_ptr.memories.get_unchecked(0).len) };
|
||||
let memories_pointer_address_0_len = memories_pointer_address_ptr_0_len as usize;
|
||||
|
||||
let globals_pointer_address_ptr: *const usize =
|
||||
unsafe { transmute(&data_ptr.globals) };
|
||||
let globals_pointer_address_ptr: *const usize = unsafe { transmute(&data_ptr.globals) };
|
||||
let globals_pointer_address = globals_pointer_address_ptr as usize;
|
||||
|
||||
println!(
|
||||
@ -53,7 +50,6 @@ instance.data_pointers.globals \t- {:X} | offset - {:?}
|
||||
tables_pointer_address - instance_address,
|
||||
memories_pointer_address,
|
||||
memories_pointer_address - instance_address,
|
||||
|
||||
memories_pointer_address_0,
|
||||
0,
|
||||
memories_pointer_address_0_data,
|
||||
@ -61,7 +57,6 @@ instance.data_pointers.globals \t- {:X} | offset - {:?}
|
||||
data_ptr.memories.get_unchecked(0).len,
|
||||
memories_pointer_address_0_len,
|
||||
memories_pointer_address_0_len - memories_pointer_address_0_data,
|
||||
|
||||
globals_pointer_address,
|
||||
globals_pointer_address - instance_address,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user