Skip to content

Commit

Permalink
Implement uvwasi library and improve WASI structure
Browse files Browse the repository at this point in the history
Introduce uvwasi into the build system.
Introduce class WasiFunction to enable WASI to acces Instance resources.
Implement further WASI types and fd_write function.

Signed-off-by: Adam Laszlo Kulcsar <[email protected]>
  • Loading branch information
kulcsaradam committed Oct 16, 2023
1 parent 54c0b6a commit 187a895
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 20 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ jobs:

install: |
apt-get update
apt-get install -y cmake build-essential ninja-build pkg-config python3 clang-12
apt-get install -y cmake build-essential ninja-build pkg-config python3 clang-12 git
#FIXME fix clang version as to 12
ln -s /usr/bin/clang-12 /usr/bin/clang
ln -s /usr/bin/clang++-12 /usr/bin/clang++
Expand Down Expand Up @@ -163,7 +163,7 @@ jobs:

install: |
apt-get update
apt-get install -y cmake build-essential ninja-build pkg-config python3 clang-12
apt-get install -y cmake build-essential ninja-build pkg-config python3 clang-12 git
#FIXME fix clang version as to 12
ln -s /usr/bin/clang-12 /usr/bin/clang
ln -s /usr/bin/clang++-12 /usr/bin/clang++
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
path = third_party/wasm-c-api
url = https://github.com/WebAssembly/wasm-c-api
ignore = untracked
[submodule "third_party/uvwasi"]
path = third_party/uvwasi
url = https://github.com/kulcsaradam/uvwasi.git
8 changes: 7 additions & 1 deletion build/walrus.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@ ENDIF()
SET (WABT_DEFINITIONS ${WALRUS_DEFINITIONS})
SET (WITH_EXCEPTIONS TRUE)
ADD_SUBDIRECTORY (third_party/wabt)
SET (WALRUS_LIBRARIES ${WALRUS_LIBRARIES} wabt)

# uvwasi
ADD_SUBDIRECTORY(third_party/uvwasi)
INCLUDE_DIRECTORIES (${WALRUS_INCDIRS} PRIVATE ${WALRUS_THIRD_PARTY_ROOT}/uvwasi/include)
INCLUDE_DIRECTORIES (${WALRUS_INCDIRS} PRIVATE ${CMAKE_BINARY_DIR}/_deps/libuv-src/include)

SET (WALRUS_LIBRARIES ${WALRUS_LIBRARIES} wabt uvwasi_a)

# BUILD
INCLUDE_DIRECTORIES (${WALRUS_INCDIRS})
Expand Down
45 changes: 45 additions & 0 deletions src/runtime/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,49 @@ void ImportedFunction::call(ExecutionState& state, Value* argv, Value* result)
m_callback(newState, argv, result, m_data);
}

WasiFunction* WasiFunction::createWasiFunction(Store* store,
FunctionType* functionType,
WasiFunctionCallback callback,
Instance* instance)
{
WasiFunction* func = new WasiFunction(functionType,
callback,
instance);
store->appendExtern(func);
return func;
}

void WasiFunction::interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets,
uint16_t parameterOffsetCount, uint16_t resultOffsetCount)
{
const FunctionType* ft = functionType();
const ValueTypeVector& paramTypeInfo = ft->param();
const ValueTypeVector& resultTypeInfo = ft->result();

ALLOCA(Value, paramVector, sizeof(Value) * paramTypeInfo.size());
ALLOCA(Value, resultVector, sizeof(Value) * resultTypeInfo.size());

size_t offsetIndex = 0;
size_t size = paramTypeInfo.size();
Value* paramVectorStart = paramVector;
for (size_t i = 0; i < size; i++) {
paramVector[i] = Value(paramTypeInfo[i], bp + offsets[offsetIndex]);
offsetIndex += valueFunctionCopyCount(paramTypeInfo[i]);
}

call(state, paramVectorStart, resultVector);

for (size_t i = 0; i < resultTypeInfo.size(); i++) {
resultVector[i].writeToMemory(bp + offsets[offsetIndex]);
offsetIndex += valueFunctionCopyCount(resultTypeInfo[i]);
}
}

void WasiFunction::call(ExecutionState& state, Value* argv, Value* result)
{
ExecutionState newState(state, this);
CHECK_STACK_LIMIT(newState);
m_callback(newState, argv, result, this->m_runningInstance);
}

} // namespace Walrus
48 changes: 48 additions & 0 deletions src/runtime/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class FunctionType;
class ModuleFunction;
class DefinedFunction;
class ImportedFunction;
class WasiFunction;

