Skip to content

Commit

Permalink
Add wasi functions required by quickjs
Browse files Browse the repository at this point in the history
Add numerous wasi functions required to run quickjs engine.
Also add test case for functions.

Signed-off-by: Ádám László Kulcsár <[email protected]>
  • Loading branch information
kulcsaradam authored and ksh8281 committed Feb 14, 2025
1 parent 5f28544 commit 41601dd
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/parser/WASMParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate {
*
* m_currentFunction->peekByteCode<Walrus::UnaryOperation>(m_lastI32EqzPos)->dstOffset() == stackPos
* checks if the output of I32Eqz is the input of JumpIfTrue/JumpIfFalse
*/
*/
return (m_lastI32EqzPos + sizeof(Walrus::I32Eqz) == m_currentFunction->currentByteCodeSize())
&& (m_currentFunction->peekByteCode<Walrus::UnaryOperation>(m_lastI32EqzPos)->dstOffset() == stackPos);
}
Expand Down
40 changes: 40 additions & 0 deletions src/runtime/DefinedFunctionTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class DefinedFunctionTypes {
I32I32I32I32_RI32,
I32I64I32I32_RI32,
I32I64I64I32_RI32,
I32I32I32I32I32_RI32,
I32I32I32I64I32_RI32,
I32I32I32I32I32I32_RI32,
I32I32I32I32I32I64I64I32I32_RI32,
RI32,
I64R,
Expand Down Expand Up @@ -138,6 +141,43 @@ class DefinedFunctionTypes {
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I32I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I64I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I64);
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I32I32I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I32I32I64I64I32I32_RI32
param = new ValueTypeVector();
Expand Down
79 changes: 79 additions & 0 deletions src/wasi/WASI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,17 @@ void WASI::fd_read(ExecutionState& state, Value* argv, Value* result, Instance*
result[0] = Value(uvwasi_fd_read(WASI::g_uvwasi, fd, iovs, iovsLen, nread));
}

void WASI::fd_readdir(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t* buf = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[1], argv[2].asI32()));
uint32_t bufLen = argv[2].asI32();
uint64_t cookie = argv[3].asI64();
uint32_t* bufUsed = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[4], sizeof(uint32_t)));

result[0] = Value(uvwasi_fd_readdir(WASI::g_uvwasi, fd, buf, bufLen, cookie, bufUsed));
}

void WASI::fd_close(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
Expand All @@ -243,6 +254,14 @@ void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Inst
result[0] = Value(uvwasi_fd_fdstat_get(WASI::g_uvwasi, fd, fdstat));
}

void WASI::fd_fdstat_set_flags(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t fdflags = argv[1].asI32();

result[0] = Value(uvwasi_fd_fdstat_set_flags(WASI::g_uvwasi, fd, fdflags));
}

void WASI::fd_prestat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
Expand Down Expand Up @@ -296,6 +315,66 @@ void WASI::path_open(ExecutionState& state, Value* argv, Value* result, Instance
oflags, rights, right_inheriting, fdflags, ret_fd));
}

void WASI::path_create_directory(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t length = argv[2].asI32();
const char* path = reinterpret_cast<char*>(get_memory_pointer(instance, argv[1], length));

result[0] = Value(uvwasi_path_create_directory(WASI::g_uvwasi, fd, path, length));
}

void WASI::path_remove_directory(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t length = argv[2].asI32();
const char* path = reinterpret_cast<char*>(get_memory_pointer(instance, argv[1], length));

result[0] = Value(uvwasi_path_remove_directory(WASI::g_uvwasi, fd, path, length));
}

void WASI::path_filestat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t flags = argv[1].asI32();
uint32_t length = argv[3].asI32();
const char* path = reinterpret_cast<char*>(get_memory_pointer(instance, argv[2], length));
uvwasi_filestat_t* buf = reinterpret_cast<uvwasi_filestat_t*>(get_memory_pointer(instance, argv[4], sizeof(uvwasi_filestat_t)));

result[0] = Value(uvwasi_path_filestat_get(WASI::g_uvwasi, fd, flags, path, length, buf));
}

void WASI::path_rename(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t oldFd = argv[0].asI32();
uint32_t oldLength = argv[2].asI32();
const char* oldPath = reinterpret_cast<char*>(get_memory_pointer(instance, argv[1], oldLength));
uint32_t newFd = argv[3].asI32();
uint32_t newLength = argv[5].asI32();
const char* newPath = reinterpret_cast<char*>(get_memory_pointer(instance, argv[4], oldLength));

result[0] = Value(uvwasi_path_rename(WASI::g_uvwasi, oldFd, oldPath, oldLength, newFd, newPath, newLength));
}

void WASI::path_unlink_file(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t length = argv[2].asI32();
const char* path = reinterpret_cast<char*>(get_memory_pointer(instance, argv[1], length));

result[0] = Value(uvwasi_path_unlink_file(WASI::g_uvwasi, fd, path, length));
}