class Function : public Extern {
public:
Expand Down Expand Up @@ -71,6 +72,10 @@ class Function : public Extern {
{
return false;
}
virtual bool isWasiFunction() const
{
return false;
}

DefinedFunction* asDefinedFunction()
{
Expand All @@ -84,6 +89,12 @@ class Function : public Extern {
return reinterpret_cast<ImportedFunction*>(this);
}

WasiFunction* asWasiFunction()
{
assert(isWasiFunction());
return reinterpret_cast<WasiFunction*>(this);
}

protected:
Function(FunctionType* functionType)
: m_functionType(functionType)
Expand Down Expand Up @@ -168,6 +179,43 @@ class ImportedFunction : public Function {
void* m_data;
};

class WasiFunction : public Function {
public:
typedef std::function<void(ExecutionState& state, Value* argv, Value* result, Instance* instance)> WasiFunctionCallback;

static WasiFunction* createWasiFunction(Store* store,
FunctionType* functionType,
WasiFunctionCallback callback,
Instance* instance);

virtual bool isWasiFunction() const override
{
return true;
}

void setRunningInstance(Instance* instance)
{
m_runningInstance = instance;
}

virtual void call(ExecutionState& state, Value* argv, Value* result) override;
virtual void interpreterCall(ExecutionState& state, uint8_t* bp, ByteCodeStackOffset* offsets,
uint16_t parameterOffsetCount, uint16_t resultOffsetCount) override;

protected:
WasiFunction(FunctionType* functionType,
WasiFunctionCallback callback,
Instance* instance)
: Function(functionType)
, m_callback(callback)
, m_runningInstance(instance)
{
}

WasiFunctionCallback m_callback;
Instance* m_runningInstance;
};

} // namespace Walrus

#endif // __WalrusFunction__
7 changes: 6 additions & 1 deletion src/runtime/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "interpreter/ByteCode.h"
#include "interpreter/Interpreter.h"
#include "parser/WASMParser.h"
#include "wasi/Wasi.h"

namespace Walrus {

Expand Down Expand Up @@ -137,7 +138,11 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports
if (!imports[i]->asFunction()->functionType()->equals(m_imports[i]->functionType())) {
Trap::throwException(state, "imported function type mismatch");
}
instance->m_functions[funcIndex++] = imports[i]->asFunction();
instance->m_functions[funcIndex] = imports[i]->asFunction();
if (imports[i]->asFunction()->isWasiFunction()) {
instance->m_functions[funcIndex]->asWasiFunction()->setRunningInstance(instance);
}
funcIndex++;
break;
}
case ImportType::Global: {
Expand Down
21 changes: 21 additions & 0 deletions src/runtime/SpecTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class SpecTestFunctionTypes {
// The R is meant to represent the results, after R are the result types.
NONE = 0,
I32R,
I32_RI32,
I32I32I32I32_RI32,
RI32,
I64R,
F32R,
Expand Down Expand Up @@ -57,6 +59,25 @@ class SpecTestFunctionTypes {
param->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I32_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);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// RI32
param = new ValueTypeVector();
Expand Down
20 changes: 10 additions & 10 deletions src/shell/Shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static void printF64(double v)
printf("%s : f64\n", formatDecmialString(ss.str()).c_str());
}

static Trap::TrapResult executeWASM(Store* store, const std::string& filename, const std::vector<uint8_t>& src, SpecTestFunctionTypes& functionTypes, WASI* wasi,
static Trap::TrapResult executeWASM(Store* store, const std::string& filename, const std::vector<uint8_t>& src, SpecTestFunctionTypes& functionTypes,
std::map<std::string, Instance*>* registeredInstanceMap = nullptr)
{
auto parseResult = WASMParser::parseBinary(store, filename, src.data(), src.size());
Expand Down Expand Up @@ -231,11 +231,11 @@ static Trap::TrapResult executeWASM(Store* store, const std::string& filename, c
nullptr));
}
} else if (import->moduleName() == "wasi_snapshot_preview1") {
Walrus::WASI::WasiFunc* wasiImportFunc = wasi->find(import->fieldName());
Walrus::WASI::WasiFunc* wasiImportFunc = WASI::find(import->fieldName());
if (wasiImportFunc != nullptr) {
FunctionType* fn = functionTypes[wasiImportFunc->functionType];
if (fn->equals(import->functionType())) {
importValues.push_back(ImportedFunction::createImportedFunction(
importValues.push_back(WasiFunction::createWasiFunction(
store,
const_cast<FunctionType*>(import->functionType()),
wasiImportFunc->ptr,
Expand Down Expand Up @@ -639,7 +639,7 @@ static Instance* fetchInstance(wabt::Var& moduleVar, std::map<size_t, Instance*>
return registeredInstanceMap[moduleVar.name()];
}

static void executeWAST(Store* store, const std::string& filename, const std::vector<uint8_t>& src, SpecTestFunctionTypes& functionTypes, WASI* wasi)
static void executeWAST(Store* store, const std::string& filename, const std::vector<uint8_t>& src, SpecTestFunctionTypes& functionTypes)
{
auto lexer = wabt::WastLexer::CreateBufferLexer("test.wabt", src.data(), src.size());
if (lexer == nullptr) {
Expand Down Expand Up @@ -671,7 +671,7 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve
case wabt::CommandType::ScriptModule: {
auto* moduleCommand = static_cast<wabt::ModuleCommand*>(command.get());
auto buf = readModuleData(&moduleCommand->module);
auto trapResult = executeWASM(store, filename, buf->data, functionTypes, wasi, &registeredInstanceMap);
auto trapResult = executeWASM(store, filename, buf->data, functionTypes, &registeredInstanceMap);
if (trapResult.exception) {
std::string& errorMessage = trapResult.exception->message();
printf("Error: %s\n", errorMessage.c_str());
Expand Down Expand Up @@ -752,7 +752,7 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve
RELEASE_ASSERT_NOT_REACHED();
}
auto buf = readModuleData(&tsm->module);
auto trapResult = executeWASM(store, filename, buf->data, functionTypes, wasi, &registeredInstanceMap);
auto trapResult = executeWASM(store, filename, buf->data, functionTypes, &registeredInstanceMap);
RELEASE_ASSERT(trapResult.exception);
std::string& s = trapResult.exception->message();
if (s.find(assertModuleUninstantiable->text) != 0) {
Expand Down Expand Up @@ -800,7 +800,7 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve
} else {
buf = dsm->data;
}
auto trapResult = executeWASM(store, filename, buf, functionTypes, wasi);
auto trapResult = executeWASM(store, filename, buf, functionTypes);
if (trapResult.exception == nullptr) {
printf("Execute WASM returned nullptr (in wabt::CommandType::AssertInvalid case)\n");
printf("Expected exception:%s\n", assertModuleInvalid->text.data());
Expand Down Expand Up @@ -831,7 +831,7 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve
} else {
buf = dsm->data;
}
auto trapResult = executeWASM(store, filename, buf, functionTypes, wasi);
auto trapResult = executeWASM(store, filename, buf, functionTypes);
if (trapResult.exception == nullptr) {
printf("Execute WASM returned nullptr (in wabt::CommandType::AssertUnlinkable case)\n");
printf("Expected exception:%s\n", assertUnlinkable->text.data());
Expand Down Expand Up @@ -1018,14 +1018,14 @@ int main(int argc, char* argv[])
if (!argParser.exportToRun.empty()) {
runExports(store, filePath, buf, argParser.exportToRun);
} else {
auto trapResult = executeWASM(store, filePath, buf, functionTypes, wasi);
auto trapResult = executeWASM(store, filePath, buf, functionTypes);
if (trapResult.exception) {
fprintf(stderr, "Uncaught Exception: %s\n", trapResult.exception->message().data());
return -1;
}
}
} else if (endsWith(filePath, "wat") || endsWith(filePath, "wast")) {
executeWAST(store, filePath, buf, functionTypes, wasi);
executeWAST(store, filePath, buf, functionTypes);
}
} else {
printf("Cannot open file %s\n", filePath.data());
Expand Down
46 changes: 46 additions & 0 deletions src/wasi/Fd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Walrus {

void WASI::fd_write(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
int32_t fd = argv[0].asI32();
int32_t iovptr = argv[1].asI32();
int32_t iovcnt = argv[2].asI32();
WASI::wasi_iovec_t wasi_iovs;

if (!WASI::checkMemOffset(instance->memory(0), iovptr, iovcnt)) {
result[0] = Value(static_cast<int16_t>(WASI::wasi_errno::inval));
result[1] = Value(static_cast<int32_t>(0));
return;
}

wasi_iovs.buf = reinterpret_cast<uint8_t*>(iovptr);
wasi_iovs.len = iovcnt;

std::vector<uvwasi_ciovec_t> iovs(iovcnt);
for (int i = 0; i < iovcnt; i++) {
iovs[i].buf_len = wasi_iovs.len;
iovs[0].buf = wasi_iovs.buf;
}

uvwasi_size_t out_addr;
result[0] = Value(static_cast<int16_t>(uvwasi_fd_write(WASI::m_uvwasi, fd, iovs.data(), iovs.size(), &out_addr)));
result[1] = Value(static_cast<int32_t>(out_addr));
}

} // namespace Walrus
Loading

0 comments on commit 187a895

Please sign in to comment.