void WASI::poll_oneoff(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uvwasi_subscription_t* in = reinterpret_cast<uvwasi_subscription_t*>(get_memory_pointer(instance, argv[0], sizeof(uvwasi_subscription_t)));
uvwasi_event_t* out = reinterpret_cast<uvwasi_event_t*>(get_memory_pointer(instance, argv[1], sizeof(uvwasi_event_t)));
uint32_t nsubscriptions = argv[2].asI32();
uint32_t* nevents = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[3], sizeof(uint32_t)));

result[0] = Value(uvwasi_poll_oneoff(WASI::g_uvwasi, in, out, nsubscriptions, nevents));
}

void WASI::environ_sizes_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uvwasi_size_t* uvCount = reinterpret_cast<uvwasi_size_t*>(get_memory_pointer(instance, argv[0], sizeof(uint32_t)));
Expand Down
10 changes: 9 additions & 1 deletion src/wasi/WASI.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,21 @@ class WASI {
F(random_get, I32I32_RI32) \
F(fd_write, I32I32I32I32_RI32) \
F(fd_read, I32I32I32I32_RI32) \
F(fd_readdir, I32I32I32I64I32_RI32) \
F(fd_close, I32_RI32) \
F(fd_fdstat_get, I32I32_RI32) \
F(fd_prestat_dir_name, I32I32I32_RI32) \
F(fd_fdstat_set_flags, I32I32_RI32) \
F(fd_prestat_get, I32I32_RI32) \
F(fd_prestat_dir_name, I32I32I32_RI32) \
F(fd_seek, I32I64I32I32_RI32) \
F(fd_advise, I32I64I64I32_RI32) \
F(path_open, I32I32I32I32I32I64I64I32I32_RI32) \
F(path_create_directory, I32I32I32_RI32) \
F(path_remove_directory, I32I32I32_RI32) \
F(path_filestat_get, I32I32I32I32I32_RI32) \
F(path_rename, I32I32I32I32I32I32_RI32) \
F(path_unlink_file, I32I32I32_RI32) \
F(poll_oneoff, I32I32I32I32_RI32) \
F(environ_get, I32I32_RI32) \
F(environ_sizes_get, I32I32_RI32)

Expand Down
201 changes: 201 additions & 0 deletions test/wasi/filesystem_functions.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
(module
(import "wasi_snapshot_preview1" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "path_create_directory" (func $path_create_directory (param i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "path_remove_directory" (func $path_remove_directory (param i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "path_filestat_get" (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "path_rename" (func $path_rename (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "path_unlink_file" (func $path_unlink_file (param i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "poll_oneoff" (func $poll_oneoff (param i32 i32 i32 i32) (result i32)))

(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_close" (func $fd_close (param i32) (result i32)))

(memory 1)

(export "create_directory" (func $create_directory))
(export "rename_directory" (func $rename_directory))
(export "remove_directory" (func $remove_directory))
(export "poll" (func $poll))
(export "create_file_and_filestat" (func $create_file_and_filestat))
(export "unlink" (func $unlink))

(data (i32.const 300) "./")
(data (i32.const 400) "./new_dir")
(data (i32.const 500) "./renamed_dir")
(data (i32.const 600) "./some_file.txt")

;; helper function
(func $open_wasi_dir (param i64) (result i32)
i32.const 3 ;; Directory file descriptior
i32.const 1 ;;lookupflags: directory
i32.const 300 ;; Offset of file name in memory
i32.const 2 ;; Length of file name
i32.const 0 ;; oflags: none
local.get 0 ;; rights
local.get 0 ;; righst inheritings
i32.const 0 ;; fdflags: none
i32.const 0 ;; Offset to store at the opened file descriptor in memory
call $path_open
)

(func $create_directory
(param i32 i32 i32) ;; fd offset, name offset, name length
(result i32)
i64.const 512
call $open_wasi_dir
drop

local.get 0
i32.load ;; fd of the containing dir
local.get 1 ;; name relative to containing dir
local.get 2 ;; name length
call $path_create_directory

i32.eqz
)

(func $rename_directory
(param i32 i32 i32 i32 i32) ;; fd, old name, old name length, new name, new name length
(result i32)
i64.const 196608
call $open_wasi_dir
drop

local.get 0
i32.load ;; fd of the containing dir
local.get 1 ;; old name relative to containing dir
local.get 2 ;; old name length
local.get 0
i32.load ;; new fd location
local.get 3 ;; new name
local.get 4 ;; new name length
call $path_rename

i32.eqz
)

(func $remove_directory
(param i32 i32 i32) ;; fd, name, name length
(result i32)
i64.const 33554432
call $open_wasi_dir
drop

local.get 0
i32.load ;; fd of the containing dir
local.get 1 ;; name of directory
local.get 2 ;; name length
call $path_remove_directory

i32.eqz
)

(func $poll
(param i32) ;; number of events
(result i32)
i64.const 134217762
call $open_wasi_dir
drop

i32.const 1000 ;; offset of subscriptions
i32.const 1100 ;; offset where events should be stored at
local.get 0 ;; number of events
i32.const 1200 ;; offset of number of stored events
call $poll_oneoff

i32.eqz
)

(func $create_file_and_filestat
(param i32 i32 i32) ;; fd offset, name, length
(result i32)
i64.const 271360
call $open_wasi_dir
drop

i32.const 0
i32.load ;; fd
i32.const 1 ;; dirflags
i32.const 600 ;; Offset of file name in memory
i32.const 15 ;; Length of file name
i32.const 1 ;; oflags: none
i64.const 271360 ;; rights
i64.const 271360 ;; rights inheriting
i32.const 0 ;; fdflags: none
i32.const 2000 ;; Offset to store at the opened file descriptor in memory
call $path_open

i32.const 2000 ;; fd
call $fd_close
drop

i32.eqz
(if
(then)
(else
i32.const 0
return
)
)

local.get 0
i32.load ;; fd
i32.const 1 ;; lookupflags
local.get 1 ;; name
local.get 2 ;; name length
i32.const 2100 ;; offset of stored data
call $path_filestat_get

i32.eqz
)

(func $unlink
(param i32 i32 i32) ;; fd, name, name length
(result i32)
i64.const 67108864
call $open_wasi_dir
drop

local.get 0
i32.load ;; fd of containing dir
local.get 1 ;; name
local.get 2 ;; name length
call $path_unlink_file

i32.eqz
)

)

;; correct tests
(assert_return (invoke "create_directory" (i32.const 0) (i32.const 400) (i32.const 9)) (i32.const 1))
(assert_return (invoke "rename_directory" (i32.const 0) (i32.const 400) (i32.const 9) (i32.const 500) (i32.const 13)) (i32.const 1))
(assert_return (invoke "remove_directory" (i32.const 0) (i32.const 500) (i32.const 13)) (i32.const 1))
(assert_return (invoke "poll" (i32.const 1)) (i32.const 1))
(assert_return (invoke "create_file_and_filestat" (i32.const 0) (i32.const 600) (i32.const 16)) (i32.const 1))
(assert_return (invoke "unlink" (i32.const 0) (i32.const 600) (i32.const 16)) (i32.const 1))

;; incorrect tests
(assert_return (invoke "create_directory" (i32.const 0) (i32.const 400) (i32.const 0)) (i32.const 0))
(assert_return (invoke "create_directory" (i32.const 0) (i32.const 20000) (i32.const 9)) (i32.const 0))
(assert_return (invoke "create_directory" (i32.const 20000) (i32.const 400) (i32.const 9)) (i32.const 0))

(assert_return (invoke "rename_directory" (i32.const 20000) (i32.const 400) (i32.const 9) (i32.const 500) (i32.const 13)) (i32.const 0))
(assert_return (invoke "rename_directory" (i32.const 0) (i32.const 20000) (i32.const 9) (i32.const 500) (i32.const 13)) (i32.const 0))
(assert_return (invoke "rename_directory" (i32.const 0) (i32.const 400) (i32.const 0) (i32.const 500) (i32.const 13)) (i32.const 0))
(assert_return (invoke "rename_directory" (i32.const 0) (i32.const 400) (i32.const 9) (i32.const 20000) (i32.const 13)) (i32.const 0))
(assert_return (invoke "rename_directory" (i32.const 0) (i32.const 400) (i32.const 9) (i32.const 500) (i32.const 0)) (i32.const 0))

(assert_return (invoke "remove_directory" (i32.const 20000) (i32.const 500) (i32.const 13)) (i32.const 0))
(assert_return (invoke "remove_directory" (i32.const 0) (i32.const 20000) (i32.const 13)) (i32.const 0))
(assert_return (invoke "remove_directory" (i32.const 0) (i32.const 500) (i32.const 0)) (i32.const 0))

(assert_return (invoke "poll" (i32.const 0)) (i32.const 0))

;; if tested with empty name or 0 length name it refers to the containing directory
(assert_return (invoke "create_file_and_filestat" (i32.const 20000) (i32.const 600) (i32.const 16)) (i32.const 0))

(assert_return (invoke "unlink" (i32.const 20000) (i32.const 600) (i32.const 16)) (i32.const 0))
(assert_return (invoke "unlink" (i32.const 0) (i32.const 20000) (i32.const 16)) (i32.const 0))
(assert_return (invoke "unlink" (i32.const 0) (i32.const 600) (i32.const 0)) (i32.const 0))

0 comments on commit 41601dd

Please sign in to comment.